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