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