SoftwareManager/plugin.py: allow autofs volumes to be selectable as backup location...
[vuplus_dvbapp] / lib / python / Plugins / SystemPlugins / SoftwareManager / plugin.py
1 from Plugins.Plugin import PluginDescriptor
2 from Screens.Console import Console
3 from Screens.ChoiceBox import ChoiceBox
4 from Screens.MessageBox import MessageBox
5 from Screens.Screen import Screen
6 from Screens.Ipkg import Ipkg
7 from Components.ActionMap import ActionMap, NumberActionMap
8 from Components.Input import Input
9 from Components.Ipkg import IpkgComponent
10 from Components.Sources.StaticText import StaticText
11 from Components.ScrollLabel import ScrollLabel
12 from Components.Pixmap import Pixmap
13 from Components.MenuList import MenuList
14 from Components.Sources.List import List
15 from Components.Slider import Slider
16 from Components.Harddisk import harddiskmanager
17 from Components.config import config,getConfigListEntry, ConfigSubsection, ConfigText, ConfigLocations, ConfigYesNo, ConfigSelection
18 from Components.ConfigList import ConfigListScreen
19 from Components.Console import Console
20 from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest
21 from Components.SelectionList import SelectionList
22 from Components.PluginComponent import plugins
23 from Components.About import about
24 from Components.DreamInfoHandler import DreamInfoHandler
25 from Components.Language import language
26 from Components.AVSwitch import AVSwitch
27 from Components.Network import iNetwork
28 from Tools.Directories import pathExists, fileExists, resolveFilename, SCOPE_PLUGINS, SCOPE_CURRENT_PLUGIN, SCOPE_CURRENT_SKIN, SCOPE_METADIR
29 from Tools.LoadPixmap import LoadPixmap
30 from Tools.NumericalTextInput import NumericalTextInput
31 from enigma import eTimer, quitMainloop, RT_HALIGN_LEFT, RT_VALIGN_CENTER, eListboxPythonMultiContent, eListbox, gFont, getDesktop, ePicLoad, eRCInput, getPrevAsciiCode, eEnv
32 from cPickle import dump, load
33 from os import path as os_path, system as os_system, unlink, stat, mkdir, popen, makedirs, listdir, access, rename, remove, W_OK, R_OK, F_OK
34 from time import time, gmtime, strftime, localtime
35 from stat import ST_MTIME
36 from datetime import date
37 from twisted.web import client
38 from twisted.internet import reactor
39
40 from ImageWizard import ImageWizard
41 from BackupRestore import BackupSelection, RestoreMenu, BackupScreen, RestoreScreen, getBackupPath, getBackupFilename
42 from SoftwareTools import iSoftwareTools
43
44 config.plugins.configurationbackup = ConfigSubsection()
45 config.plugins.configurationbackup.backuplocation = ConfigText(default = '/media/hdd/', visible_width = 50, fixed_size = False)
46 config.plugins.configurationbackup.backupdirs = ConfigLocations(default=[eEnv.resolve('${sysconfdir}/enigma2/'), '/etc/network/interfaces', '/etc/wpa_supplicant.conf', '/etc/resolv.conf', '/etc/default_gw', '/etc/hostname'])
47
48 config.plugins.SoftwareManager = ConfigSubsection()
49 config.plugins.SoftwareManager.overwriteConfigFiles = ConfigSelection(
50                                 [
51                                  ("Y", _("Yes, always")),
52                                  ("N", _("No, never")),                          
53                                  ("ask", _("Always ask"))
54                                 ], "Y")
55
56 def write_cache(cache_file, cache_data):
57         #Does a cPickle dump
58         if not os_path.isdir( os_path.dirname(cache_file) ):
59                 try:
60                         mkdir( os_path.dirname(cache_file) )
61                 except OSError:
62                             print os_path.dirname(cache_file), 'is a file'
63         fd = open(cache_file, 'w')
64         dump(cache_data, fd, -1)
65         fd.close()
66
67 def valid_cache(cache_file, cache_ttl):
68         #See if the cache file exists and is still living
69         try:
70                 mtime = stat(cache_file)[ST_MTIME]
71         except:
72                 return 0
73         curr_time = time()
74         if (curr_time - mtime) > cache_ttl:
75                 return 0
76         else:
77                 return 1
78
79 def load_cache(cache_file):
80         #Does a cPickle load
81         fd = open(cache_file)
82         cache_data = load(fd)
83         fd.close()
84         return cache_data
85
86
87 class UpdatePluginMenu(Screen):
88         skin = """
89                 <screen name="UpdatePluginMenu" position="center,center" size="610,410" title="Software management" >
90                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
91                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
92                         <ePixmap pixmap="skin_default/border_menu_350.png" position="5,50" zPosition="1" size="350,300" transparent="1" alphatest="on" />
93                         <widget source="menu" render="Listbox" position="15,60" size="330,290" scrollbarMode="showOnDemand">
94                                 <convert type="TemplatedMultiContent">
95                                         {"template": [
96                                                         MultiContentEntryText(pos = (2, 2), size = (330, 24), flags = RT_HALIGN_LEFT, text = 1), # index 0 is the MenuText,
97                                                 ],
98                                         "fonts": [gFont("Regular", 22)],
99                                         "itemHeight": 25
100                                         }
101                                 </convert>
102                         </widget>
103                         <widget source="menu" render="Listbox" position="360,50" size="240,300" scrollbarMode="showNever" selectionDisabled="1">
104                                 <convert type="TemplatedMultiContent">
105                                         {"template": [
106                                                         MultiContentEntryText(pos = (2, 2), size = (240, 300), flags = RT_HALIGN_CENTER|RT_VALIGN_CENTER|RT_WRAP, text = 2), # index 2 is the Description,
107                                                 ],
108                                         "fonts": [gFont("Regular", 22)],
109                                         "itemHeight": 300
110                                         }
111                                 </convert>
112                         </widget>
113                         <widget source="status" render="Label" position="5,360" zPosition="10" size="600,50" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
114                 </screen>"""
115                 
116         def __init__(self, session, args = 0):
117                 Screen.__init__(self, session)
118                 self.skin_path = plugin_path
119                 self.menu = args
120                 self.list = []
121                 self.oktext = _("\nPress OK on your remote control to continue.")
122                 self.menutext = _("Press MENU on your remote control for additional options.")
123                 self.infotext = _("Press INFO on your remote control for additional information.")
124                 self.text = ""
125                 self.backupdirs = ' '.join( config.plugins.configurationbackup.backupdirs.value )
126                 if self.menu == 0:
127                         print "building menu entries"
128                         self.list.append(("install-extensions", _("Manage extensions"), _("\nManage extensions or plugins for your Dreambox" ) + self.oktext, None))
129                         self.list.append(("software-update", _("Software update"), _("\nOnline update of your Dreambox software." ) + self.oktext, None))
130                         self.list.append(("software-restore", _("Software restore"), _("\nRestore your Dreambox with a new firmware." ) + self.oktext, None))
131                         self.list.append(("system-backup", _("Backup system settings"), _("\nBackup your Dreambox settings." ) + self.oktext + "\n\n" + self.infotext, None))
132                         self.list.append(("system-restore",_("Restore system settings"), _("\nRestore your Dreambox settings." ) + self.oktext, None))
133                         self.list.append(("ipkg-install", _("Install local extension"),  _("\nScan for local extensions and install them." ) + self.oktext, None))
134                         for p in plugins.getPlugins(PluginDescriptor.WHERE_SOFTWAREMANAGER):
135                                 if p.__call__.has_key("SoftwareSupported"):
136                                         callFnc = p.__call__["SoftwareSupported"](None)
137                                         if callFnc is not None:
138                                                 if p.__call__.has_key("menuEntryName"):
139                                                         menuEntryName = p.__call__["menuEntryName"](None)
140                                                 else:
141                                                         menuEntryName = _('Extended Software')
142                                                 if p.__call__.has_key("menuEntryDescription"):
143                                                         menuEntryDescription = p.__call__["menuEntryDescription"](None)
144                                                 else:
145                                                         menuEntryDescription = _('Extended Software Plugin')
146                                                 self.list.append(('default-plugin', menuEntryName, menuEntryDescription + self.oktext, callFnc))
147                         if config.usage.setup_level.index >= 2: # expert+
148                                 self.list.append(("advanced", _("Advanced Options"), _("\nAdvanced options and settings." ) + self.oktext, None))
149                 elif self.menu == 1:
150                         self.list.append(("advancedrestore", _("Advanced restore"), _("\nRestore your backups by date." ) + self.oktext, None))
151                         self.list.append(("backuplocation", _("Choose backup location"),  _("\nSelect your backup device.\nCurrent device: " ) + config.plugins.configurationbackup.backuplocation.value + self.oktext, None))
152                         self.list.append(("backupfiles", _("Choose backup files"),  _("Select files for backup.") + self.oktext + "\n\n" + self.infotext, None))
153                         if config.usage.setup_level.index >= 2: # expert+
154                                 self.list.append(("ipkg-manager", _("Packet management"),  _("\nView, install and remove available or installed packages." ) + self.oktext, None))
155                         self.list.append(("ipkg-source",_("Choose upgrade source"), _("\nEdit the upgrade source address." ) + self.oktext, None))
156                         for p in plugins.getPlugins(PluginDescriptor.WHERE_SOFTWAREMANAGER):
157                                 if p.__call__.has_key("AdvancedSoftwareSupported"):
158                                         callFnc = p.__call__["AdvancedSoftwareSupported"](None)
159                                         if callFnc is not None:
160                                                 if p.__call__.has_key("menuEntryName"):
161                                                         menuEntryName = p.__call__["menuEntryName"](None)
162                                                 else:
163                                                         menuEntryName = _('Advanced Software')
164                                                 if p.__call__.has_key("menuEntryDescription"):
165                                                         menuEntryDescription = p.__call__["menuEntryDescription"](None)
166                                                 else:
167                                                         menuEntryDescription = _('Advanced Software Plugin')
168                                                 self.list.append(('advanced-plugin', menuEntryName, menuEntryDescription + self.oktext, callFnc))
169
170                 self["menu"] = List(self.list)
171                 self["key_red"] = StaticText(_("Close"))
172                 self["status"] = StaticText(self.menutext)
173
174                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions", "InfobarEPGActions", "MenuActions"],
175                 {
176                         "ok": self.go,
177                         "back": self.close,
178                         "red": self.close,
179                         "menu": self.handleMenu,
180                         "showEventInfo": self.handleInfo,
181                 }, -1)
182                 self.onLayoutFinish.append(self.layoutFinished)
183                 self.backuppath = getBackupPath()
184                 self.backupfile = getBackupFilename()
185                 self.fullbackupfilename = self.backuppath + "/" + self.backupfile
186                 self.onShown.append(self.setWindowTitle)
187
188         def layoutFinished(self):
189                 idx = 0
190                 self["menu"].index = idx
191
192         def setWindowTitle(self):
193                 self.setTitle(_("Software management"))
194
195         def cleanup(self):
196                 iNetwork.stopPingConsole()
197                 iSoftwareTools.cleanupSoftwareTools()
198
199         def getUpdateInfos(self):
200                 self.text = ""
201                 if iSoftwareTools.NetworkConnectionAvailable == True:
202                         if iSoftwareTools.list_updating is False:
203                                 if iSoftwareTools.available_updates is not 0:
204                                         self.text = _("There are at least ") + str(iSoftwareTools.available_updates) + _(" updates available.")
205                                 else:
206                                         self.text = "" #_("There are no updates available.")
207                         else:
208                                 if iSoftwareTools.available_updates is not 0:
209                                         self.text = _("There are at least ") + str(iSoftwareTools.available_updates) + _(" updates available.")
210                                 else:
211                                         self.text = ""  #_("There are no updates available.")
212                                 self.text += "\n" + _("A search for available updates is currently in progress.")
213                 else:
214                         self.text = _("No network connection available.")
215                 self["status"].setText(self.text)
216
217         def handleMenu(self):
218                 self.session.open(SoftwareManagerSetup)
219                 
220         def handleInfo(self):
221                 current = self["menu"].getCurrent()
222                 if current:
223                         currentEntry = current[0]
224                         if currentEntry in ("system-backup","backupfiles"):
225                                 self.session.open(SoftwareManagerInfo, mode = "backupinfo")
226
227         def go(self):
228                 current = self["menu"].getCurrent()
229                 if current:
230                         currentEntry = current[0]
231                         if self.menu == 0:
232                                 if (currentEntry == "software-update"):
233                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to update your Dreambox?")+"\n"+_("\nAfter pressing OK, please wait!"))
234                                 elif (currentEntry == "software-restore"):
235                                         self.session.open(ImageWizard)
236                                 elif (currentEntry == "install-extensions"):
237                                         self.session.open(PluginManager, self.skin_path)
238                                 elif (currentEntry == "system-backup"):
239                                         self.session.openWithCallback(self.backupDone,BackupScreen, runBackup = True)
240                                 elif (currentEntry == "system-restore"):
241                                         if os_path.exists(self.fullbackupfilename):
242                                                 self.session.openWithCallback(self.startRestore, MessageBox, _("Are you sure you want to restore your Enigma2 backup?\nEnigma2 will restart after the restore"))
243                                         else:
244                                                 self.session.open(MessageBox, _("Sorry no backups found!"), MessageBox.TYPE_INFO, timeout = 10)
245                                 elif (currentEntry == "ipkg-install"):
246                                         try:
247                                                 from Plugins.Extensions.MediaScanner.plugin import main
248                                                 main(self.session)
249                                         except:
250                                                 self.session.open(MessageBox, _("Sorry MediaScanner is not installed!"), MessageBox.TYPE_INFO, timeout = 10)
251                                 elif (currentEntry == "default-plugin"):
252                                         self.extended = current[3]
253                                         self.extended(self.session, None)
254                                 elif (currentEntry == "advanced"):
255                                         self.session.open(UpdatePluginMenu, 1)
256                         elif self.menu == 1:
257                                 if (currentEntry == "ipkg-manager"):
258                                         self.session.open(PacketManager, self.skin_path)
259                                 elif (currentEntry == "backuplocation"):
260                                         parts = [ (r.description, r.mountpoint, self.session) for r in harddiskmanager.getMountedPartitions(onlyhotplug = False)]
261                                         for x in parts:
262                                                 if not access(x[1], F_OK|R_OK|W_OK) or x[1] == '/':
263                                                         parts.remove(x)
264                                         if len(parts):
265                                                 self.session.openWithCallback(self.backuplocation_choosen, ChoiceBox, title = _("Please select medium to use as backup location"), list = parts)
266                                 elif (currentEntry == "backupfiles"):
267                                         self.session.openWithCallback(self.backupfiles_choosen,BackupSelection)
268                                 elif (currentEntry == "advancedrestore"):
269                                         self.session.open(RestoreMenu, self.skin_path)
270                                 elif (currentEntry == "ipkg-source"):
271                                         self.session.open(IPKGMenu, self.skin_path)
272                                 elif (currentEntry == "advanced-plugin"):
273                                         self.extended = current[3]
274                                         self.extended(self.session, None)
275
276         def backupfiles_choosen(self, ret):
277                 self.backupdirs = ' '.join( config.plugins.configurationbackup.backupdirs.value )
278                 config.plugins.configurationbackup.backupdirs.save()
279                 config.plugins.configurationbackup.save()
280                 config.save()
281                 
282         def backuplocation_choosen(self, option):
283                 oldpath = config.plugins.configurationbackup.backuplocation.getValue()
284                 if option is not None:
285                         config.plugins.configurationbackup.backuplocation.value = str(option[1])
286                 config.plugins.configurationbackup.backuplocation.save()
287                 config.plugins.configurationbackup.save()
288                 config.save()
289                 newpath = config.plugins.configurationbackup.backuplocation.getValue()
290                 if newpath != oldpath:
291                         self.createBackupfolders()
292
293         def runUpgrade(self, result):
294                 if result:
295                         self.session.open(UpdatePlugin, self.skin_path)
296
297         def createBackupfolders(self):
298                 print "Creating backup folder if not already there..."
299                 self.backuppath = getBackupPath()
300                 try:
301                         if (os_path.exists(self.backuppath) == False):
302                                 makedirs(self.backuppath)
303                 except OSError:
304                         self.session.open(MessageBox, _("Sorry, your backup destination is not writeable.\n\nPlease choose another one."), MessageBox.TYPE_INFO, timeout = 10)
305
306         def backupDone(self,retval = None):
307                 if retval is True:
308                         self.session.open(MessageBox, _("Backup done."), MessageBox.TYPE_INFO, timeout = 10)
309                 else:
310                         self.session.open(MessageBox, _("Backup failed."), MessageBox.TYPE_INFO, timeout = 10)
311
312         def startRestore(self, ret = False):
313                 if (ret == True):
314                         self.exe = True
315                         self.session.open(RestoreScreen, runRestore = True)
316
317 class SoftwareManagerSetup(Screen, ConfigListScreen):
318
319         skin = """
320                 <screen name="SoftwareManagerSetup" position="center,center" size="560,440" title="SoftwareManager setup">
321                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
322                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
323                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
324                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
325                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
326                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
327                         <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
328                         <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" transparent="1" />
329                         <widget name="config" position="5,50" size="550,350" scrollbarMode="showOnDemand" />
330                         <ePixmap pixmap="skin_default/div-h.png" position="0,400" zPosition="1" size="560,2" />
331                         <widget source="introduction" render="Label" position="5,410" size="550,30" zPosition="10" font="Regular;21" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
332                 </screen>"""
333
334         def __init__(self, session, skin_path = None):
335                 Screen.__init__(self, session)
336                 self.session = session
337                 self.skin_path = skin_path
338                 if self.skin_path == None:
339                         self.skin_path = resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager")
340
341                 self.onChangedEntry = [ ]
342                 self.setup_title = _("Software manager setup")
343                 self.overwriteConfigfilesEntry = None
344
345                 self.list = [ ]
346                 ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changedEntry)
347
348                 self["actions"] = ActionMap(["SetupActions"],
349                         {
350                                 "cancel": self.keyCancel,
351                                 "save": self.apply,
352                         }, -2)
353
354                 self["key_red"] = StaticText(_("Cancel"))
355                 self["key_green"] = StaticText(_("OK"))
356                 self["key_yellow"] = StaticText()
357                 self["key_blue"] = StaticText()
358                 self["introduction"] = StaticText()
359
360                 self.createSetup()
361                 self.onLayoutFinish.append(self.layoutFinished)
362
363         def layoutFinished(self):
364                 self.setTitle(self.setup_title)
365
366         def createSetup(self):
367                 self.list = [ ]
368                 self.overwriteConfigfilesEntry = getConfigListEntry(_("Overwrite configuration files ?"), config.plugins.SoftwareManager.overwriteConfigFiles)
369                 self.list.append(self.overwriteConfigfilesEntry)        
370                 self["config"].list = self.list
371                 self["config"].l.setSeperation(400)
372                 self["config"].l.setList(self.list)
373                 if not self.selectionChanged in self["config"].onSelectionChanged:
374                         self["config"].onSelectionChanged.append(self.selectionChanged)
375                 self.selectionChanged()
376
377         def selectionChanged(self):
378                 if self["config"].getCurrent() == self.overwriteConfigfilesEntry:
379                         self["introduction"].setText(_("Overwrite configuration files during software upgrade?"))
380                 else:
381                         self["introduction"].setText("")
382
383         def newConfig(self):
384                 pass
385
386         def keyLeft(self):
387                 ConfigListScreen.keyLeft(self)
388
389         def keyRight(self):
390                 ConfigListScreen.keyRight(self)
391
392         def confirm(self, confirmed):
393                 if not confirmed:
394                         print "not confirmed"
395                         return
396                 else:
397                         self.keySave()
398
399         def apply(self):
400                 self.session.openWithCallback(self.confirm, MessageBox, _("Use this settings?"), MessageBox.TYPE_YESNO, timeout = 20, default = True)
401
402         def cancelConfirm(self, result):
403                 if not result:
404                         return
405                 for x in self["config"].list:
406                         x[1].cancel()
407                 self.close()
408
409         def keyCancel(self):
410                 if self["config"].isChanged():
411                         self.session.openWithCallback(self.cancelConfirm, MessageBox, _("Really close without saving settings?"), MessageBox.TYPE_YESNO, timeout = 20, default = True)
412                 else:
413                         self.close()
414
415         # for summary:
416         def changedEntry(self):
417                 for x in self.onChangedEntry:
418                         x()
419                 self.selectionChanged()
420
421         def getCurrentEntry(self):
422                 return self["config"].getCurrent()[0]
423
424         def getCurrentValue(self):
425                 return str(self["config"].getCurrent()[1].value)
426
427         def createSummary(self):
428                 from Screens.Setup import SetupSummary
429                 return SetupSummary
430
431
432 class SoftwareManagerInfo(Screen):
433         skin = """
434                 <screen name="SoftwareManagerInfo" position="center,center" size="560,440" title="SoftwareManager information">
435                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
436                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
437                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
438                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
439                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
440                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
441                         <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
442                         <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" transparent="1" />
443                         <widget source="list" render="Listbox" position="5,50" size="550,340" scrollbarMode="showOnDemand" selectionDisabled="0">
444                                 <convert type="TemplatedMultiContent">
445                                         {"template": [
446                                                         MultiContentEntryText(pos = (5, 0), size = (540, 26), font=0, flags = RT_HALIGN_LEFT | RT_HALIGN_CENTER, text = 0), # index 0 is the name
447                                                 ],
448                                         "fonts": [gFont("Regular", 24),gFont("Regular", 22)],
449                                         "itemHeight": 26
450                                         }
451                                 </convert>
452                         </widget>
453                         <ePixmap pixmap="skin_default/div-h.png" position="0,400" zPosition="1" size="560,2" />
454                         <widget source="introduction" render="Label" position="5,410" size="550,30" zPosition="10" font="Regular;21" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
455                 </screen>"""
456
457         def __init__(self, session, skin_path = None, mode = None):
458                 Screen.__init__(self, session)
459                 self.session = session
460                 self.mode = mode
461                 self.skin_path = skin_path
462                 if self.skin_path == None:
463                         self.skin_path = resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager")
464
465                 self["actions"] = ActionMap(["ShortcutActions", "WizardActions"],
466                         {
467                                 "back": self.close,
468                                 "red": self.close,
469                         }, -2)
470
471                 self.list = []
472                 self["list"] = List(self.list)
473                 
474                 self["key_red"] = StaticText(_("Close"))
475                 self["key_green"] = StaticText()
476                 self["key_yellow"] = StaticText()
477                 self["key_blue"] = StaticText()
478                 self["introduction"] = StaticText()
479
480                 self.onLayoutFinish.append(self.layoutFinished)
481
482         def layoutFinished(self):
483                 self.setTitle(_("Softwaremanager information"))
484                 if self.mode is not None:
485                         self.showInfos()
486
487         def showInfos(self):
488                 if self.mode == "backupinfo":
489                         self.list = []
490                         backupfiles = config.plugins.configurationbackup.backupdirs.value
491                         for entry in backupfiles:
492                                 print entry
493                                 self.list.append((entry,))
494                         self['list'].setList(self.list)
495                         
496
497 class PluginManager(Screen, DreamInfoHandler):
498
499         skin = """
500                 <screen name="PluginManager" position="center,center" size="560,440" title="Extensions management" >
501                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
502                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
503                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
504                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
505                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
506                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
507                         <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
508                         <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" transparent="1" />
509                         <widget source="list" render="Listbox" position="5,50" size="550,360" scrollbarMode="showOnDemand">
510                                 <convert type="TemplatedMultiContent">
511                                 {"templates":
512                                         {"default": (51,[
513                                                         MultiContentEntryText(pos = (0, 1), size = (470, 24), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
514                                                         MultiContentEntryText(pos = (0, 25), size = (470, 24), font=1, flags = RT_HALIGN_LEFT, text = 2), # index 2 is the description
515                                                         MultiContentEntryPixmapAlphaTest(pos = (475, 0), size = (48, 48), png = 5), # index 5 is the status pixmap
516                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 49), size = (550, 2), png = 6), # index 6 is the div pixmap
517                                                 ]),
518                                         "category": (40,[
519                                                         MultiContentEntryText(pos = (30, 0), size = (500, 22), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
520                                                         MultiContentEntryText(pos = (30, 22), size = (500, 16), font=2, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the description
521                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 38), size = (550, 2), png = 3), # index 3 is the div pixmap
522                                                 ])
523                                         },
524                                         "fonts": [gFont("Regular", 22),gFont("Regular", 20),gFont("Regular", 16)],
525                                         "itemHeight": 52
526                                 }
527                                 </convert>
528                         </widget>
529                         <widget source="status" render="Label" position="5,410" zPosition="10" size="540,30" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
530                 </screen>"""
531
532         def __init__(self, session, plugin_path = None, args = None):
533                 Screen.__init__(self, session)
534                 self.session = session
535                 self.skin_path = plugin_path
536                 if self.skin_path == None:
537                         self.skin_path = resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager")
538
539                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions", "InfobarEPGActions", "HelpActions" ],
540                 {
541                         "ok": self.handleCurrent,
542                         "back": self.exit,
543                         "red": self.exit,
544                         "green": self.handleCurrent,
545                         "yellow": self.handleSelected,
546                         "showEventInfo": self.handleSelected,
547                         "displayHelp": self.handleHelp,
548                 }, -1)
549
550                 self.list = []
551                 self.statuslist = []
552                 self.selectedFiles = []
553                 self.categoryList = []
554                 self.packetlist = []
555                 self["list"] = List(self.list)
556                 self["key_red"] = StaticText(_("Close"))
557                 self["key_green"] = StaticText("")
558                 self["key_yellow"] = StaticText("")
559                 self["key_blue"] = StaticText("")
560                 self["status"] = StaticText("")
561
562                 self.cmdList = []
563                 self.oktext = _("\nAfter pressing OK, please wait!")
564                 if not self.selectionChanged in self["list"].onSelectionChanged:
565                         self["list"].onSelectionChanged.append(self.selectionChanged)
566
567                 self.currList = ""
568                 self.currentSelectedTag = None
569                 self.currentSelectedIndex = None
570                 self.currentSelectedPackage = None
571                 self.saved_currentSelectedPackage = None
572                 
573                 self.onShown.append(self.setWindowTitle)
574                 self.onLayoutFinish.append(self.getUpdateInfos)
575
576         def setWindowTitle(self):
577                 self.setTitle(_("Extensions management"))
578
579         def exit(self):
580                 if self.currList == "packages":
581                         self.currList = "category"
582                         self.currentSelectedTag = None
583                         self["list"].style = "category"
584                         self['list'].setList(self.categoryList)
585                         self["list"].setIndex(self.currentSelectedIndex)
586                         self["list"].updateList(self.categoryList)
587                         self.selectionChanged()
588                 else:
589                         iSoftwareTools.cleanupSoftwareTools()
590                         self.prepareInstall()
591                         if len(self.cmdList):
592                                 self.session.openWithCallback(self.runExecute, PluginManagerInfo, self.skin_path, self.cmdList)
593                         else:
594                                 self.close()
595
596         def handleHelp(self):
597                 if self.currList != "status":
598                         self.session.open(PluginManagerHelp, self.skin_path)
599
600         def setState(self,status = None):
601                 if status:
602                         self.currList = "status"
603                         self.statuslist = []
604                         self["key_green"].setText("")
605                         self["key_blue"].setText("")
606                         self["key_yellow"].setText("")
607                         divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
608                         if status == 'update':
609                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
610                                 self.statuslist.append(( _("Updating software catalog"), '', _("Searching for available updates. Please wait..." ),'', '', statuspng, divpng, None, '' ))
611                         elif status == 'sync':
612                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
613                                 self.statuslist.append(( _("Package list update"), '', _("Searching for new installed or removed packages. Please wait..." ),'', '', statuspng, divpng, None, '' ))
614                         elif status == 'error':
615                                 self["key_green"].setText(_("Continue"))
616                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
617                                 self.statuslist.append(( _("Error"), '', _("There was an error downloading the packetlist. Please try again." ),'', '', statuspng, divpng, None, '' ))
618                         self["list"].style = "default"
619                         self['list'].setList(self.statuslist)
620
621
622         def getUpdateInfos(self):
623                 if (iSoftwareTools.lastDownloadDate is not None and iSoftwareTools.NetworkConnectionAvailable is False):
624                         self.rebuildList()
625                 else:
626                         self.setState('update')
627                         iSoftwareTools.startSoftwareTools(self.getUpdateInfosCB)
628
629         def getUpdateInfosCB(self, retval = None):
630                 if retval is not None:
631                         if retval is True:
632                                 if iSoftwareTools.available_updates is not 0:
633                                         self["status"].setText(_("There are at least ") + str(iSoftwareTools.available_updates) + _(" updates available."))
634                                 else:
635                                         self["status"].setText(_("There are no updates available."))
636                                 self.rebuildList()
637                         elif retval is False:
638                                 if iSoftwareTools.lastDownloadDate is None:
639                                         self.setState('error')
640                                         if iSoftwareTools.NetworkConnectionAvailable:
641                                                 self["status"].setText(_("Updatefeed not available."))
642                                         else:
643                                                 self["status"].setText(_("No network connection available."))
644                                 else:
645                                         iSoftwareTools.lastDownloadDate = time()
646                                         iSoftwareTools.list_updating = True
647                                         self.setState('update')
648                                         iSoftwareTools.getUpdates(self.getUpdateInfosCB)                                        
649
650         def rebuildList(self, retval = None):
651                 if self.currentSelectedTag is None:
652                         self.buildCategoryList()
653                 else:
654                         self.buildPacketList(self.currentSelectedTag)
655
656         def selectionChanged(self):
657                 current = self["list"].getCurrent()
658                 self["status"].setText("")
659                 if current:
660                         if self.currList == "packages":
661                                 self["key_red"].setText(_("Back"))
662                                 if current[4] == 'installed':
663                                         self["key_green"].setText(_("Uninstall"))
664                                 elif current[4] == 'installable':
665                                         self["key_green"].setText(_("Install"))
666                                         if iSoftwareTools.NetworkConnectionAvailable is False:
667                                                 self["key_green"].setText("")
668                                 elif current[4] == 'remove':
669                                         self["key_green"].setText(_("Undo uninstall"))
670                                 elif current[4] == 'install':
671                                         self["key_green"].setText(_("Undo install"))
672                                         if iSoftwareTools.NetworkConnectionAvailable is False:
673                                                 self["key_green"].setText("")
674                                 self["key_yellow"].setText(_("View details"))
675                                 self["key_blue"].setText("")
676                                 if len(self.selectedFiles) == 0 and iSoftwareTools.available_updates is not 0:
677                                         self["status"].setText(_("There are at least ") + str(iSoftwareTools.available_updates) + _(" updates available."))
678                                 elif len(self.selectedFiles) is not 0:
679                                         self["status"].setText(str(len(self.selectedFiles)) + _(" packages selected."))
680                                 else:
681                                         self["status"].setText(_("There are currently no outstanding actions."))
682                         elif self.currList == "category":
683                                 self["key_red"].setText(_("Close"))
684                                 self["key_green"].setText("")
685                                 self["key_yellow"].setText("")
686                                 self["key_blue"].setText("")
687                                 if len(self.selectedFiles) == 0 and iSoftwareTools.available_updates is not 0:
688                                         self["status"].setText(_("There are at least ") + str(iSoftwareTools.available_updates) + _(" updates available."))
689                                         self["key_yellow"].setText(_("Update"))
690                                 elif len(self.selectedFiles) is not 0:
691                                         self["status"].setText(str(len(self.selectedFiles)) + _(" packages selected."))
692                                         self["key_yellow"].setText(_("Process"))
693                                 else:
694                                         self["status"].setText(_("There are currently no outstanding actions."))
695
696         def getSelectionState(self, detailsFile):
697                 for entry in self.selectedFiles:
698                         if entry[0] == detailsFile:
699                                 return True
700                 return False
701
702         def handleCurrent(self):
703                 current = self["list"].getCurrent()
704                 if current:
705                         if self.currList == "category":
706                                 self.currentSelectedIndex = self["list"].index
707                                 selectedTag = current[2]
708                                 self.buildPacketList(selectedTag)
709                         elif self.currList == "packages":
710                                 if current[7] is not '':
711                                         idx = self["list"].getIndex()
712                                         detailsFile = self.list[idx][1]
713                                         if self.list[idx][7] == True:
714                                                 for entry in self.selectedFiles:
715                                                         if entry[0] == detailsFile:
716                                                                 self.selectedFiles.remove(entry)
717                                         else:
718                                                 alreadyinList = False
719                                                 for entry in self.selectedFiles:
720                                                         if entry[0] == detailsFile:
721                                                                 alreadyinList = True
722                                                 if not alreadyinList:
723                                                         if (iSoftwareTools.NetworkConnectionAvailable is False and current[4] in ('installable','install')):
724                                                                 pass
725                                                         else:
726                                                                 self.selectedFiles.append((detailsFile,current[4],current[3]))
727                                                                 self.currentSelectedPackage = ((detailsFile,current[4],current[3]))
728                                         if current[4] == 'installed':
729                                                 self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'remove', True)
730                                         elif current[4] == 'installable':
731                                                 if iSoftwareTools.NetworkConnectionAvailable:
732                                                         self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'install', True)
733                                         elif current[4] == 'remove':
734                                                 self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'installed', False)
735                                         elif current[4] == 'install':
736                                                 if iSoftwareTools.NetworkConnectionAvailable:
737                                                         self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'installable',False)
738                                         self["list"].setList(self.list)
739                                         self["list"].setIndex(idx)
740                                         self["list"].updateList(self.list)
741                                         self.selectionChanged()
742                         elif self.currList == "status":
743                                 iSoftwareTools.lastDownloadDate = time()
744                                 iSoftwareTools.list_updating = True
745                                 self.setState('update')
746                                 iSoftwareTools.getUpdates(self.getUpdateInfosCB)
747                                 
748         def handleSelected(self):
749                 current = self["list"].getCurrent()
750                 if current:
751                         if self.currList == "packages":
752                                 if current[7] is not '':
753                                         detailsfile = iSoftwareTools.directory[0] + "/" + current[1]
754                                         if (os_path.exists(detailsfile) == True):
755                                                 self.saved_currentSelectedPackage = self.currentSelectedPackage
756                                                 self.session.openWithCallback(self.detailsClosed, PluginDetails, self.skin_path, current)
757                                         else:
758                                                 self.session.open(MessageBox, _("Sorry, no Details available!"), MessageBox.TYPE_INFO, timeout = 10)
759                         elif self.currList == "category":
760                                 self.prepareInstall()
761                                 if len(self.cmdList):
762                                         self.session.openWithCallback(self.runExecute, PluginManagerInfo, self.skin_path, self.cmdList)
763
764         def detailsClosed(self, result = None):
765                 if result is not None:
766                         if result is not False:
767                                 self.setState('sync')
768                                 iSoftwareTools.lastDownloadDate = time()
769                                 for entry in self.selectedFiles:
770                                         if entry == self.saved_currentSelectedPackage:
771                                                 self.selectedFiles.remove(entry)
772                                 iSoftwareTools.startIpkgListInstalled(self.rebuildList)
773
774         def buildEntryComponent(self, name, details, description, packagename, state, selected = False):
775                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
776                 installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installed.png"))
777                 installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installable.png"))
778                 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
779                 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/install.png"))
780                 if state == 'installed':
781                         return((name, details, description, packagename, state, installedpng, divpng, selected))
782                 elif state == 'installable':
783                         return((name, details, description, packagename, state, installablepng, divpng, selected))
784                 elif state == 'remove':
785                         return((name, details, description, packagename, state, removepng, divpng, selected))
786                 elif state == 'install':
787                         return((name, details, description, packagename, state, installpng, divpng, selected))
788
789         def buildPacketList(self, categorytag = None):
790                 if categorytag is not None:
791                         self.currList = "packages"
792                         self.currentSelectedTag = categorytag
793                         self.packetlist = []
794                         for package in iSoftwareTools.packagesIndexlist[:]:
795                                 prerequisites = package[0]["prerequisites"]
796                                 if prerequisites.has_key("tag"):
797                                         for foundtag in prerequisites["tag"]:
798                                                 if categorytag == foundtag:
799                                                         attributes = package[0]["attributes"]
800                                                         if attributes.has_key("packagetype"):
801                                                                 if attributes["packagetype"] == "internal":
802                                                                         continue
803                                                                 self.packetlist.append([attributes["name"], attributes["details"], attributes["shortdescription"], attributes["packagename"]])
804                                                         else:
805                                                                 self.packetlist.append([attributes["name"], attributes["details"], attributes["shortdescription"], attributes["packagename"]])
806                         self.list = []
807                         for x in self.packetlist:
808                                 status = ""
809                                 name = x[0].strip()
810                                 details = x[1].strip()
811                                 description = x[2].strip()
812                                 packagename = x[3].strip()
813                                 selectState = self.getSelectionState(details)
814                                 if iSoftwareTools.installed_packetlist.has_key(packagename):
815                                         if selectState == True:
816                                                 status = "remove"
817                                         else:
818                                                 status = "installed"
819                                         self.list.append(self.buildEntryComponent(name, _(details), _(description), packagename, status, selected = selectState))
820                                 else:
821                                         if selectState == True:
822                                                 status = "install"
823                                         else:
824                                                 status = "installable"
825                                         self.list.append(self.buildEntryComponent(name, _(details), _(description), packagename, status, selected = selectState))
826                         if len(self.list):
827                                 self.list.sort(key=lambda x: x[0])
828                         self["list"].style = "default"
829                         self['list'].setList(self.list)
830                         self["list"].updateList(self.list)
831                         self.selectionChanged()
832
833         def buildCategoryList(self):
834                 self.currList = "category"
835                 self.categories = []
836                 self.categoryList = []
837                 for package in iSoftwareTools.packagesIndexlist[:]:
838                         prerequisites = package[0]["prerequisites"]
839                         if prerequisites.has_key("tag"):
840                                 for foundtag in prerequisites["tag"]:
841                                         attributes = package[0]["attributes"]
842                                         if foundtag not in self.categories:
843                                                 self.categories.append(foundtag)
844                                                 self.categoryList.append(self.buildCategoryComponent(foundtag))
845                 self.categoryList.sort(key=lambda x: x[0])
846                 self["list"].style = "category"
847                 self['list'].setList(self.categoryList)
848                 self["list"].updateList(self.categoryList)
849                 self.selectionChanged()
850
851         def buildCategoryComponent(self, tag = None):
852                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
853                 if tag is not None:
854                         if tag == 'System':
855                                 return(( _("System"), _("View list of available system extensions" ), tag, divpng ))
856                         elif tag == 'Skin':
857                                 return(( _("Skins"), _("View list of available skins" ), tag, divpng ))
858                         elif tag == 'Recording':
859                                 return(( _("Recordings"), _("View list of available recording extensions" ), tag, divpng ))
860                         elif tag == 'Network':
861                                 return(( _("Network"), _("View list of available networking extensions" ), tag, divpng ))
862                         elif tag == 'CI':
863                                 return(( _("CommonInterface"), _("View list of available CommonInterface extensions" ), tag, divpng ))
864                         elif tag == 'Default':
865                                 return(( _("Default Settings"), _("View list of available default settings" ), tag, divpng ))
866                         elif tag == 'SAT':
867                                 return(( _("Satellite equipment"), _("View list of available Satellite equipment extensions." ), tag, divpng ))
868                         elif tag == 'Software':
869                                 return(( _("Software"), _("View list of available software extensions" ), tag, divpng ))
870                         elif tag == 'Multimedia':
871                                 return(( _("Multimedia"), _("View list of available multimedia extensions." ), tag, divpng ))
872                         elif tag == 'Display':
873                                 return(( _("Display and Userinterface"), _("View list of available Display and Userinterface extensions." ), tag, divpng ))
874                         elif tag == 'EPG':
875                                 return(( _("Electronic Program Guide"), _("View list of available EPG extensions." ), tag, divpng ))
876                         elif tag == 'Communication':
877                                 return(( _("Communication"), _("View list of available communication extensions." ), tag, divpng ))
878                         else: # dynamically generate non existent tags
879                                 return(( str(tag), _("View list of available ") + str(tag) + _(" extensions." ), tag, divpng ))
880
881         def prepareInstall(self):
882                 self.cmdList = []
883                 if iSoftwareTools.available_updates > 0:
884                         self.cmdList.append((IpkgComponent.CMD_UPGRADE, { "test_only": False }))
885                 if self.selectedFiles and len(self.selectedFiles):
886                         for plugin in self.selectedFiles:
887                                 detailsfile = iSoftwareTools.directory[0] + "/" + plugin[0]
888                                 if (os_path.exists(detailsfile) == True):
889                                         iSoftwareTools.fillPackageDetails(plugin[0])
890                                         self.package = iSoftwareTools.packageDetails[0]
891                                         if self.package[0].has_key("attributes"):
892                                                 self.attributes = self.package[0]["attributes"]
893                                         if self.attributes.has_key("package"):
894                                                 self.packagefiles = self.attributes["package"]
895                                         if plugin[1] == 'installed':
896                                                 if self.packagefiles:
897                                                         for package in self.packagefiles[:]:
898                                                                 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package["name"] }))
899                                                 else:
900                                                         self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": plugin[2] }))
901                                         else:
902                                                 if self.packagefiles:
903                                                         for package in self.packagefiles[:]:
904                                                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package["name"] }))
905                                                 else:
906                                                         self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": plugin[2] }))
907                                 else:
908                                         if plugin[1] == 'installed':
909                                                 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": plugin[2] }))
910                                         else:
911                                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": plugin[2] }))
912
913         def runExecute(self, result = None):
914                 if result is not None:
915                         if result[0] is True:
916                                 self.session.openWithCallback(self.runExecuteFinished, Ipkg, cmdList = self.cmdList)
917                         elif result[0] is False:
918                                 self.cmdList = result[1]
919                                 self.session.openWithCallback(self.runExecuteFinished, Ipkg, cmdList = self.cmdList)
920                 else:
921                         self.close()
922
923         def runExecuteFinished(self):
924                 self.session.openWithCallback(self.ExecuteReboot, MessageBox, _("Install or remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
925
926         def ExecuteReboot(self, result):
927                 if result is None:
928                         return
929                 if result is False:
930                         self.reloadPluginlist()
931                         self.selectedFiles = []
932                         self.detailsClosed(True)
933                 if result:
934                         quitMainloop(3)
935
936         def reloadPluginlist(self):
937                 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
938
939
940 class PluginManagerInfo(Screen):
941         skin = """
942                 <screen name="PluginManagerInfo" position="center,center" size="560,450" title="Plugin manager activity information" >
943                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
944                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
945                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
946                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
947                         <widget source="list" render="Listbox" position="5,50" size="550,350" scrollbarMode="showOnDemand" selectionDisabled="1">
948                                 <convert type="TemplatedMultiContent">
949                                         {"template": [
950                                                         MultiContentEntryText(pos = (50, 0), size = (150, 26), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
951                                                         MultiContentEntryText(pos = (50, 27), size = (540, 23), font=1, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the state
952                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 1), size = (48, 48), png = 2), # index 2 is the status pixmap
953                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 48), size = (550, 2), png = 3), # index 3 is the div pixmap
954                                                 ],
955                                         "fonts": [gFont("Regular", 24),gFont("Regular", 22)],
956                                         "itemHeight": 50
957                                         }
958                                 </convert>
959                         </widget>
960                         <ePixmap pixmap="skin_default/div-h.png" position="0,404" zPosition="10" size="560,2" transparent="1" alphatest="on" />
961                         <widget source="status" render="Label" position="5,408" zPosition="10" size="550,44" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
962                 </screen>"""
963
964         def __init__(self, session, plugin_path, cmdlist = None):
965                 Screen.__init__(self, session)
966                 self.session = session
967                 self.skin_path = plugin_path
968                 self.cmdlist = cmdlist
969
970                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
971                 {
972                         "ok": self.process_all,
973                         "back": self.exit,
974                         "red": self.exit,
975                         "green": self.process_extensions,
976                 }, -1)
977
978                 self.list = []
979                 self["list"] = List(self.list)
980                 self["key_red"] = StaticText(_("Cancel"))
981                 self["key_green"] = StaticText(_("Only extensions."))
982                 self["status"] = StaticText(_("Following tasks will be done after you press OK!"))
983
984                 self.onShown.append(self.setWindowTitle)
985                 self.onLayoutFinish.append(self.rebuildList)
986
987         def setWindowTitle(self):
988                 self.setTitle(_("Plugin manager activity information"))
989
990         def rebuildList(self):
991                 self.list = []
992                 if self.cmdlist is not None:
993                         for entry in self.cmdlist:
994                                 action = ""
995                                 info = ""
996                                 cmd = entry[0]
997                                 if cmd == 0:
998                                         action = 'install'
999                                 elif cmd == 2:
1000                                         action = 'remove'
1001                                 else:
1002                                         action = 'upgrade'
1003                                 args = entry[1]
1004                                 if cmd == 0:
1005                                         info = args['package']
1006                                 elif cmd == 2:
1007                                         info = args['package']
1008                                 else:
1009                                         info = _("Dreambox software because updates are available.")
1010
1011                                 self.list.append(self.buildEntryComponent(action,info))
1012                         self['list'].setList(self.list)
1013                         self['list'].updateList(self.list)
1014
1015         def buildEntryComponent(self, action,info):
1016                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1017                 upgradepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
1018                 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/install.png"))
1019                 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
1020                 if action == 'install':
1021                         return(( _('Installing'), info, installpng, divpng))
1022                 elif action == 'remove':
1023                         return(( _('Removing'), info, removepng, divpng))
1024                 else:
1025                         return(( _('Upgrading'), info, upgradepng, divpng))
1026
1027         def exit(self):
1028                 self.close()
1029
1030         def process_all(self):
1031                 self.close((True,None))
1032
1033         def process_extensions(self):
1034                 self.list = []
1035                 if self.cmdlist is not None:
1036                         for entry in self.cmdlist:
1037                                 cmd = entry[0]
1038                                 if entry[0] in (0,2):
1039                                         self.list.append((entry))
1040                 self.close((False,self.list))
1041
1042
1043 class PluginManagerHelp(Screen):
1044         skin = """
1045                 <screen name="PluginManagerHelp" position="center,center" size="560,450" title="Plugin manager help" >
1046                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1047                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
1048                         <widget source="list" render="Listbox" position="5,50" size="550,350" scrollbarMode="showOnDemand" selectionDisabled="1">
1049                                 <convert type="TemplatedMultiContent">
1050                                         {"template": [
1051                                                         MultiContentEntryText(pos = (50, 0), size = (540, 26), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
1052                                                         MultiContentEntryText(pos = (50, 27), size = (540, 23), font=1, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the state
1053                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 1), size = (48, 48), png = 2), # index 2 is the status pixmap
1054                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 48), size = (550, 2), png = 3), # index 3 is the div pixmap
1055                                                 ],
1056                                         "fonts": [gFont("Regular", 24),gFont("Regular", 22)],
1057                                         "itemHeight": 50
1058                                         }
1059                                 </convert>
1060                         </widget>
1061                         <ePixmap pixmap="skin_default/div-h.png" position="0,404" zPosition="10" size="560,2" transparent="1" alphatest="on" />
1062                         <widget source="status" render="Label" position="5,408" zPosition="10" size="550,44" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
1063                 </screen>"""
1064
1065         def __init__(self, session, plugin_path):
1066                 Screen.__init__(self, session)
1067                 self.session = session
1068                 self.skin_path = plugin_path
1069
1070                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
1071                 {
1072                         "back": self.exit,
1073                         "red": self.exit,
1074                 }, -1)
1075
1076                 self.list = []
1077                 self["list"] = List(self.list)
1078                 self["key_red"] = StaticText(_("Close"))
1079                 self["status"] = StaticText(_("A small overview of the available icon states and actions."))
1080
1081                 self.onShown.append(self.setWindowTitle)
1082                 self.onLayoutFinish.append(self.rebuildList)
1083
1084         def setWindowTitle(self):
1085                 self.setTitle(_("Plugin manager help"))
1086
1087         def rebuildList(self):
1088                 self.list = []
1089                 self.list.append(self.buildEntryComponent('install'))
1090                 self.list.append(self.buildEntryComponent('installable'))
1091                 self.list.append(self.buildEntryComponent('installed'))
1092                 self.list.append(self.buildEntryComponent('remove'))
1093                 self['list'].setList(self.list)
1094                 self['list'].updateList(self.list)
1095
1096         def buildEntryComponent(self, state):
1097                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1098                 installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installed.png"))
1099                 installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installable.png"))
1100                 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
1101                 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/install.png"))
1102
1103                 if state == 'installed':
1104                         return(( _('This plugin is installed.'), _('You can remove this plugin.'), installedpng, divpng))
1105                 elif state == 'installable':
1106                         return(( _('This plugin is not installed.'), _('You can install this plugin.'), installablepng, divpng))
1107                 elif state == 'install':
1108                         return(( _('This plugin will be installed.'), _('You can cancel the installation.'), installpng, divpng))
1109                 elif state == 'remove':
1110                         return(( _('This plugin will be removed.'), _('You can cancel the removal.'), removepng, divpng))
1111
1112         def exit(self):
1113                 self.close()
1114
1115
1116 class PluginDetails(Screen, DreamInfoHandler):
1117         skin = """
1118                 <screen name="PluginDetails" position="center,center" size="600,440" title="Plugin details" >
1119                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1120                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1121                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
1122                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
1123                         <widget source="author" render="Label" position="10,50" size="500,25" zPosition="10" font="Regular;21" transparent="1" />
1124                         <widget name="statuspic" position="550,40" size="48,48" alphatest="on"/>
1125                         <widget name="divpic" position="0,80" size="600,2" alphatest="on"/>
1126                         <widget name="detailtext" position="10,90" size="270,330" zPosition="10" font="Regular;21" transparent="1" halign="left" valign="top"/>
1127                         <widget name="screenshot" position="290,90" size="300,330" alphatest="on"/>
1128                 </screen>"""
1129         def __init__(self, session, plugin_path, packagedata = None):
1130                 Screen.__init__(self, session)
1131                 self.skin_path = plugin_path
1132                 self.language = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
1133                 self.attributes = None
1134                 DreamInfoHandler.__init__(self, self.statusCallback, blocking = False)
1135                 self.directory = resolveFilename(SCOPE_METADIR)
1136                 if packagedata:
1137                         self.pluginname = packagedata[0]
1138                         self.details = packagedata[1]
1139                         self.pluginstate = packagedata[4]
1140                         self.statuspicinstance = packagedata[5]
1141                         self.divpicinstance = packagedata[6]
1142                         self.fillPackageDetails(self.details)
1143
1144                 self.thumbnail = ""
1145
1146                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
1147                 {
1148                         "back": self.exit,
1149                         "red": self.exit,
1150                         "green": self.go,
1151                         "up": self.pageUp,
1152                         "down": self.pageDown,
1153                         "left": self.pageUp,
1154                         "right": self.pageDown,
1155                 }, -1)
1156
1157                 self["key_red"] = StaticText(_("Close"))
1158                 self["key_green"] = StaticText("")
1159                 self["author"] = StaticText()
1160                 self["statuspic"] = Pixmap()
1161                 self["divpic"] = Pixmap()
1162                 self["screenshot"] = Pixmap()
1163                 self["detailtext"] = ScrollLabel()
1164
1165                 self["statuspic"].hide()
1166                 self["screenshot"].hide()
1167                 self["divpic"].hide()
1168
1169                 self.package = self.packageDetails[0]
1170                 if self.package[0].has_key("attributes"):
1171                         self.attributes = self.package[0]["attributes"]
1172
1173                 self.cmdList = []
1174                 self.oktext = _("\nAfter pressing OK, please wait!")
1175                 self.picload = ePicLoad()
1176                 self.picload.PictureData.get().append(self.paintScreenshotPixmapCB)
1177                 self.onShown.append(self.setWindowTitle)
1178                 self.onLayoutFinish.append(self.setInfos)
1179
1180         def setWindowTitle(self):
1181                 self.setTitle(_("Details for plugin: ") + self.pluginname )
1182
1183         def exit(self):
1184                 self.close(False)
1185
1186         def pageUp(self):
1187                 self["detailtext"].pageUp()
1188
1189         def pageDown(self):
1190                 self["detailtext"].pageDown()
1191
1192         def statusCallback(self, status, progress):
1193                 pass
1194
1195         def setInfos(self):
1196                 if self.attributes.has_key("screenshot"):
1197                         self.loadThumbnail(self.attributes)
1198
1199                 if self.attributes.has_key("name"):
1200                         self.pluginname = self.attributes["name"]
1201                 else:
1202                         self.pluginname = _("unknown")
1203
1204                 if self.attributes.has_key("author"):
1205                         self.author = self.attributes["author"]
1206                 else:
1207                         self.author = _("unknown")
1208
1209                 if self.attributes.has_key("description"):
1210                         self.description = _(self.attributes["description"].replace("\\n", "\n"))
1211                 else:
1212                         self.description = _("No description available.")
1213
1214                 self["author"].setText(_("Author: ") + self.author)
1215                 self["detailtext"].setText(_(self.description))
1216                 if self.pluginstate in ('installable', 'install'):
1217                         if iSoftwareTools.NetworkConnectionAvailable:
1218                                 self["key_green"].setText(_("Install"))
1219                         else:
1220                                 self["key_green"].setText("")
1221                 else:
1222                         self["key_green"].setText(_("Remove"))
1223
1224         def loadThumbnail(self, entry):
1225                 thumbnailUrl = None
1226                 if entry.has_key("screenshot"):
1227                         thumbnailUrl = entry["screenshot"]
1228                         if self.language == "de":
1229                                 if thumbnailUrl[-7:] == "_en.jpg":
1230                                         thumbnailUrl = thumbnailUrl[:-7] + "_de.jpg"
1231
1232                 if thumbnailUrl is not None:
1233                         self.thumbnail = "/tmp/" + thumbnailUrl.split('/')[-1]
1234                         print "[PluginDetails] downloading screenshot " + thumbnailUrl + " to " + self.thumbnail
1235                         if iSoftwareTools.NetworkConnectionAvailable:
1236                                 client.downloadPage(thumbnailUrl,self.thumbnail).addCallback(self.setThumbnail).addErrback(self.fetchFailed)
1237                         else:
1238                                 self.setThumbnail(noScreenshot = True)
1239                 else:
1240                         self.setThumbnail(noScreenshot = True)
1241
1242         def setThumbnail(self, noScreenshot = False):
1243                 if not noScreenshot:
1244                         filename = self.thumbnail
1245                 else:
1246                         filename = resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/noprev.png")
1247
1248                 sc = AVSwitch().getFramebufferScale()
1249                 self.picload.setPara((self["screenshot"].instance.size().width(), self["screenshot"].instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
1250                 self.picload.startDecode(filename)
1251
1252                 if self.statuspicinstance != None:
1253                         self["statuspic"].instance.setPixmap(self.statuspicinstance.__deref__())
1254                         self["statuspic"].show()
1255                 if self.divpicinstance != None:
1256                         self["divpic"].instance.setPixmap(self.divpicinstance.__deref__())
1257                         self["divpic"].show()
1258
1259         def paintScreenshotPixmapCB(self, picInfo=None):
1260                 ptr = self.picload.getData()
1261                 if ptr != None:
1262                         self["screenshot"].instance.setPixmap(ptr.__deref__())
1263                         self["screenshot"].show()
1264                 else:
1265                         self.setThumbnail(noScreenshot = True)
1266
1267         def go(self):
1268                 if self.attributes.has_key("package"):
1269                         self.packagefiles = self.attributes["package"]
1270                 self.cmdList = []
1271                 if self.pluginstate in ('installed', 'remove'):
1272                         if self.packagefiles:
1273                                 for package in self.packagefiles[:]:
1274                                         self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package["name"] }))
1275                                         if len(self.cmdList):
1276                                                 self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n") + self.pluginname + "\n" + self.oktext)
1277                 else:
1278                         if iSoftwareTools.NetworkConnectionAvailable:
1279                                 if self.packagefiles:
1280                                         for package in self.packagefiles[:]:
1281                                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package["name"] }))
1282                                                 if len(self.cmdList):
1283                                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n") + self.pluginname + "\n" + self.oktext)
1284
1285         def runUpgrade(self, result):
1286                 if result:
1287                         self.session.openWithCallback(self.runUpgradeFinished, Ipkg, cmdList = self.cmdList)
1288
1289         def runUpgradeFinished(self):
1290                 self.session.openWithCallback(self.UpgradeReboot, MessageBox, _("Installation finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1291
1292         def UpgradeReboot(self, result):
1293                 if result is None:
1294                         return
1295                 if result is False:
1296                         self.close(True)
1297                 if result:
1298                         quitMainloop(3)
1299
1300         def runRemove(self, result):
1301                 if result:
1302                         self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
1303
1304         def runRemoveFinished(self):
1305                 self.session.openWithCallback(self.RemoveReboot, MessageBox, _("Remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1306
1307         def RemoveReboot(self, result):
1308                 if result is None:
1309                         return
1310                 if result is False:
1311                         self.close(True)
1312                 if result:
1313                         quitMainloop(3)
1314
1315         def reloadPluginlist(self):
1316                 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
1317
1318         def fetchFailed(self,string):
1319                 self.setThumbnail(noScreenshot = True)
1320                 print "[PluginDetails] fetch failed " + string.getErrorMessage()
1321
1322
1323 class UpdatePlugin(Screen):
1324         skin = """
1325                 <screen name="UpdatePlugin" position="center,center" size="550,300" title="Software update" >
1326                         <widget name="activityslider" position="0,0" size="550,5"  />
1327                         <widget name="slider" position="0,150" size="550,30"  />
1328                         <widget source="package" render="Label" position="10,30" size="540,20" font="Regular;18" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
1329                         <widget source="status" render="Label" position="10,180" size="540,100" font="Regular;20" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
1330                 </screen>"""
1331
1332         def __init__(self, session, args = None):
1333                 Screen.__init__(self, session)
1334
1335                 self.sliderPackages = { "dreambox-dvb-modules": 1, "enigma2": 2, "tuxbox-image-info": 3 }
1336
1337                 self.slider = Slider(0, 4)
1338                 self["slider"] = self.slider
1339                 self.activityslider = Slider(0, 100)
1340                 self["activityslider"] = self.activityslider
1341                 self.status = StaticText(_("Upgrading Dreambox... Please wait"))
1342                 self["status"] = self.status
1343                 self.package = StaticText()
1344                 self["package"] = self.package
1345                 self.oktext = _("Press OK on your remote control to continue.")
1346
1347                 self.packages = 0
1348                 self.error = 0
1349                 self.processed_packages = []
1350
1351                 self.activity = 0
1352                 self.activityTimer = eTimer()
1353                 self.activityTimer.callback.append(self.doActivityTimer)
1354                 self.activityTimer.start(100, False)
1355
1356                 self.ipkg = IpkgComponent()
1357                 self.ipkg.addCallback(self.ipkgCallback)
1358
1359                 self.updating = True
1360                 self.package.setText(_("Package list update"))
1361                 self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
1362
1363                 self["actions"] = ActionMap(["WizardActions"], 
1364                 {
1365                         "ok": self.exit,
1366                         "back": self.exit
1367                 }, -1)
1368
1369         def doActivityTimer(self):
1370                 self.activity += 1
1371                 if self.activity == 100:
1372                         self.activity = 0
1373                 self.activityslider.setValue(self.activity)
1374
1375         def ipkgCallback(self, event, param):
1376                 if event == IpkgComponent.EVENT_DOWNLOAD:
1377                         self.status.setText(_("Downloading"))
1378                 elif event == IpkgComponent.EVENT_UPGRADE:
1379                         if self.sliderPackages.has_key(param):
1380                                 self.slider.setValue(self.sliderPackages[param])
1381                         self.package.setText(param)
1382                         self.status.setText(_("Upgrading"))
1383                         if not param in self.processed_packages:
1384                                 self.processed_packages.append(param)
1385                                 self.packages += 1
1386                 elif event == IpkgComponent.EVENT_INSTALL:
1387                         self.package.setText(param)
1388                         self.status.setText(_("Installing"))
1389                         if not param in self.processed_packages:
1390                                 self.processed_packages.append(param)
1391                                 self.packages += 1
1392                 elif event == IpkgComponent.EVENT_REMOVE:
1393                         self.package.setText(param)
1394                         self.status.setText(_("Removing"))
1395                         if not param in self.processed_packages:
1396                                 self.processed_packages.append(param)
1397                                 self.packages += 1
1398                 elif event == IpkgComponent.EVENT_CONFIGURING:
1399                         self.package.setText(param)
1400                         self.status.setText(_("Configuring"))
1401                         
1402                 elif event == IpkgComponent.EVENT_MODIFIED:
1403                         if config.plugins.SoftwareManager.overwriteConfigFiles.value in ("N", "Y"):
1404                                 self.ipkg.write(True and config.plugins.SoftwareManager.overwriteConfigFiles.value)
1405                         else:
1406                                 self.session.openWithCallback(
1407                                         self.modificationCallback,
1408                                         MessageBox,
1409                                         _("A configuration file (%s) was modified since Installation.\nDo you want to keep your version?") % (param)
1410                                 )
1411                 elif event == IpkgComponent.EVENT_ERROR:
1412                         self.error += 1
1413                 elif event == IpkgComponent.EVENT_DONE:
1414                         if self.updating:
1415                                 self.updating = False
1416                                 self.ipkg.startCmd(IpkgComponent.CMD_UPGRADE, args = {'test_only': False})
1417                         elif self.error == 0:
1418                                 self.slider.setValue(4)
1419                                 
1420                                 self.activityTimer.stop()
1421                                 self.activityslider.setValue(0)
1422                                 
1423                                 self.package.setText(_("Done - Installed or upgraded %d packages") % self.packages)
1424                                 self.status.setText(self.oktext)
1425                         else:
1426                                 self.activityTimer.stop()
1427                                 self.activityslider.setValue(0)
1428                                 error = _("your dreambox might be unusable now. Please consult the manual for further assistance before rebooting your dreambox.")
1429                                 if self.packages == 0:
1430                                         error = _("No packages were upgraded yet. So you can check your network and try again.")
1431                                 if self.updating:
1432                                         error = _("Your dreambox isn't connected to the internet properly. Please check it and try again.")
1433                                 self.status.setText(_("Error") +  " - " + error)
1434                 #print event, "-", param
1435                 pass
1436
1437         def modificationCallback(self, res):
1438                 self.ipkg.write(res and "N" or "Y")
1439
1440         def exit(self):
1441                 if not self.ipkg.isRunning():
1442                         if self.packages != 0 and self.error == 0:
1443                                 self.session.openWithCallback(self.exitAnswer, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"))
1444                         else:
1445                                 self.close()
1446
1447         def exitAnswer(self, result):
1448                 if result is not None and result:
1449                         quitMainloop(2)
1450                 self.close()
1451
1452
1453
1454 class IPKGMenu(Screen):
1455         skin = """
1456                 <screen name="IPKGMenu" position="center,center" size="560,400" title="Select upgrade source to edit." >
1457                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1458                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1459                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
1460                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
1461                         <widget name="filelist" position="5,50" size="550,340" scrollbarMode="showOnDemand" />
1462                 </screen>"""
1463
1464         def __init__(self, session, plugin_path):
1465                 Screen.__init__(self, session)
1466                 self.skin_path = plugin_path
1467                 
1468                 self["key_red"] = StaticText(_("Close"))
1469                 self["key_green"] = StaticText(_("Edit"))
1470
1471                 self.sel = []
1472                 self.val = []
1473                 self.entry = False
1474                 self.exe = False
1475                 
1476                 self.path = ""
1477
1478                 self["actions"] = NumberActionMap(["SetupActions"],
1479                 {
1480                         "ok": self.KeyOk,
1481                         "cancel": self.keyCancel
1482                 }, -1)
1483
1484                 self["shortcuts"] = ActionMap(["ShortcutActions"],
1485                 {
1486                         "red": self.keyCancel,
1487                         "green": self.KeyOk,
1488                 })
1489                 self.flist = []
1490                 self["filelist"] = MenuList(self.flist)
1491                 self.fill_list()
1492                 self.onLayoutFinish.append(self.layoutFinished)
1493
1494         def layoutFinished(self):
1495                 self.setWindowTitle()
1496
1497         def setWindowTitle(self):
1498                 self.setTitle(_("Select upgrade source to edit."))
1499
1500         def fill_list(self):
1501                 self.flist = []
1502                 self.path = '/etc/ipkg/'
1503                 if (os_path.exists(self.path) == False):
1504                         self.entry = False
1505                         return
1506                 for file in listdir(self.path):
1507                         if (file.endswith(".conf")):
1508                                 if file != 'arch.conf':
1509                                         self.flist.append((file))
1510                                         self.entry = True
1511                                         self["filelist"].l.setList(self.flist)
1512
1513         def KeyOk(self):
1514                 if (self.exe == False) and (self.entry == True):
1515                         self.sel = self["filelist"].getCurrent()
1516                         self.val = self.path + self.sel
1517                         self.session.open(IPKGSource, self.val)
1518
1519         def keyCancel(self):
1520                 self.close()
1521
1522         def Exit(self):
1523                 self.close()
1524
1525
1526 class IPKGSource(Screen):
1527         skin = """
1528                 <screen name="IPKGSource" position="center,center" size="560,80" title="Edit upgrade source url." >
1529                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1530                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1531                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
1532                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
1533                         <widget name="text" position="5,50" size="550,25" font="Regular;20" backgroundColor="background" foregroundColor="#cccccc" />
1534                 </screen>"""
1535
1536         def __init__(self, session, configfile = None):
1537                 Screen.__init__(self, session)
1538                 self.session = session
1539                 self.configfile = configfile
1540                 text = ""
1541                 if self.configfile:
1542                         try:
1543                                 fp = file(configfile, 'r')
1544                                 sources = fp.readlines()
1545                                 if sources:
1546                                         text = sources[0]
1547                                 fp.close()
1548                         except IOError:
1549                                 pass
1550
1551                 desk = getDesktop(0)
1552                 x= int(desk.size().width())
1553                 y= int(desk.size().height())
1554
1555                 self["key_red"] = StaticText(_("Cancel"))
1556                 self["key_green"] = StaticText(_("Save"))
1557
1558                 if (y>=720):
1559                         self["text"] = Input(text, maxSize=False, type=Input.TEXT)
1560                 else:
1561                         self["text"] = Input(text, maxSize=False, visible_width = 55, type=Input.TEXT)
1562
1563                 self["actions"] = NumberActionMap(["WizardActions", "InputActions", "TextEntryActions", "KeyboardInputActions","ShortcutActions"], 
1564                 {
1565                         "ok": self.go,
1566                         "back": self.close,
1567                         "red": self.close,
1568                         "green": self.go,
1569                         "left": self.keyLeft,
1570                         "right": self.keyRight,
1571                         "home": self.keyHome,
1572                         "end": self.keyEnd,
1573                         "deleteForward": self.keyDeleteForward,
1574                         "deleteBackward": self.keyDeleteBackward,
1575                         "1": self.keyNumberGlobal,
1576                         "2": self.keyNumberGlobal,
1577                         "3": self.keyNumberGlobal,
1578                         "4": self.keyNumberGlobal,
1579                         "5": self.keyNumberGlobal,
1580                         "6": self.keyNumberGlobal,
1581                         "7": self.keyNumberGlobal,
1582                         "8": self.keyNumberGlobal,
1583                         "9": self.keyNumberGlobal,
1584                         "0": self.keyNumberGlobal
1585                 }, -1)
1586
1587                 self.onLayoutFinish.append(self.layoutFinished)
1588
1589         def layoutFinished(self):
1590                 self.setWindowTitle()
1591                 self["text"].right()
1592
1593         def setWindowTitle(self):
1594                 self.setTitle(_("Edit upgrade source url."))
1595
1596         def go(self):
1597                 text = self["text"].getText()
1598                 if text:
1599                         fp = file(self.configfile, 'w')
1600                         fp.write(text)
1601                         fp.write("\n")
1602                         fp.close()
1603                 self.close()
1604
1605         def keyLeft(self):
1606                 self["text"].left()
1607         
1608         def keyRight(self):
1609                 self["text"].right()
1610         
1611         def keyHome(self):
1612                 self["text"].home()
1613         
1614         def keyEnd(self):
1615                 self["text"].end()
1616         
1617         def keyDeleteForward(self):
1618                 self["text"].delete()
1619         
1620         def keyDeleteBackward(self):
1621                 self["text"].deleteBackward()
1622         
1623         def keyNumberGlobal(self, number):
1624                 self["text"].number(number)
1625
1626
1627 class PacketManager(Screen, NumericalTextInput):
1628         skin = """
1629                 <screen name="PacketManager" position="center,center" size="530,420" title="Packet manager" >
1630                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1631                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1632                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
1633                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
1634                         <widget source="list" render="Listbox" position="5,50" size="520,365" scrollbarMode="showOnDemand">
1635                                 <convert type="TemplatedMultiContent">
1636                                         {"template": [
1637                                                         MultiContentEntryText(pos = (5, 1), size = (440, 28), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
1638                                                         MultiContentEntryText(pos = (5, 26), size = (440, 20), font=1, flags = RT_HALIGN_LEFT, text = 2), # index 2 is the description
1639                                                         MultiContentEntryPixmapAlphaTest(pos = (445, 2), size = (48, 48), png = 4), # index 4 is the status pixmap
1640                                                         MultiContentEntryPixmapAlphaTest(pos = (5, 50), size = (510, 2), png = 5), # index 4 is the div pixmap
1641                                                 ],
1642                                         "fonts": [gFont("Regular", 22),gFont("Regular", 14)],
1643                                         "itemHeight": 52
1644                                         }
1645                                 </convert>
1646                         </widget>
1647                 </screen>"""
1648                 
1649         def __init__(self, session, plugin_path, args = None):
1650                 Screen.__init__(self, session)
1651                 NumericalTextInput.__init__(self)
1652                 self.session = session
1653                 self.skin_path = plugin_path
1654
1655                 self.setUseableChars(u'1234567890abcdefghijklmnopqrstuvwxyz')
1656
1657                 self["shortcuts"] = NumberActionMap(["ShortcutActions", "WizardActions", "NumberActions", "InputActions", "InputAsciiActions", "KeyboardInputActions" ],
1658                 {
1659                         "ok": self.go,
1660                         "back": self.exit,
1661                         "red": self.exit,
1662                         "green": self.reload,
1663                         "gotAsciiCode": self.keyGotAscii,
1664                         "1": self.keyNumberGlobal,
1665                         "2": self.keyNumberGlobal,
1666                         "3": self.keyNumberGlobal,
1667                         "4": self.keyNumberGlobal,
1668                         "5": self.keyNumberGlobal,
1669                         "6": self.keyNumberGlobal,
1670                         "7": self.keyNumberGlobal,
1671                         "8": self.keyNumberGlobal,
1672                         "9": self.keyNumberGlobal,
1673                         "0": self.keyNumberGlobal
1674                 }, -1)
1675                 
1676                 self.list = []
1677                 self.statuslist = []
1678                 self["list"] = List(self.list)
1679                 self["key_red"] = StaticText(_("Close"))
1680                 self["key_green"] = StaticText(_("Reload"))
1681
1682                 self.list_updating = True
1683                 self.packetlist = []
1684                 self.installed_packetlist = {}
1685                 self.upgradeable_packages = {}
1686                 self.Console = Console()
1687                 self.cmdList = []
1688                 self.cachelist = []
1689                 self.cache_ttl = 86400  #600 is default, 0 disables, Seconds cache is considered valid (24h should be ok for caching ipkgs)
1690                 self.cache_file = eEnv.resolve('${libdir}/enigma2/python/Plugins/SystemPlugins/SoftwareManager/packetmanager.cache') #Path to cache directory
1691                 self.oktext = _("\nAfter pressing OK, please wait!")
1692                 self.unwanted_extensions = ('-dbg', '-dev', '-doc', 'busybox')
1693                 self.opkgAvail = fileExists('/usr/bin/opkg')
1694
1695                 self.ipkg = IpkgComponent()
1696                 self.ipkg.addCallback(self.ipkgCallback)
1697                 self.onShown.append(self.setWindowTitle)
1698                 self.onLayoutFinish.append(self.rebuildList)
1699
1700                 rcinput = eRCInput.getInstance()
1701                 rcinput.setKeyboardMode(rcinput.kmAscii)                
1702
1703         def keyNumberGlobal(self, val):
1704                 key = self.getKey(val)
1705                 if key is not None:
1706                         keyvalue = key.encode("utf-8")
1707                         if len(keyvalue) == 1:
1708                                 self.setNextIdx(keyvalue[0])
1709                 
1710         def keyGotAscii(self):
1711                 keyvalue = unichr(getPrevAsciiCode()).encode("utf-8")
1712                 if len(keyvalue) == 1:
1713                         self.setNextIdx(keyvalue[0])
1714                 
1715         def setNextIdx(self,char):
1716                 if char in ("0", "1", "a"):
1717                         self["list"].setIndex(0)
1718                 else:
1719                         idx = self.getNextIdx(char)
1720                         if idx and idx <= self["list"].count:
1721                                 self["list"].setIndex(idx)
1722
1723         def getNextIdx(self,char):
1724                 idx = 0
1725                 for i in self["list"].list:
1726                         if i[0][0] == char:
1727                                 return idx
1728                         idx += 1
1729
1730         def exit(self):
1731                 self.ipkg.stop()
1732                 if self.Console is not None:
1733                         if len(self.Console.appContainers):
1734                                 for name in self.Console.appContainers.keys():
1735                                         self.Console.kill(name)
1736                 rcinput = eRCInput.getInstance()
1737                 rcinput.setKeyboardMode(rcinput.kmNone)
1738                 self.close()
1739
1740         def reload(self):
1741                 if (os_path.exists(self.cache_file) == True):
1742                         remove(self.cache_file)
1743                         self.list_updating = True
1744                         self.rebuildList()
1745                         
1746         def setWindowTitle(self):
1747                 self.setTitle(_("Packet manager"))
1748
1749         def setStatus(self,status = None):
1750                 if status:
1751                         self.statuslist = []
1752                         divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1753                         if status == 'update':
1754                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
1755                                 self.statuslist.append(( _("Package list update"), '', _("Trying to download a new packetlist. Please wait..." ),'',statuspng, divpng ))
1756                                 self['list'].setList(self.statuslist)   
1757                         elif status == 'error':
1758                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
1759                                 self.statuslist.append(( _("Error"), '', _("There was an error downloading the packetlist. Please try again." ),'',statuspng, divpng ))
1760                                 self['list'].setList(self.statuslist)                           
1761
1762         def rebuildList(self):
1763                 self.setStatus('update')
1764                 self.inv_cache = 0
1765                 self.vc = valid_cache(self.cache_file, self.cache_ttl)
1766                 if self.cache_ttl > 0 and self.vc != 0:
1767                         try:
1768                                 self.buildPacketList()
1769                         except:
1770                                 self.inv_cache = 1
1771                 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
1772                         self.run = 0
1773                         self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
1774
1775         def go(self, returnValue = None):
1776                 cur = self["list"].getCurrent()
1777                 if cur:
1778                         status = cur[3]
1779                         package = cur[0]
1780                         self.cmdList = []
1781                         if status == 'installed':
1782                                 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package }))
1783                                 if len(self.cmdList):
1784                                         self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n") + package + "\n" + self.oktext)
1785                         elif status == 'upgradeable':
1786                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package }))
1787                                 if len(self.cmdList):
1788                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to upgrade the package:\n") + package + "\n" + self.oktext)
1789                         elif status == "installable":
1790                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package }))
1791                                 if len(self.cmdList):
1792                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n") + package + "\n" + self.oktext)
1793
1794         def runRemove(self, result):
1795                 if result:
1796                         self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
1797
1798         def runRemoveFinished(self):
1799                 self.session.openWithCallback(self.RemoveReboot, MessageBox, _("Remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1800
1801         def RemoveReboot(self, result):
1802                 if result is None:
1803                         return
1804                 if result is False:
1805                         cur = self["list"].getCurrent()
1806                         if cur:
1807                                 item = self['list'].getIndex()
1808                                 self.list[item] = self.buildEntryComponent(cur[0], cur[1], cur[2], 'installable')
1809                                 self.cachelist[item] = [cur[0], cur[1], cur[2], 'installable']
1810                                 self['list'].setList(self.list)
1811                                 write_cache(self.cache_file, self.cachelist)
1812                                 self.reloadPluginlist()
1813                 if result:
1814                         quitMainloop(3)
1815
1816         def runUpgrade(self, result):
1817                 if result:
1818                         self.session.openWithCallback(self.runUpgradeFinished, Ipkg, cmdList = self.cmdList)
1819
1820         def runUpgradeFinished(self):
1821                 self.session.openWithCallback(self.UpgradeReboot, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1822                 
1823         def UpgradeReboot(self, result):
1824                 if result is None:
1825                         return
1826                 if result is False:
1827                         cur = self["list"].getCurrent()
1828                         if cur:
1829                                 item = self['list'].getIndex()
1830                                 self.list[item] = self.buildEntryComponent(cur[0], cur[1], cur[2], 'installed')
1831                                 self.cachelist[item] = [cur[0], cur[1], cur[2], 'installed']
1832                                 self['list'].setList(self.list)
1833                                 write_cache(self.cache_file, self.cachelist)
1834                                 self.reloadPluginlist()
1835                 if result:
1836                         quitMainloop(3)
1837
1838         def ipkgCallback(self, event, param):
1839                 if event == IpkgComponent.EVENT_ERROR:
1840                         self.list_updating = False
1841                         self.setStatus('error')
1842                 elif event == IpkgComponent.EVENT_DONE:
1843                         if self.list_updating:
1844                                 self.list_updating = False
1845                                 if not self.Console:
1846                                         self.Console = Console()
1847                                 cmd = "ipkg list"
1848                                 self.Console.ePopen(cmd, self.IpkgList_Finished)
1849                 #print event, "-", param
1850                 pass
1851
1852         def IpkgList_Finished(self, result, retval, extra_args = None):
1853                 if result:
1854                         self.packetlist = []
1855                         last_name = ""
1856                         for x in result.splitlines():
1857                                 tokens = x.split(' - ') 
1858                                 name = tokens[0].strip()
1859                                 if not any(name.endswith(x) for x in self.unwanted_extensions):
1860                                         l = len(tokens)
1861                                         version = l > 1 and tokens[1].strip() or ""
1862                                         descr = l > 2 and tokens[2].strip() or ""
1863                                         if name == last_name:
1864                                                 continue
1865                                         last_name = name 
1866                                         self.packetlist.append([name, version, descr])
1867
1868                 if not self.Console:
1869                         self.Console = Console()
1870                 cmd = "ipkg list_installed"
1871                 self.Console.ePopen(cmd, self.IpkgListInstalled_Finished)
1872
1873         def IpkgListInstalled_Finished(self, result, retval, extra_args = None):
1874                 if result:
1875                         self.installed_packetlist = {}
1876                         for x in result.splitlines():
1877                                 tokens = x.split(' - ')
1878                                 name = tokens[0].strip()
1879                                 if not any(name.endswith(x) for x in self.unwanted_extensions):
1880                                         l = len(tokens)
1881                                         version = l > 1 and tokens[1].strip() or ""
1882                                         self.installed_packetlist[name] = version
1883                 if self.opkgAvail:
1884                         if not self.Console:
1885                                 self.Console = Console()
1886                         cmd = "opkg list-upgradable"
1887                         self.Console.ePopen(cmd, self.OpkgListUpgradeable_Finished)
1888                 else:
1889                         self.buildPacketList()
1890
1891         def OpkgListUpgradeable_Finished(self, result, retval, extra_args = None):
1892                 if result:
1893                         self.upgradeable_packages = {}
1894                         for x in result.splitlines():
1895                                 tokens = x.split(' - ')
1896                                 name = tokens[0].strip()
1897                                 if not any(name.endswith(x) for x in self.unwanted_extensions):
1898                                         l = len(tokens)
1899                                         version = l > 2 and tokens[2].strip() or ""
1900                                         self.upgradeable_packages[name] = version
1901                 self.buildPacketList()
1902         
1903         def buildEntryComponent(self, name, version, description, state):
1904                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1905                 if state == 'installed':
1906                         installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installed.png"))
1907                         return((name, version, _(description), state, installedpng, divpng))    
1908                 elif state == 'upgradeable':
1909                         upgradeablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgradeable.png"))
1910                         return((name, version, _(description), state, upgradeablepng, divpng))  
1911                 else:
1912                         installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installable.png"))
1913                         return((name, version, _(description), state, installablepng, divpng))
1914
1915         def buildPacketList(self):
1916                 self.list = []
1917                 self.cachelist = []
1918                 if self.cache_ttl > 0 and self.vc != 0:
1919                         print 'Loading packagelist cache from ',self.cache_file
1920                         try:
1921                                 self.cachelist = load_cache(self.cache_file)
1922                                 if len(self.cachelist) > 0:
1923                                         for x in self.cachelist:
1924                                                 self.list.append(self.buildEntryComponent(x[0], x[1], x[2], x[3]))
1925                                         self['list'].setList(self.list)
1926                         except:
1927                                 self.inv_cache = 1
1928
1929                 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
1930                         print 'rebuilding fresh package list'
1931                         for x in self.packetlist:
1932                                 status = ""
1933                                 if self.installed_packetlist.has_key(x[0]):
1934                                         if self.opkgAvail:
1935                                                 if self.upgradeable_packages.has_key(x[0]):
1936                                                         status = "upgradeable"
1937                                                 else:
1938                                                         status = "installed"
1939                                         else:
1940                                                 if self.installed_packetlist[x[0]] == x[1]:
1941                                                         status = "installed"
1942                                                 else:
1943                                                         status = "upgradeable"
1944                                 else:
1945                                         status = "installable"
1946                                 self.list.append(self.buildEntryComponent(x[0], x[1], x[2], status))    
1947                                 self.cachelist.append([x[0], x[1], x[2], status])
1948                         write_cache(self.cache_file, self.cachelist)
1949                         self['list'].setList(self.list)
1950
1951         def reloadPluginlist(self):
1952                 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
1953
1954
1955 class IpkgInstaller(Screen):
1956         skin = """
1957                 <screen name="IpkgInstaller" position="center,center" size="550,450" title="Install extensions" >
1958                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1959                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1960                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
1961                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
1962                         <widget name="list" position="5,50" size="540,360" />
1963                         <ePixmap pixmap="skin_default/div-h.png" position="0,410" zPosition="10" size="560,2" transparent="1" alphatest="on" />
1964                         <widget source="introduction" render="Label" position="5,420" zPosition="10" size="550,30" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
1965                 </screen>"""
1966         
1967         def __init__(self, session, list):
1968                 Screen.__init__(self, session)
1969
1970                 self.list = SelectionList()
1971                 self["list"] = self.list
1972                 for listindex in range(len(list)):
1973                         self.list.addSelection(list[listindex], list[listindex], listindex, True)
1974
1975                 self["key_red"] = StaticText(_("Close"))
1976                 self["key_green"] = StaticText(_("Install"))
1977                 self["introduction"] = StaticText(_("Press OK to toggle the selection."))
1978                 
1979                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions"], 
1980                 {
1981                         "ok": self.list.toggleSelection, 
1982                         "cancel": self.close,
1983                         "red": self.close,
1984                         "green": self.install
1985                 }, -1)
1986
1987         def install(self):
1988                 list = self.list.getSelectionsList()
1989                 cmdList = []
1990                 for item in list:
1991                         cmdList.append((IpkgComponent.CMD_INSTALL, { "package": item[1] }))
1992                 self.session.open(Ipkg, cmdList = cmdList)
1993
1994
1995 def filescan_open(list, session, **kwargs):
1996         filelist = [x.path for x in list]
1997         session.open(IpkgInstaller, filelist) # list
1998
1999 def filescan(**kwargs):
2000         from Components.Scanner import Scanner, ScanPath
2001         return \
2002                 Scanner(mimetypes = ["application/x-debian-package"], 
2003                         paths_to_scan = 
2004                                 [
2005                                         ScanPath(path = "ipk", with_subdirs = True), 
2006                                         ScanPath(path = "", with_subdirs = False), 
2007                                 ], 
2008                         name = "Ipkg", 
2009                         description = _("Install extensions."),
2010                         openfnc = filescan_open, )
2011
2012
2013
2014 def UpgradeMain(session, **kwargs):
2015         session.open(UpdatePluginMenu)
2016
2017 def startSetup(menuid):
2018         if menuid != "setup": 
2019                 return [ ]
2020         return [(_("Software management"), UpgradeMain, "software_manager", 50)]
2021
2022
2023 def Plugins(path, **kwargs):
2024         global plugin_path
2025         plugin_path = path
2026         list = [
2027                 PluginDescriptor(name=_("Software management"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_MENU, fnc=startSetup),
2028                 PluginDescriptor(name=_("Ipkg"), where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)
2029         ]
2030         if config.usage.setup_level.index >= 2: # expert+
2031                 list.append(PluginDescriptor(name=_("Software management"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=UpgradeMain))
2032         return list