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