Components/DreamInfoHandler.py, SystemPlugins/SoftwareManager: add possibility to...
[enigma2.git] / 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/wpa_supplicant.ath0.conf', '/etc/wpa_supplicant.wlan0.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                                 self.list.append((entry,))
493                         self['list'].setList(self.list)
494                         
495
496 class PluginManager(Screen, DreamInfoHandler):
497
498         skin = """
499                 <screen name="PluginManager" position="center,center" size="560,440" title="Extensions management" >
500                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
501                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
502                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
503                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
504                         <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" />
505                         <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" />
506                         <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" />
507                         <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" />
508                         <widget source="list" render="Listbox" position="5,50" size="550,360" scrollbarMode="showOnDemand">
509                                 <convert type="TemplatedMultiContent">
510                                 {"templates":
511                                         {"default": (51,[
512                                                         MultiContentEntryText(pos = (0, 1), size = (470, 24), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
513                                                         MultiContentEntryText(pos = (0, 25), size = (470, 24), font=1, flags = RT_HALIGN_LEFT, text = 2), # index 2 is the description
514                                                         MultiContentEntryPixmapAlphaTest(pos = (475, 0), size = (48, 48), png = 5), # index 5 is the status pixmap
515                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 49), size = (550, 2), png = 6), # index 6 is the div pixmap
516                                                 ]),
517                                         "category": (40,[
518                                                         MultiContentEntryText(pos = (30, 0), size = (500, 22), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
519                                                         MultiContentEntryText(pos = (30, 22), size = (500, 16), font=2, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the description
520                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 38), size = (550, 2), png = 3), # index 3 is the div pixmap
521                                                 ])
522                                         },
523                                         "fonts": [gFont("Regular", 22),gFont("Regular", 20),gFont("Regular", 16)],
524                                         "itemHeight": 52
525                                 }
526                                 </convert>
527                         </widget>
528                         <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" />
529                 </screen>"""
530
531         def __init__(self, session, plugin_path = None, args = None):
532                 Screen.__init__(self, session)
533                 self.session = session
534                 self.skin_path = plugin_path
535                 if self.skin_path == None:
536                         self.skin_path = resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager")
537
538                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions", "InfobarEPGActions", "HelpActions" ],
539                 {
540                         "ok": self.handleCurrent,
541                         "back": self.exit,
542                         "red": self.exit,
543                         "green": self.handleCurrent,
544                         "yellow": self.handleSelected,
545                         "showEventInfo": self.handleSelected,
546                         "displayHelp": self.handleHelp,
547                 }, -1)
548
549                 self.list = []
550                 self.statuslist = []
551                 self.selectedFiles = []
552                 self.categoryList = []
553                 self.packetlist = []
554                 self["list"] = List(self.list)
555                 self["key_red"] = StaticText(_("Close"))
556                 self["key_green"] = StaticText("")
557                 self["key_yellow"] = StaticText("")
558                 self["key_blue"] = StaticText("")
559                 self["status"] = StaticText("")
560
561                 self.cmdList = []
562                 self.oktext = _("\nAfter pressing OK, please wait!")
563                 if not self.selectionChanged in self["list"].onSelectionChanged:
564                         self["list"].onSelectionChanged.append(self.selectionChanged)
565
566                 self.currList = ""
567                 self.currentSelectedTag = None
568                 self.currentSelectedIndex = None
569                 self.currentSelectedPackage = None
570                 self.saved_currentSelectedPackage = None
571                 self.restartRequired = False
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                                 if description == "":
813                                         description = "No description available."
814                                 packagename = x[3].strip()
815                                 selectState = self.getSelectionState(details)
816                                 if iSoftwareTools.installed_packetlist.has_key(packagename):
817                                         if selectState == True:
818                                                 status = "remove"
819                                         else:
820                                                 status = "installed"
821                                         self.list.append(self.buildEntryComponent(name, _(details), _(description), packagename, status, selected = selectState))
822                                 else:
823                                         if selectState == True:
824                                                 status = "install"
825                                         else:
826                                                 status = "installable"
827                                         self.list.append(self.buildEntryComponent(name, _(details), _(description), packagename, status, selected = selectState))
828                         if len(self.list):
829                                 self.list.sort(key=lambda x: x[0])
830                         self["list"].style = "default"
831                         self['list'].setList(self.list)
832                         self["list"].updateList(self.list)
833                         self.selectionChanged()
834
835         def buildCategoryList(self):
836                 self.currList = "category"
837                 self.categories = []
838                 self.categoryList = []
839                 for package in iSoftwareTools.packagesIndexlist[:]:
840                         prerequisites = package[0]["prerequisites"]
841                         if prerequisites.has_key("tag"):
842                                 for foundtag in prerequisites["tag"]:
843                                         attributes = package[0]["attributes"]
844                                         if foundtag not in self.categories:
845                                                 self.categories.append(foundtag)
846                                                 self.categoryList.append(self.buildCategoryComponent(foundtag))
847                 self.categoryList.sort(key=lambda x: x[0])
848                 self["list"].style = "category"
849                 self['list'].setList(self.categoryList)
850                 self["list"].updateList(self.categoryList)
851                 self.selectionChanged()
852
853         def buildCategoryComponent(self, tag = None):
854                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
855                 if tag is not None:
856                         if tag == 'System':
857                                 return(( _("System"), _("View list of available system extensions" ), tag, divpng ))
858                         elif tag == 'Skin':
859                                 return(( _("Skins"), _("View list of available skins" ), tag, divpng ))
860                         elif tag == 'Recording':
861                                 return(( _("Recordings"), _("View list of available recording extensions" ), tag, divpng ))
862                         elif tag == 'Network':
863                                 return(( _("Network"), _("View list of available networking extensions" ), tag, divpng ))
864                         elif tag == 'CI':
865                                 return(( _("CommonInterface"), _("View list of available CommonInterface extensions" ), tag, divpng ))
866                         elif tag == 'Default':
867                                 return(( _("Default Settings"), _("View list of available default settings" ), tag, divpng ))
868                         elif tag == 'SAT':
869                                 return(( _("Satellite equipment"), _("View list of available Satellite equipment extensions." ), tag, divpng ))
870                         elif tag == 'Software':
871                                 return(( _("Software"), _("View list of available software extensions" ), tag, divpng ))
872                         elif tag == 'Multimedia':
873                                 return(( _("Multimedia"), _("View list of available multimedia extensions." ), tag, divpng ))
874                         elif tag == 'Display':
875                                 return(( _("Display and Userinterface"), _("View list of available Display and Userinterface extensions." ), tag, divpng ))
876                         elif tag == 'EPG':
877                                 return(( _("Electronic Program Guide"), _("View list of available EPG extensions." ), tag, divpng ))
878                         elif tag == 'Communication':
879                                 return(( _("Communication"), _("View list of available communication extensions." ), tag, divpng ))
880                         else: # dynamically generate non existent tags
881                                 return(( str(tag), _("View list of available ") + str(tag) + _(" extensions." ), tag, divpng ))
882
883         def prepareInstall(self):
884                 self.cmdList = []
885                 if iSoftwareTools.available_updates > 0:
886                         self.cmdList.append((IpkgComponent.CMD_UPGRADE, { "test_only": False }))
887                 if self.selectedFiles and len(self.selectedFiles):
888                         for plugin in self.selectedFiles:
889                                 detailsfile = iSoftwareTools.directory[0] + "/" + plugin[0]
890                                 if (os_path.exists(detailsfile) == True):
891                                         iSoftwareTools.fillPackageDetails(plugin[0])
892                                         self.package = iSoftwareTools.packageDetails[0]
893                                         if self.package[0].has_key("attributes"):
894                                                 self.attributes = self.package[0]["attributes"]
895                                                 if self.attributes.has_key("needsRestart"):
896                                                         self.restartRequired = True
897                                         if self.attributes.has_key("package"):
898                                                 self.packagefiles = self.attributes["package"]
899                                         if plugin[1] == 'installed':
900                                                 if self.packagefiles:
901                                                         for package in self.packagefiles[:]:
902                                                                 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package["name"] }))
903                                                 else:
904                                                         self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": plugin[2] }))
905                                         else:
906                                                 if self.packagefiles:
907                                                         for package in self.packagefiles[:]:
908                                                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package["name"] }))
909                                                 else:
910                                                         self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": plugin[2] }))
911                                 else:
912                                         if plugin[1] == 'installed':
913                                                 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": plugin[2] }))
914                                         else:
915                                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": plugin[2] }))
916
917         def runExecute(self, result = None):
918                 if result is not None:
919                         if result[0] is True:
920                                 self.session.openWithCallback(self.runExecuteFinished, Ipkg, cmdList = self.cmdList)
921                         elif result[0] is False:
922                                 self.cmdList = result[1]
923                                 self.session.openWithCallback(self.runExecuteFinished, Ipkg, cmdList = self.cmdList)
924                 else:
925                         self.close()
926
927         def runExecuteFinished(self):
928                 self.reloadPluginlist()
929                 if plugins.restartRequired or self.restartRequired:
930                         self.session.openWithCallback(self.ExecuteReboot, MessageBox, _("Install or remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
931                 else:
932                         self.selectedFiles = []
933                         self.restartRequired = False
934                         self.detailsClosed(True)
935
936         def ExecuteReboot(self, result):
937                 if result:
938                         quitMainloop(3)
939                 else:
940                         self.selectedFiles = []
941                         self.restartRequired = False
942                         self.detailsClosed(True)
943
944         def reloadPluginlist(self):
945                 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
946
947
948 class PluginManagerInfo(Screen):
949         skin = """
950                 <screen name="PluginManagerInfo" position="center,center" size="560,450" title="Plugin manager activity information" >
951                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
952                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
953                         <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" />
954                         <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" />
955                         <widget source="list" render="Listbox" position="5,50" size="550,350" scrollbarMode="showOnDemand" selectionDisabled="1">
956                                 <convert type="TemplatedMultiContent">
957                                         {"template": [
958                                                         MultiContentEntryText(pos = (50, 0), size = (150, 26), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
959                                                         MultiContentEntryText(pos = (50, 27), size = (540, 23), font=1, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the state
960                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 1), size = (48, 48), png = 2), # index 2 is the status pixmap
961                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 48), size = (550, 2), png = 3), # index 3 is the div pixmap
962                                                 ],
963                                         "fonts": [gFont("Regular", 24),gFont("Regular", 22)],
964                                         "itemHeight": 50
965                                         }
966                                 </convert>
967                         </widget>
968                         <ePixmap pixmap="skin_default/div-h.png" position="0,404" zPosition="10" size="560,2" transparent="1" alphatest="on" />
969                         <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" />
970                 </screen>"""
971
972         def __init__(self, session, plugin_path, cmdlist = None):
973                 Screen.__init__(self, session)
974                 self.session = session
975                 self.skin_path = plugin_path
976                 self.cmdlist = cmdlist
977
978                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
979                 {
980                         "ok": self.process_all,
981                         "back": self.exit,
982                         "red": self.exit,
983                         "green": self.process_extensions,
984                 }, -1)
985
986                 self.list = []
987                 self["list"] = List(self.list)
988                 self["key_red"] = StaticText(_("Cancel"))
989                 self["key_green"] = StaticText(_("Only extensions."))
990                 self["status"] = StaticText(_("Following tasks will be done after you press OK!"))
991
992                 self.onShown.append(self.setWindowTitle)
993                 self.onLayoutFinish.append(self.rebuildList)
994
995         def setWindowTitle(self):
996                 self.setTitle(_("Plugin manager activity information"))
997
998         def rebuildList(self):
999                 self.list = []
1000                 if self.cmdlist is not None:
1001                         for entry in self.cmdlist:
1002                                 action = ""
1003                                 info = ""
1004                                 cmd = entry[0]
1005                                 if cmd == 0:
1006                                         action = 'install'
1007                                 elif cmd == 2:
1008                                         action = 'remove'
1009                                 else:
1010                                         action = 'upgrade'
1011                                 args = entry[1]
1012                                 if cmd == 0:
1013                                         info = args['package']
1014                                 elif cmd == 2:
1015                                         info = args['package']
1016                                 else:
1017                                         info = _("Dreambox software because updates are available.")
1018
1019                                 self.list.append(self.buildEntryComponent(action,info))
1020                         self['list'].setList(self.list)
1021                         self['list'].updateList(self.list)
1022
1023         def buildEntryComponent(self, action,info):
1024                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1025                 upgradepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
1026                 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/install.png"))
1027                 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
1028                 if action == 'install':
1029                         return(( _('Installing'), info, installpng, divpng))
1030                 elif action == 'remove':
1031                         return(( _('Removing'), info, removepng, divpng))
1032                 else:
1033                         return(( _('Upgrading'), info, upgradepng, divpng))
1034
1035         def exit(self):
1036                 self.close()
1037
1038         def process_all(self):
1039                 self.close((True,None))
1040
1041         def process_extensions(self):
1042                 self.list = []
1043                 if self.cmdlist is not None:
1044                         for entry in self.cmdlist:
1045                                 cmd = entry[0]
1046                                 if entry[0] in (0,2):
1047                                         self.list.append((entry))
1048                 self.close((False,self.list))
1049
1050
1051 class PluginManagerHelp(Screen):
1052         skin = """
1053                 <screen name="PluginManagerHelp" position="center,center" size="560,450" title="Plugin manager help" >
1054                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1055                         <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" />
1056                         <widget source="list" render="Listbox" position="5,50" size="550,350" scrollbarMode="showOnDemand" selectionDisabled="1">
1057                                 <convert type="TemplatedMultiContent">
1058                                         {"template": [
1059                                                         MultiContentEntryText(pos = (50, 0), size = (540, 26), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
1060                                                         MultiContentEntryText(pos = (50, 27), size = (540, 23), font=1, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the state
1061                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 1), size = (48, 48), png = 2), # index 2 is the status pixmap
1062                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 48), size = (550, 2), png = 3), # index 3 is the div pixmap
1063                                                 ],
1064                                         "fonts": [gFont("Regular", 24),gFont("Regular", 22)],
1065                                         "itemHeight": 50
1066                                         }
1067                                 </convert>
1068                         </widget>
1069                         <ePixmap pixmap="skin_default/div-h.png" position="0,404" zPosition="10" size="560,2" transparent="1" alphatest="on" />
1070                         <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" />
1071                 </screen>"""
1072
1073         def __init__(self, session, plugin_path):
1074                 Screen.__init__(self, session)
1075                 self.session = session
1076                 self.skin_path = plugin_path
1077
1078                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
1079                 {
1080                         "back": self.exit,
1081                         "red": self.exit,
1082                 }, -1)
1083
1084                 self.list = []
1085                 self["list"] = List(self.list)
1086                 self["key_red"] = StaticText(_("Close"))
1087                 self["status"] = StaticText(_("A small overview of the available icon states and actions."))
1088
1089                 self.onShown.append(self.setWindowTitle)
1090                 self.onLayoutFinish.append(self.rebuildList)
1091
1092         def setWindowTitle(self):
1093                 self.setTitle(_("Plugin manager help"))
1094
1095         def rebuildList(self):
1096                 self.list = []
1097                 self.list.append(self.buildEntryComponent('install'))
1098                 self.list.append(self.buildEntryComponent('installable'))
1099                 self.list.append(self.buildEntryComponent('installed'))
1100                 self.list.append(self.buildEntryComponent('remove'))
1101                 self['list'].setList(self.list)
1102                 self['list'].updateList(self.list)
1103
1104         def buildEntryComponent(self, state):
1105                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1106                 installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installed.png"))
1107                 installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installable.png"))
1108                 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
1109                 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/install.png"))
1110
1111                 if state == 'installed':
1112                         return(( _('This plugin is installed.'), _('You can remove this plugin.'), installedpng, divpng))
1113                 elif state == 'installable':
1114                         return(( _('This plugin is not installed.'), _('You can install this plugin.'), installablepng, divpng))
1115                 elif state == 'install':
1116                         return(( _('This plugin will be installed.'), _('You can cancel the installation.'), installpng, divpng))
1117                 elif state == 'remove':
1118                         return(( _('This plugin will be removed.'), _('You can cancel the removal.'), removepng, divpng))
1119
1120         def exit(self):
1121                 self.close()
1122
1123
1124 class PluginDetails(Screen, DreamInfoHandler):
1125         skin = """
1126                 <screen name="PluginDetails" position="center,center" size="600,440" title="Plugin details" >
1127                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1128                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1129                         <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" />
1130                         <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" />
1131                         <widget source="author" render="Label" position="10,50" size="500,25" zPosition="10" font="Regular;21" transparent="1" />
1132                         <widget name="statuspic" position="550,40" size="48,48" alphatest="on"/>
1133                         <widget name="divpic" position="0,80" size="600,2" alphatest="on"/>
1134                         <widget name="detailtext" position="10,90" size="270,330" zPosition="10" font="Regular;21" transparent="1" halign="left" valign="top"/>
1135                         <widget name="screenshot" position="290,90" size="300,330" alphatest="on"/>
1136                 </screen>"""
1137         def __init__(self, session, plugin_path, packagedata = None):
1138                 Screen.__init__(self, session)
1139                 self.skin_path = plugin_path
1140                 self.language = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
1141                 self.attributes = None
1142                 DreamInfoHandler.__init__(self, self.statusCallback, blocking = False)
1143                 self.directory = resolveFilename(SCOPE_METADIR)
1144                 if packagedata:
1145                         self.pluginname = packagedata[0]
1146                         self.details = packagedata[1]
1147                         self.pluginstate = packagedata[4]
1148                         self.statuspicinstance = packagedata[5]
1149                         self.divpicinstance = packagedata[6]
1150                         self.fillPackageDetails(self.details)
1151
1152                 self.thumbnail = ""
1153
1154                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
1155                 {
1156                         "back": self.exit,
1157                         "red": self.exit,
1158                         "green": self.go,
1159                         "up": self.pageUp,
1160                         "down": self.pageDown,
1161                         "left": self.pageUp,
1162                         "right": self.pageDown,
1163                 }, -1)
1164
1165                 self["key_red"] = StaticText(_("Close"))
1166                 self["key_green"] = StaticText("")
1167                 self["author"] = StaticText()
1168                 self["statuspic"] = Pixmap()
1169                 self["divpic"] = Pixmap()
1170                 self["screenshot"] = Pixmap()
1171                 self["detailtext"] = ScrollLabel()
1172
1173                 self["statuspic"].hide()
1174                 self["screenshot"].hide()
1175                 self["divpic"].hide()
1176
1177                 self.package = self.packageDetails[0]
1178                 if self.package[0].has_key("attributes"):
1179                         self.attributes = self.package[0]["attributes"]
1180                 self.restartRequired = False
1181                 self.cmdList = []
1182                 self.oktext = _("\nAfter pressing OK, please wait!")
1183                 self.picload = ePicLoad()
1184                 self.picload.PictureData.get().append(self.paintScreenshotPixmapCB)
1185                 self.onShown.append(self.setWindowTitle)
1186                 self.onLayoutFinish.append(self.setInfos)
1187
1188         def setWindowTitle(self):
1189                 self.setTitle(_("Details for plugin: ") + self.pluginname )
1190
1191         def exit(self):
1192                 self.close(False)
1193
1194         def pageUp(self):
1195                 self["detailtext"].pageUp()
1196
1197         def pageDown(self):
1198                 self["detailtext"].pageDown()
1199
1200         def statusCallback(self, status, progress):
1201                 pass
1202
1203         def setInfos(self):
1204                 if self.attributes.has_key("screenshot"):
1205                         self.loadThumbnail(self.attributes)
1206
1207                 if self.attributes.has_key("name"):
1208                         self.pluginname = self.attributes["name"]
1209                 else:
1210                         self.pluginname = _("unknown")
1211
1212                 if self.attributes.has_key("author"):
1213                         self.author = self.attributes["author"]
1214                 else:
1215                         self.author = _("unknown")
1216
1217                 if self.attributes.has_key("description"):
1218                         self.description = _(self.attributes["description"].replace("\\n", "\n"))
1219                 else:
1220                         self.description = _("No description available.")
1221
1222                 self["author"].setText(_("Author: ") + self.author)
1223                 self["detailtext"].setText(_(self.description))
1224                 if self.pluginstate in ('installable', 'install'):
1225                         if iSoftwareTools.NetworkConnectionAvailable:
1226                                 self["key_green"].setText(_("Install"))
1227                         else:
1228                                 self["key_green"].setText("")
1229                 else:
1230                         self["key_green"].setText(_("Remove"))
1231
1232         def loadThumbnail(self, entry):
1233                 thumbnailUrl = None
1234                 if entry.has_key("screenshot"):
1235                         thumbnailUrl = entry["screenshot"]
1236                         if self.language == "de":
1237                                 if thumbnailUrl[-7:] == "_en.jpg":
1238                                         thumbnailUrl = thumbnailUrl[:-7] + "_de.jpg"
1239
1240                 if thumbnailUrl is not None:
1241                         self.thumbnail = "/tmp/" + thumbnailUrl.split('/')[-1]
1242                         print "[PluginDetails] downloading screenshot " + thumbnailUrl + " to " + self.thumbnail
1243                         if iSoftwareTools.NetworkConnectionAvailable:
1244                                 client.downloadPage(thumbnailUrl,self.thumbnail).addCallback(self.setThumbnail).addErrback(self.fetchFailed)
1245                         else:
1246                                 self.setThumbnail(noScreenshot = True)
1247                 else:
1248                         self.setThumbnail(noScreenshot = True)
1249
1250         def setThumbnail(self, noScreenshot = False):
1251                 if not noScreenshot:
1252                         filename = self.thumbnail
1253                 else:
1254                         filename = resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/noprev.png")
1255
1256                 sc = AVSwitch().getFramebufferScale()
1257                 self.picload.setPara((self["screenshot"].instance.size().width(), self["screenshot"].instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
1258                 self.picload.startDecode(filename)
1259
1260                 if self.statuspicinstance != None:
1261                         self["statuspic"].instance.setPixmap(self.statuspicinstance.__deref__())
1262                         self["statuspic"].show()
1263                 if self.divpicinstance != None:
1264                         self["divpic"].instance.setPixmap(self.divpicinstance.__deref__())
1265                         self["divpic"].show()
1266
1267         def paintScreenshotPixmapCB(self, picInfo=None):
1268                 ptr = self.picload.getData()
1269                 if ptr != None:
1270                         self["screenshot"].instance.setPixmap(ptr.__deref__())
1271                         self["screenshot"].show()
1272                 else:
1273                         self.setThumbnail(noScreenshot = True)
1274
1275         def go(self):
1276                 if self.attributes.has_key("package"):
1277                         self.packagefiles = self.attributes["package"]
1278                 if self.attributes.has_key("needsRestart"):
1279                         self.restartRequired = True
1280                 self.cmdList = []
1281                 if self.pluginstate in ('installed', 'remove'):
1282                         if self.packagefiles:
1283                                 for package in self.packagefiles[:]:
1284                                         self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package["name"] }))
1285                                         if len(self.cmdList):
1286                                                 self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n") + self.pluginname + "\n" + self.oktext)
1287                 else:
1288                         if iSoftwareTools.NetworkConnectionAvailable:
1289                                 if self.packagefiles:
1290                                         for package in self.packagefiles[:]:
1291                                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package["name"] }))
1292                                                 if len(self.cmdList):
1293                                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n") + self.pluginname + "\n" + self.oktext)
1294
1295         def runUpgrade(self, result):
1296                 if result:
1297                         self.session.openWithCallback(self.runUpgradeFinished, Ipkg, cmdList = self.cmdList)
1298
1299         def runUpgradeFinished(self):
1300                 self.reloadPluginlist()
1301                 if plugins.restartRequired or self.restartRequired:
1302                         self.session.openWithCallback(self.UpgradeReboot, MessageBox, _("Installation finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1303                 else:
1304                         self.close(True)
1305         def UpgradeReboot(self, result):
1306                 if result:
1307                         quitMainloop(3)
1308                 else:
1309                         self.close(True)
1310
1311         def runRemove(self, result):
1312                 if result:
1313                         self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
1314
1315         def runRemoveFinished(self):
1316                 self.close(True)
1317
1318         def reloadPluginlist(self):
1319                 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
1320
1321         def fetchFailed(self,string):
1322                 self.setThumbnail(noScreenshot = True)
1323                 print "[PluginDetails] fetch failed " + string.getErrorMessage()
1324
1325
1326 class UpdatePlugin(Screen):
1327         skin = """
1328                 <screen name="UpdatePlugin" position="center,center" size="550,300" title="Software update" >
1329                         <widget name="activityslider" position="0,0" size="550,5"  />
1330                         <widget name="slider" position="0,150" size="550,30"  />
1331                         <widget source="package" render="Label" position="10,30" size="540,20" font="Regular;18" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
1332                         <widget source="status" render="Label" position="10,180" size="540,100" font="Regular;20" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
1333                 </screen>"""
1334
1335         def __init__(self, session, args = None):
1336                 Screen.__init__(self, session)
1337
1338                 self.sliderPackages = { "dreambox-dvb-modules": 1, "enigma2": 2, "tuxbox-image-info": 3 }
1339
1340                 self.slider = Slider(0, 4)
1341                 self["slider"] = self.slider
1342                 self.activityslider = Slider(0, 100)
1343                 self["activityslider"] = self.activityslider
1344                 self.status = StaticText(_("Please wait..."))
1345                 self["status"] = self.status
1346                 self.package = StaticText(_("Verifying your internet connection..."))
1347                 self["package"] = self.package
1348                 self.oktext = _("Press OK on your remote control to continue.")
1349
1350                 self.packages = 0
1351                 self.error = 0
1352                 self.processed_packages = []
1353
1354                 self.activity = 0
1355                 self.activityTimer = eTimer()
1356                 self.activityTimer.callback.append(self.doActivityTimer)
1357
1358                 self.ipkg = IpkgComponent()
1359                 self.ipkg.addCallback(self.ipkgCallback)
1360
1361                 self.updating = False
1362
1363                 self["actions"] = ActionMap(["WizardActions"], 
1364                 {
1365                         "ok": self.exit,
1366                         "back": self.exit
1367                 }, -1)
1368                 
1369                 iNetwork.checkNetworkState(self.checkNetworkCB)
1370                 self.onClose.append(self.cleanup)
1371                 
1372         def cleanup(self):
1373                 iNetwork.stopPingConsole()
1374
1375         def checkNetworkCB(self,data):
1376                 if data is not None:
1377                         if data <= 2:
1378                                 self.updating = True
1379                                 self.activityTimer.start(100, False)
1380                                 self.package.setText(_("Package list update"))
1381                                 self.status.setText(_("Upgrading Dreambox... Please wait"))
1382                                 self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
1383                         else:
1384                                 self.package.setText(_("Your network is not working. Please try again."))
1385                                 self.status.setText(self.oktext)
1386
1387         def doActivityTimer(self):
1388                 self.activity += 1
1389                 if self.activity == 100:
1390                         self.activity = 0
1391                 self.activityslider.setValue(self.activity)
1392
1393         def ipkgCallback(self, event, param):
1394                 if event == IpkgComponent.EVENT_DOWNLOAD:
1395                         self.status.setText(_("Downloading"))
1396                 elif event == IpkgComponent.EVENT_UPGRADE:
1397                         if self.sliderPackages.has_key(param):
1398                                 self.slider.setValue(self.sliderPackages[param])
1399                         self.package.setText(param)
1400                         self.status.setText(_("Upgrading"))
1401                         if not param in self.processed_packages:
1402                                 self.processed_packages.append(param)
1403                                 self.packages += 1
1404                 elif event == IpkgComponent.EVENT_INSTALL:
1405                         self.package.setText(param)
1406                         self.status.setText(_("Installing"))
1407                         if not param in self.processed_packages:
1408                                 self.processed_packages.append(param)
1409                                 self.packages += 1
1410                 elif event == IpkgComponent.EVENT_REMOVE:
1411                         self.package.setText(param)
1412                         self.status.setText(_("Removing"))
1413                         if not param in self.processed_packages:
1414                                 self.processed_packages.append(param)
1415                                 self.packages += 1
1416                 elif event == IpkgComponent.EVENT_CONFIGURING:
1417                         self.package.setText(param)
1418                         self.status.setText(_("Configuring"))
1419                         
1420                 elif event == IpkgComponent.EVENT_MODIFIED:
1421                         if config.plugins.softwaremanager.overwriteConfigFiles.value in ("N", "Y"):
1422                                 self.ipkg.write(True and config.plugins.softwaremanager.overwriteConfigFiles.value)
1423                         else:
1424                                 self.session.openWithCallback(
1425                                         self.modificationCallback,
1426                                         MessageBox,
1427                                         _("A configuration file (%s) was modified since Installation.\nDo you want to keep your version?") % (param)
1428                                 )
1429                 elif event == IpkgComponent.EVENT_ERROR:
1430                         self.error += 1
1431                 elif event == IpkgComponent.EVENT_DONE:
1432                         if self.updating:
1433                                 self.updating = False
1434                                 self.ipkg.startCmd(IpkgComponent.CMD_UPGRADE, args = {'test_only': False})
1435                         elif self.error == 0:
1436                                 self.slider.setValue(4)
1437                                 
1438                                 self.activityTimer.stop()
1439                                 self.activityslider.setValue(0)
1440                                 
1441                                 self.package.setText(_("Done - Installed or upgraded %d packages") % self.packages)
1442                                 self.status.setText(self.oktext)
1443                         else:
1444                                 self.activityTimer.stop()
1445                                 self.activityslider.setValue(0)
1446                                 error = _("your dreambox might be unusable now. Please consult the manual for further assistance before rebooting your dreambox.")
1447                                 if self.packages == 0:
1448                                         error = _("No packages were upgraded yet. So you can check your network and try again.")
1449                                 if self.updating:
1450                                         error = _("Your dreambox isn't connected to the internet properly. Please check it and try again.")
1451                                 self.status.setText(_("Error") +  " - " + error)
1452                 #print event, "-", param
1453                 pass
1454
1455         def modificationCallback(self, res):
1456                 self.ipkg.write(res and "N" or "Y")
1457
1458         def exit(self):
1459                 if not self.ipkg.isRunning():
1460                         if self.packages != 0 and self.error == 0:
1461                                 self.session.openWithCallback(self.exitAnswer, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"))
1462                         else:
1463                                 self.close()
1464                 else:
1465                         if not self.updating:
1466                                 self.close()
1467
1468         def exitAnswer(self, result):
1469                 if result is not None and result:
1470                         quitMainloop(2)
1471                 self.close()
1472
1473
1474
1475 class IPKGMenu(Screen):
1476         skin = """
1477                 <screen name="IPKGMenu" position="center,center" size="560,400" title="Select upgrade source to edit." >
1478                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1479                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1480                         <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" />
1481                         <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" />
1482                         <widget name="filelist" position="5,50" size="550,340" scrollbarMode="showOnDemand" />
1483                 </screen>"""
1484
1485         def __init__(self, session, plugin_path):
1486                 Screen.__init__(self, session)
1487                 self.skin_path = plugin_path
1488                 
1489                 self["key_red"] = StaticText(_("Close"))
1490                 self["key_green"] = StaticText(_("Edit"))
1491
1492                 self.sel = []
1493                 self.val = []
1494                 self.entry = False
1495                 self.exe = False
1496                 
1497                 self.path = ""
1498
1499                 self["actions"] = NumberActionMap(["SetupActions"],
1500                 {
1501                         "ok": self.KeyOk,
1502                         "cancel": self.keyCancel
1503                 }, -1)
1504
1505                 self["shortcuts"] = ActionMap(["ShortcutActions"],
1506                 {
1507                         "red": self.keyCancel,
1508                         "green": self.KeyOk,
1509                 })
1510                 self.flist = []
1511                 self["filelist"] = MenuList(self.flist)
1512                 self.fill_list()
1513                 self.onLayoutFinish.append(self.layoutFinished)
1514
1515         def layoutFinished(self):
1516                 self.setWindowTitle()
1517
1518         def setWindowTitle(self):
1519                 self.setTitle(_("Select upgrade source to edit."))
1520
1521         def fill_list(self):
1522                 self.flist = []
1523                 self.path = '/etc/opkg/'
1524                 if (os_path.exists(self.path) == False):
1525                         self.entry = False
1526                         return
1527                 for file in listdir(self.path):
1528                         if (file.endswith(".conf")):
1529                                 if file != 'arch.conf':
1530                                         self.flist.append((file))
1531                                         self.entry = True
1532                                         self["filelist"].l.setList(self.flist)
1533
1534         def KeyOk(self):
1535                 if (self.exe == False) and (self.entry == True):
1536                         self.sel = self["filelist"].getCurrent()
1537                         self.val = self.path + self.sel
1538                         self.session.open(IPKGSource, self.val)
1539
1540         def keyCancel(self):
1541                 self.close()
1542
1543         def Exit(self):
1544                 self.close()
1545
1546
1547 class IPKGSource(Screen):
1548         skin = """
1549                 <screen name="IPKGSource" position="center,center" size="560,80" title="Edit upgrade source url." >
1550                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1551                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1552                         <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" />
1553                         <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" />
1554                         <widget name="text" position="5,50" size="550,25" font="Regular;20" backgroundColor="background" foregroundColor="#cccccc" />
1555                 </screen>"""
1556
1557         def __init__(self, session, configfile = None):
1558                 Screen.__init__(self, session)
1559                 self.session = session
1560                 self.configfile = configfile
1561                 text = ""
1562                 if self.configfile:
1563                         try:
1564                                 fp = file(configfile, 'r')
1565                                 sources = fp.readlines()
1566                                 if sources:
1567                                         text = sources[0]
1568                                 fp.close()
1569                         except IOError:
1570                                 pass
1571
1572                 desk = getDesktop(0)
1573                 x= int(desk.size().width())
1574                 y= int(desk.size().height())
1575
1576                 self["key_red"] = StaticText(_("Cancel"))
1577                 self["key_green"] = StaticText(_("Save"))
1578
1579                 if (y>=720):
1580                         self["text"] = Input(text, maxSize=False, type=Input.TEXT)
1581                 else:
1582                         self["text"] = Input(text, maxSize=False, visible_width = 55, type=Input.TEXT)
1583
1584                 self["actions"] = NumberActionMap(["WizardActions", "InputActions", "TextEntryActions", "KeyboardInputActions","ShortcutActions"], 
1585                 {
1586                         "ok": self.go,
1587                         "back": self.close,
1588                         "red": self.close,
1589                         "green": self.go,
1590                         "left": self.keyLeft,
1591                         "right": self.keyRight,
1592                         "home": self.keyHome,
1593                         "end": self.keyEnd,
1594                         "deleteForward": self.keyDeleteForward,
1595                         "deleteBackward": self.keyDeleteBackward,
1596                         "1": self.keyNumberGlobal,
1597                         "2": self.keyNumberGlobal,
1598                         "3": self.keyNumberGlobal,
1599                         "4": self.keyNumberGlobal,
1600                         "5": self.keyNumberGlobal,
1601                         "6": self.keyNumberGlobal,
1602                         "7": self.keyNumberGlobal,
1603                         "8": self.keyNumberGlobal,
1604                         "9": self.keyNumberGlobal,
1605                         "0": self.keyNumberGlobal
1606                 }, -1)
1607
1608                 self.onLayoutFinish.append(self.layoutFinished)
1609
1610         def layoutFinished(self):
1611                 self.setWindowTitle()
1612                 self["text"].right()
1613
1614         def setWindowTitle(self):
1615                 self.setTitle(_("Edit upgrade source url."))
1616
1617         def go(self):
1618                 text = self["text"].getText()
1619                 if text:
1620                         fp = file(self.configfile, 'w')
1621                         fp.write(text)
1622                         fp.write("\n")
1623                         fp.close()
1624                 self.close()
1625
1626         def keyLeft(self):
1627                 self["text"].left()
1628         
1629         def keyRight(self):
1630                 self["text"].right()
1631         
1632         def keyHome(self):
1633                 self["text"].home()
1634         
1635         def keyEnd(self):
1636                 self["text"].end()
1637         
1638         def keyDeleteForward(self):
1639                 self["text"].delete()
1640         
1641         def keyDeleteBackward(self):
1642                 self["text"].deleteBackward()
1643         
1644         def keyNumberGlobal(self, number):
1645                 self["text"].number(number)
1646
1647
1648 class PacketManager(Screen, NumericalTextInput):
1649         skin = """
1650                 <screen name="PacketManager" position="center,center" size="530,420" title="Packet manager" >
1651                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1652                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1653                         <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" />
1654                         <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" />
1655                         <widget source="list" render="Listbox" position="5,50" size="520,365" scrollbarMode="showOnDemand">
1656                                 <convert type="TemplatedMultiContent">
1657                                         {"template": [
1658                                                         MultiContentEntryText(pos = (5, 1), size = (440, 28), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
1659                                                         MultiContentEntryText(pos = (5, 26), size = (440, 20), font=1, flags = RT_HALIGN_LEFT, text = 2), # index 2 is the description
1660                                                         MultiContentEntryPixmapAlphaTest(pos = (445, 2), size = (48, 48), png = 4), # index 4 is the status pixmap
1661                                                         MultiContentEntryPixmapAlphaTest(pos = (5, 50), size = (510, 2), png = 5), # index 4 is the div pixmap
1662                                                 ],
1663                                         "fonts": [gFont("Regular", 22),gFont("Regular", 14)],
1664                                         "itemHeight": 52
1665                                         }
1666                                 </convert>
1667                         </widget>
1668                 </screen>"""
1669                 
1670         def __init__(self, session, plugin_path, args = None):
1671                 Screen.__init__(self, session)
1672                 NumericalTextInput.__init__(self)
1673                 self.session = session
1674                 self.skin_path = plugin_path
1675
1676                 self.setUseableChars(u'1234567890abcdefghijklmnopqrstuvwxyz')
1677
1678                 self["shortcuts"] = NumberActionMap(["ShortcutActions", "WizardActions", "NumberActions", "InputActions", "InputAsciiActions", "KeyboardInputActions" ],
1679                 {
1680                         "ok": self.go,
1681                         "back": self.exit,
1682                         "red": self.exit,
1683                         "green": self.reload,
1684                         "gotAsciiCode": self.keyGotAscii,
1685                         "1": self.keyNumberGlobal,
1686                         "2": self.keyNumberGlobal,
1687                         "3": self.keyNumberGlobal,
1688                         "4": self.keyNumberGlobal,
1689                         "5": self.keyNumberGlobal,
1690                         "6": self.keyNumberGlobal,
1691                         "7": self.keyNumberGlobal,
1692                         "8": self.keyNumberGlobal,
1693                         "9": self.keyNumberGlobal,
1694                         "0": self.keyNumberGlobal
1695                 }, -1)
1696                 
1697                 self.list = []
1698                 self.statuslist = []
1699                 self["list"] = List(self.list)
1700                 self["key_red"] = StaticText(_("Close"))
1701                 self["key_green"] = StaticText(_("Reload"))
1702
1703                 self.list_updating = True
1704                 self.packetlist = []
1705                 self.installed_packetlist = {}
1706                 self.upgradeable_packages = {}
1707                 self.Console = Console()
1708                 self.cmdList = []
1709                 self.cachelist = []
1710                 self.cache_ttl = 86400  #600 is default, 0 disables, Seconds cache is considered valid (24h should be ok for caching ipkgs)
1711                 self.cache_file = eEnv.resolve('${libdir}/enigma2/python/Plugins/SystemPlugins/SoftwareManager/packetmanager.cache') #Path to cache directory
1712                 self.oktext = _("\nAfter pressing OK, please wait!")
1713                 self.unwanted_extensions = ('-dbg', '-dev', '-doc', 'busybox')
1714
1715                 self.ipkg = IpkgComponent()
1716                 self.ipkg.addCallback(self.ipkgCallback)
1717                 self.onShown.append(self.setWindowTitle)
1718                 self.onLayoutFinish.append(self.rebuildList)
1719
1720                 rcinput = eRCInput.getInstance()
1721                 rcinput.setKeyboardMode(rcinput.kmAscii)                
1722
1723         def keyNumberGlobal(self, val):
1724                 key = self.getKey(val)
1725                 if key is not None:
1726                         keyvalue = key.encode("utf-8")
1727                         if len(keyvalue) == 1:
1728                                 self.setNextIdx(keyvalue[0])
1729                 
1730         def keyGotAscii(self):
1731                 keyvalue = unichr(getPrevAsciiCode()).encode("utf-8")
1732                 if len(keyvalue) == 1:
1733                         self.setNextIdx(keyvalue[0])
1734                 
1735         def setNextIdx(self,char):
1736                 if char in ("0", "1", "a"):
1737                         self["list"].setIndex(0)
1738                 else:
1739                         idx = self.getNextIdx(char)
1740                         if idx and idx <= self["list"].count:
1741                                 self["list"].setIndex(idx)
1742
1743         def getNextIdx(self,char):
1744                 idx = 0
1745                 for i in self["list"].list:
1746                         if i[0][0] == char:
1747                                 return idx
1748                         idx += 1
1749
1750         def exit(self):
1751                 self.ipkg.stop()
1752                 if self.Console is not None:
1753                         if len(self.Console.appContainers):
1754                                 for name in self.Console.appContainers.keys():
1755                                         self.Console.kill(name)
1756                 rcinput = eRCInput.getInstance()
1757                 rcinput.setKeyboardMode(rcinput.kmNone)
1758                 self.close()
1759
1760         def reload(self):
1761                 if (os_path.exists(self.cache_file) == True):
1762                         remove(self.cache_file)
1763                         self.list_updating = True
1764                         self.rebuildList()
1765                         
1766         def setWindowTitle(self):
1767                 self.setTitle(_("Packet manager"))
1768
1769         def setStatus(self,status = None):
1770                 if status:
1771                         self.statuslist = []
1772                         divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1773                         if status == 'update':
1774                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
1775                                 self.statuslist.append(( _("Package list update"), '', _("Trying to download a new packetlist. Please wait..." ),'',statuspng, divpng ))
1776                                 self['list'].setList(self.statuslist)   
1777                         elif status == 'error':
1778                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
1779                                 self.statuslist.append(( _("Error"), '', _("There was an error downloading the packetlist. Please try again." ),'',statuspng, divpng ))
1780                                 self['list'].setList(self.statuslist)                           
1781
1782         def rebuildList(self):
1783                 self.setStatus('update')
1784                 self.inv_cache = 0
1785                 self.vc = valid_cache(self.cache_file, self.cache_ttl)
1786                 if self.cache_ttl > 0 and self.vc != 0:
1787                         try:
1788                                 self.buildPacketList()
1789                         except:
1790                                 self.inv_cache = 1
1791                 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
1792                         self.run = 0
1793                         self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
1794
1795         def go(self, returnValue = None):
1796                 cur = self["list"].getCurrent()
1797                 if cur:
1798                         status = cur[3]
1799                         package = cur[0]
1800                         self.cmdList = []
1801                         if status == 'installed':
1802                                 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package }))
1803                                 if len(self.cmdList):
1804                                         self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n") + package + "\n" + self.oktext)
1805                         elif status == 'upgradeable':
1806                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package }))
1807                                 if len(self.cmdList):
1808                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to upgrade the package:\n") + package + "\n" + self.oktext)
1809                         elif status == "installable":
1810                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package }))
1811                                 if len(self.cmdList):
1812                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n") + package + "\n" + self.oktext)
1813
1814         def runRemove(self, result):
1815                 if result:
1816                         self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
1817
1818         def runRemoveFinished(self):
1819                 self.session.openWithCallback(self.RemoveReboot, MessageBox, _("Remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1820
1821         def RemoveReboot(self, result):
1822                 if result is None:
1823                         return
1824                 if result is False:
1825                         cur = self["list"].getCurrent()
1826                         if cur:
1827                                 item = self['list'].getIndex()
1828                                 self.list[item] = self.buildEntryComponent(cur[0], cur[1], cur[2], 'installable')
1829                                 self.cachelist[item] = [cur[0], cur[1], cur[2], 'installable']
1830                                 self['list'].setList(self.list)
1831                                 write_cache(self.cache_file, self.cachelist)
1832                                 self.reloadPluginlist()
1833                 if result:
1834                         quitMainloop(3)
1835
1836         def runUpgrade(self, result):
1837                 if result:
1838                         self.session.openWithCallback(self.runUpgradeFinished, Ipkg, cmdList = self.cmdList)
1839
1840         def runUpgradeFinished(self):
1841                 self.session.openWithCallback(self.UpgradeReboot, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1842                 
1843         def UpgradeReboot(self, result):
1844                 if result is None:
1845                         return
1846                 if result is False:
1847                         cur = self["list"].getCurrent()
1848                         if cur:
1849                                 item = self['list'].getIndex()
1850                                 self.list[item] = self.buildEntryComponent(cur[0], cur[1], cur[2], 'installed')
1851                                 self.cachelist[item] = [cur[0], cur[1], cur[2], 'installed']
1852                                 self['list'].setList(self.list)
1853                                 write_cache(self.cache_file, self.cachelist)
1854                                 self.reloadPluginlist()
1855                 if result:
1856                         quitMainloop(3)
1857
1858         def ipkgCallback(self, event, param):
1859                 if event == IpkgComponent.EVENT_ERROR:
1860                         self.list_updating = False
1861                         self.setStatus('error')
1862                 elif event == IpkgComponent.EVENT_DONE:
1863                         if self.list_updating:
1864                                 self.list_updating = False
1865                                 if not self.Console:
1866                                         self.Console = Console()
1867                                 cmd = "opkg list"
1868                                 self.Console.ePopen(cmd, self.IpkgList_Finished)
1869                 #print event, "-", param
1870                 pass
1871
1872         def IpkgList_Finished(self, result, retval, extra_args = None):
1873                 if result:
1874                         self.packetlist = []
1875                         last_name = ""
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                                         descr = l > 2 and tokens[2].strip() or ""
1883                                         if name == last_name:
1884                                                 continue
1885                                         last_name = name 
1886                                         self.packetlist.append([name, version, descr])
1887
1888                 if not self.Console:
1889                         self.Console = Console()
1890                 cmd = "opkg list-installed"
1891                 self.Console.ePopen(cmd, self.IpkgListInstalled_Finished)
1892
1893         def IpkgListInstalled_Finished(self, result, retval, extra_args = None):
1894                 if result:
1895                         self.installed_packetlist = {}
1896                         for x in result.splitlines():
1897                                 tokens = x.split(' - ')
1898                                 name = tokens[0].strip()
1899                                 if not any(name.endswith(x) for x in self.unwanted_extensions):
1900                                         l = len(tokens)
1901                                         version = l > 1 and tokens[1].strip() or ""
1902                                         self.installed_packetlist[name] = version
1903                 if not self.Console:
1904                         self.Console = Console()
1905                 cmd = "opkg list-upgradable"
1906                 self.Console.ePopen(cmd, self.OpkgListUpgradeable_Finished)
1907
1908         def OpkgListUpgradeable_Finished(self, result, retval, extra_args = None):
1909                 if result:
1910                         self.upgradeable_packages = {}
1911                         for x in result.splitlines():
1912                                 tokens = x.split(' - ')
1913                                 name = tokens[0].strip()
1914                                 if not any(name.endswith(x) for x in self.unwanted_extensions):
1915                                         l = len(tokens)
1916                                         version = l > 2 and tokens[2].strip() or ""
1917                                         self.upgradeable_packages[name] = version
1918                 self.buildPacketList()
1919         
1920         def buildEntryComponent(self, name, version, description, state):
1921                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1922                 if description == "":
1923                         description = "No description available."
1924                 if state == 'installed':
1925                         installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installed.png"))
1926                         return((name, version, _(description), state, installedpng, divpng))    
1927                 elif state == 'upgradeable':
1928                         upgradeablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgradeable.png"))
1929                         return((name, version, _(description), state, upgradeablepng, divpng))  
1930                 else:
1931                         installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installable.png"))
1932                         return((name, version, _(description), state, installablepng, divpng))
1933
1934         def buildPacketList(self):
1935                 self.list = []
1936                 self.cachelist = []
1937                 if self.cache_ttl > 0 and self.vc != 0:
1938                         print 'Loading packagelist cache from ',self.cache_file
1939                         try:
1940                                 self.cachelist = load_cache(self.cache_file)
1941                                 if len(self.cachelist) > 0:
1942                                         for x in self.cachelist:
1943                                                 self.list.append(self.buildEntryComponent(x[0], x[1], x[2], x[3]))
1944                                         self['list'].setList(self.list)
1945                         except:
1946                                 self.inv_cache = 1
1947
1948                 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
1949                         print 'rebuilding fresh package list'
1950                         for x in self.packetlist:
1951                                 status = ""
1952                                 if self.installed_packetlist.has_key(x[0]):
1953                                         if self.upgradeable_packages.has_key(x[0]):
1954                                                 status = "upgradeable"
1955                                         else:
1956                                                 status = "installed"
1957                                 else:
1958                                         status = "installable"
1959                                 self.list.append(self.buildEntryComponent(x[0], x[1], x[2], status))    
1960                                 self.cachelist.append([x[0], x[1], x[2], status])
1961                         write_cache(self.cache_file, self.cachelist)
1962                         self['list'].setList(self.list)
1963
1964         def reloadPluginlist(self):
1965                 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
1966
1967
1968 class IpkgInstaller(Screen):
1969         skin = """
1970                 <screen name="IpkgInstaller" position="center,center" size="550,450" title="Install extensions" >
1971                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1972                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1973                         <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" />
1974                         <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" />
1975                         <widget name="list" position="5,50" size="540,360" />
1976                         <ePixmap pixmap="skin_default/div-h.png" position="0,410" zPosition="10" size="560,2" transparent="1" alphatest="on" />
1977                         <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" />
1978                 </screen>"""
1979         
1980         def __init__(self, session, list):
1981                 Screen.__init__(self, session)
1982
1983                 self.list = SelectionList()
1984                 self["list"] = self.list
1985                 for listindex in range(len(list)):
1986                         self.list.addSelection(list[listindex], list[listindex], listindex, True)
1987
1988                 self["key_red"] = StaticText(_("Close"))
1989                 self["key_green"] = StaticText(_("Install"))
1990                 self["introduction"] = StaticText(_("Press OK to toggle the selection."))
1991                 
1992                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions"], 
1993                 {
1994                         "ok": self.list.toggleSelection, 
1995                         "cancel": self.close,
1996                         "red": self.close,
1997                         "green": self.install
1998                 }, -1)
1999
2000         def install(self):
2001                 list = self.list.getSelectionsList()
2002                 cmdList = []
2003                 for item in list:
2004                         cmdList.append((IpkgComponent.CMD_INSTALL, { "package": item[1] }))
2005                 self.session.open(Ipkg, cmdList = cmdList)
2006
2007
2008 def filescan_open(list, session, **kwargs):
2009         filelist = [x.path for x in list]
2010         session.open(IpkgInstaller, filelist) # list
2011
2012 def filescan(**kwargs):
2013         from Components.Scanner import Scanner, ScanPath
2014         return \
2015                 Scanner(mimetypes = ["application/x-debian-package"], 
2016                         paths_to_scan = 
2017                                 [
2018                                         ScanPath(path = "ipk", with_subdirs = True), 
2019                                         ScanPath(path = "", with_subdirs = False), 
2020                                 ], 
2021                         name = "Ipkg", 
2022                         description = _("Install extensions."),
2023                         openfnc = filescan_open, )
2024
2025
2026
2027 def UpgradeMain(session, **kwargs):
2028         session.open(UpdatePluginMenu)
2029
2030 def startSetup(menuid):
2031         if menuid != "setup": 
2032                 return [ ]
2033         return [(_("Software management"), UpgradeMain, "software_manager", 50)]
2034
2035
2036 def Plugins(path, **kwargs):
2037         global plugin_path
2038         plugin_path = path
2039         list = [
2040                 PluginDescriptor(name=_("Software management"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_MENU, needsRestart = False, fnc=startSetup),
2041                 PluginDescriptor(name=_("Ipkg"), where = PluginDescriptor.WHERE_FILESCAN, needsRestart = False, fnc = filescan)
2042         ]
2043         if config.usage.setup_level.index >= 2: # expert+
2044                 list.append(PluginDescriptor(name=_("Software management"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_EXTENSIONSMENU, needsRestart = False, fnc=UpgradeMain))
2045         return list