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