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