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