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