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