1 from Plugins.Plugin import PluginDescriptor
2 from Screens.Console import Console
3 from Screens.ChoiceBox import ChoiceBox
4 from Screens.MessageBox import MessageBox
5 from Screens.Screen import Screen
6 from Screens.Ipkg import Ipkg
7 from Components.ActionMap import ActionMap, NumberActionMap
8 from Components.Input import Input
9 from Components.Ipkg import IpkgComponent
10 from Components.Sources.StaticText import StaticText
11 from Components.ScrollLabel import ScrollLabel
12 from Components.Pixmap import Pixmap
13 from Components.MenuList import MenuList
14 from Components.Sources.List import List
15 from Components.Slider import Slider
16 from Components.Harddisk import harddiskmanager
17 from Components.config import config,getConfigListEntry, ConfigSubsection, ConfigText, ConfigLocations
18 from Components.Console import Console
19 from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest
20 from Components.SelectionList import SelectionList
21 from Components.PluginComponent import plugins
22 from Components.About import about
23 from Components.DreamInfoHandler import DreamInfoHandler
24 from Components.Language import language
25 from Components.AVSwitch import AVSwitch
26 from Tools.Directories import pathExists, fileExists, resolveFilename, SCOPE_PLUGINS, SCOPE_CURRENT_PLUGIN, SCOPE_CURRENT_SKIN, SCOPE_METADIR
27 from Tools.LoadPixmap import LoadPixmap
28 from enigma import eTimer, quitMainloop, RT_HALIGN_LEFT, RT_VALIGN_CENTER, eListboxPythonMultiContent, eListbox, gFont, getDesktop, ePicLoad
29 from cPickle import dump, load
30 from os import path as os_path, system as os_system, unlink, stat, mkdir, popen, makedirs, listdir, access, rename, remove, W_OK, R_OK, F_OK
31 from time import time, gmtime, strftime, localtime
32 from stat import ST_MTIME
33 from datetime import date
34 from twisted.web import client
35 from twisted.internet import reactor
37 from ImageWizard import ImageWizard
38 from BackupRestore import BackupSelection, RestoreMenu, BackupScreen, RestoreScreen, getBackupPath, getBackupFilename
39 #from SoftwareTools import extensions
41 config.plugins.configurationbackup = ConfigSubsection()
42 config.plugins.configurationbackup.backuplocation = ConfigText(default = '/media/hdd/', visible_width = 50, fixed_size = False)
43 config.plugins.configurationbackup.backupdirs = ConfigLocations(default=['/etc/enigma2/', '/etc/network/interfaces', '/etc/wpa_supplicant.conf', '/etc/resolv.conf', '/etc/default_gw', '/etc/hostname'])
45 def write_cache(cache_file, cache_data):
47 if not os_path.isdir( os_path.dirname(cache_file) ):
49 mkdir( os_path.dirname(cache_file) )
51 print os_path.dirname(cache_file), 'is a file'
52 fd = open(cache_file, 'w')
53 dump(cache_data, fd, -1)
56 def valid_cache(cache_file, cache_ttl):
57 #See if the cache file exists and is still living
59 mtime = stat(cache_file)[ST_MTIME]
63 if (curr_time - mtime) > cache_ttl:
68 def load_cache(cache_file):
76 class UpdatePluginMenu(Screen):
78 <screen name="UpdatePluginMenu" position="center,center" size="560,400" title="Software manager" >
79 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
80 <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" />
81 <ePixmap pixmap="skin_default/border_menu_300.png" position="5,50" zPosition="1" size="300,300" transparent="1" alphatest="on" />
82 <widget source="menu" render="Listbox" position="10,60" size="290,260" scrollbarMode="showOnDemand">
83 <convert type="TemplatedMultiContent">
85 MultiContentEntryText(pos = (2, 2), size = (290, 22), flags = RT_HALIGN_LEFT, text = 1), # index 0 is the MenuText,
87 "fonts": [gFont("Regular", 20)],
92 <widget source="menu" render="Listbox" position="310,50" size="240,300" scrollbarMode="showNever" selectionDisabled="1">
93 <convert type="TemplatedMultiContent">
95 MultiContentEntryText(pos = (2, 2), size = (240, 300), flags = RT_HALIGN_CENTER|RT_VALIGN_CENTER|RT_WRAP, text = 2), # index 2 is the Description,
97 "fonts": [gFont("Regular", 20)],
104 def __init__(self, session, args = 0):
105 Screen.__init__(self, session)
106 self.skin_path = plugin_path
109 self.oktext = _("\nPress OK on your remote control to continue.")
110 self.backupdirs = ' '.join( config.plugins.configurationbackup.backupdirs.value )
112 self.list.append(("software-update", _("Software update"), _("\nOnline update of your Dreambox software." ) + self.oktext, None))
113 self.list.append(("install-plugins", _("Install extensions"), _("\nInstall new Extensions or Plugins to your dreambox" ) + self.oktext, None))
114 self.list.append(("software-restore", _("Software restore"), _("\nRestore your Dreambox with a new firmware." ) + self.oktext, None))
115 self.list.append(("system-backup", _("Backup system settings"), _("\nBackup your Dreambox settings." ) + self.oktext, None))
116 self.list.append(("system-restore",_("Restore system settings"), _("\nRestore your Dreambox settings." ) + self.oktext, None))
117 self.list.append(("ipkg-install", _("Install local extension"), _("\nScan for local packages and install them." ) + self.oktext, None))
118 for p in plugins.getPlugins(PluginDescriptor.WHERE_SOFTWAREMANAGER):
119 if p.__call__.has_key("SoftwareSupported"):
120 callFnc = p.__call__["SoftwareSupported"](None)
121 if callFnc is not None:
122 if p.__call__.has_key("menuEntryName"):
123 menuEntryName = p.__call__["menuEntryName"](None)
125 menuEntryName = _('Extended Software')
126 if p.__call__.has_key("menuEntryDescription"):
127 menuEntryDescription = p.__call__["menuEntryDescription"](None)
129 menuEntryDescription = _('Extended Software Plugin')
130 self.list.append(('default-plugin', menuEntryName, menuEntryDescription + self.oktext, callFnc))
131 if config.usage.setup_level.index >= 2: # expert+
132 self.list.append(("advanced", _("Advanced Options"), _("\nAdvanced options and settings." ) + self.oktext, None))
134 self.list.append(("advancedrestore", _("Advanced restore"), _("\nRestore your backups by date." ) + self.oktext, None))
135 self.list.append(("backuplocation", _("Choose backup location"), _("\nSelect your backup device.\nCurrent device: " ) + config.plugins.configurationbackup.backuplocation.value + self.oktext, None))
136 self.list.append(("backupfiles", _("Choose backup files"), _("Select files for backup. Currently selected:\n" ) + self.backupdirs + self.oktext, None))
137 if config.usage.setup_level.index >= 2: # expert+
138 self.list.append(("ipkg-manager", _("Packet management"), _("\nView, install and remove available or installed packages." ) + self.oktext, None))
139 self.list.append(("ipkg-source",_("Choose upgrade source"), _("\nEdit the upgrade source address." ) + self.oktext, None))
140 for p in plugins.getPlugins(PluginDescriptor.WHERE_SOFTWAREMANAGER):
141 if p.__call__.has_key("AdvancedSoftwareSupported"):
142 callFnc = p.__call__["AdvancedSoftwareSupported"](None)
143 if callFnc is not None:
144 if p.__call__.has_key("menuEntryName"):
145 menuEntryName = p.__call__["menuEntryName"](None)
147 menuEntryName = _('Advanced Software')
148 if p.__call__.has_key("menuEntryDescription"):
149 menuEntryDescription = p.__call__["menuEntryDescription"](None)
151 menuEntryDescription = _('Advanced Software Plugin')
152 self.list.append(('advanced-plugin', menuEntryName, menuEntryDescription + self.oktext, callFnc))
154 self["menu"] = List(self.list)
155 self["key_red"] = StaticText(_("Close"))
157 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
164 self.onLayoutFinish.append(self.layoutFinished)
165 self.backuppath = getBackupPath()
166 self.backupfile = getBackupFilename()
167 self.fullbackupfilename = self.backuppath + "/" + self.backupfile
168 self.onShown.append(self.setWindowTitle)
170 def layoutFinished(self):
172 self["menu"].index = idx
174 def setWindowTitle(self):
175 self.setTitle(_("Software manager"))
178 current = self["menu"].getCurrent()
180 currentEntry = current[0]
182 if (currentEntry == "software-update"):
183 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to update your Dreambox?")+"\n"+_("\nAfter pressing OK, please wait!"))
184 elif (currentEntry == "software-restore"):
185 self.session.open(ImageWizard)
186 elif (currentEntry == "install-plugins"):
187 self.session.open(PluginManager, self.skin_path)
188 elif (currentEntry == "system-backup"):
189 self.session.openWithCallback(self.backupDone,BackupScreen, runBackup = True)
190 elif (currentEntry == "system-restore"):
191 if os_path.exists(self.fullbackupfilename):
192 self.session.openWithCallback(self.startRestore, MessageBox, _("Are you sure you want to restore your Enigma2 backup?\nEnigma2 will restart after the restore"))
194 self.session.open(MessageBox, _("Sorry no backups found!"), MessageBox.TYPE_INFO, timeout = 10)
195 elif (currentEntry == "ipkg-install"):
197 from Plugins.Extensions.MediaScanner.plugin import main
200 self.session.open(MessageBox, _("Sorry MediaScanner is not installed!"), MessageBox.TYPE_INFO, timeout = 10)
201 elif (currentEntry == "default-plugin"):
202 self.extended = current[3]
203 self.extended(self.session, None)
204 elif (currentEntry == "advanced"):
205 self.session.open(UpdatePluginMenu, 1)
207 if (currentEntry == "ipkg-manager"):
208 self.session.open(PacketManager, self.skin_path)
209 elif (currentEntry == "backuplocation"):
210 parts = [ (r.description, r.mountpoint, self.session) for r in harddiskmanager.getMountedPartitions(onlyhotplug = False)]
212 if not access(x[1], F_OK|R_OK|W_OK) or x[1] == '/':
215 if x[1].startswith('/autofs/'):
218 self.session.openWithCallback(self.backuplocation_choosen, ChoiceBox, title = _("Please select medium to use as backup location"), list = parts)
219 elif (currentEntry == "backupfiles"):
220 self.session.openWithCallback(self.backupfiles_choosen,BackupSelection)
221 elif (currentEntry == "advancedrestore"):
222 self.session.open(RestoreMenu, self.skin_path)
223 elif (currentEntry == "ipkg-source"):
224 self.session.open(IPKGMenu, self.skin_path)
225 elif (currentEntry == "advanced-plugin"):
226 self.extended = current[3]
227 self.extended(self.session, None)
229 def backupfiles_choosen(self, ret):
230 self.backupdirs = ' '.join( config.plugins.configurationbackup.backupdirs.value )
232 def backuplocation_choosen(self, option):
233 if option is not None:
234 config.plugins.configurationbackup.backuplocation.value = str(option[1])
235 config.plugins.configurationbackup.backuplocation.save()
236 config.plugins.configurationbackup.save()
238 self.createBackupfolders()
240 def runUpgrade(self, result):
242 self.session.open(UpdatePlugin, self.skin_path)
244 def createBackupfolders(self):
245 print "Creating backup folder if not already there..."
246 self.backuppath = getBackupPath()
248 if (os_path.exists(self.backuppath) == False):
249 makedirs(self.backuppath)
251 self.session.open(MessageBox, _("Sorry, your backup destination is not writeable.\n\nPlease choose another one."), MessageBox.TYPE_INFO, timeout = 10)
253 def backupDone(self,retval = None):
255 self.session.open(MessageBox, _("Backup done."), MessageBox.TYPE_INFO, timeout = 10)
257 self.session.open(MessageBox, _("Backup failed."), MessageBox.TYPE_INFO, timeout = 10)
259 def startRestore(self, ret = False):
262 self.session.open(RestoreScreen, runRestore = True)
264 class IPKGMenu(Screen):
266 <screen name="IPKGMenu" position="center,center" size="560,400" title="Select upgrade source to edit." >
267 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
268 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
269 <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" />
270 <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" />
271 <widget name="filelist" position="5,50" size="550,340" scrollbarMode="showOnDemand" />
274 def __init__(self, session, plugin_path):
275 Screen.__init__(self, session)
276 self.skin_path = plugin_path
278 self["key_red"] = StaticText(_("Close"))
279 self["key_green"] = StaticText(_("Edit"))
288 self["actions"] = NumberActionMap(["SetupActions"],
291 "cancel": self.keyCancel
294 self["shortcuts"] = ActionMap(["ShortcutActions"],
296 "red": self.keyCancel,
300 self["filelist"] = MenuList(self.flist)
302 self.onLayoutFinish.append(self.layoutFinished)
304 def layoutFinished(self):
305 self.setWindowTitle()
307 def setWindowTitle(self):
308 self.setTitle(_("Select upgrade source to edit."))
312 self.path = '/etc/ipkg/'
313 if (os_path.exists(self.path) == False):
316 for file in listdir(self.path):
317 if (file.endswith(".conf")):
318 if file != 'arch.conf':
319 self.flist.append((file))
321 self["filelist"].l.setList(self.flist)
324 if (self.exe == False) and (self.entry == True):
325 self.sel = self["filelist"].getCurrent()
326 self.val = self.path + self.sel
327 self.session.open(IPKGSource, self.val)
336 class IPKGSource(Screen):
338 <screen name="IPKGSource" position="center,center" size="560,80" title="Edit upgrade source url." >
339 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
340 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
341 <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" />
342 <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" />
343 <widget name="text" position="5,50" size="550,25" font="Regular;20" backgroundColor="background" foregroundColor="#cccccc" />
346 def __init__(self, session, configfile = None):
347 Screen.__init__(self, session)
348 self.session = session
349 self.configfile = configfile
353 fp = file(configfile, 'r')
354 sources = fp.readlines()
362 x= int(desk.size().width())
363 y= int(desk.size().height())
365 self["key_red"] = StaticText(_("Cancel"))
366 self["key_green"] = StaticText(_("Save"))
369 self["text"] = Input(text, maxSize=False, type=Input.TEXT)
371 self["text"] = Input(text, maxSize=False, visible_width = 55, type=Input.TEXT)
373 self["actions"] = NumberActionMap(["WizardActions", "InputActions", "TextEntryActions", "KeyboardInputActions","ShortcutActions"],
379 "left": self.keyLeft,
380 "right": self.keyRight,
381 "home": self.keyHome,
383 "deleteForward": self.keyDeleteForward,
384 "deleteBackward": self.keyDeleteBackward,
385 "1": self.keyNumberGlobal,
386 "2": self.keyNumberGlobal,
387 "3": self.keyNumberGlobal,
388 "4": self.keyNumberGlobal,
389 "5": self.keyNumberGlobal,
390 "6": self.keyNumberGlobal,
391 "7": self.keyNumberGlobal,
392 "8": self.keyNumberGlobal,
393 "9": self.keyNumberGlobal,
394 "0": self.keyNumberGlobal
397 self.onLayoutFinish.append(self.layoutFinished)
399 def layoutFinished(self):
400 self.setWindowTitle()
403 def setWindowTitle(self):
404 self.setTitle(_("Edit upgrade source url."))
407 text = self["text"].getText()
409 fp = file(self.configfile, 'w')
427 def keyDeleteForward(self):
428 self["text"].delete()
430 def keyDeleteBackward(self):
431 self["text"].deleteBackward()
433 def keyNumberGlobal(self, number):
434 self["text"].number(number)
437 class PacketManager(Screen):
439 <screen name="PacketManager" position="center,center" size="530,420" title="Packet manager" >
440 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
441 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
442 <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" />
443 <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" />
444 <widget source="list" render="Listbox" position="5,50" size="520,365" scrollbarMode="showOnDemand">
445 <convert type="TemplatedMultiContent">
447 MultiContentEntryText(pos = (5, 1), size = (440, 28), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
448 MultiContentEntryText(pos = (5, 26), size = (440, 20), font=1, flags = RT_HALIGN_LEFT, text = 2), # index 2 is the description
449 MultiContentEntryPixmapAlphaTest(pos = (445, 2), size = (48, 48), png = 4), # index 4 is the status pixmap
450 MultiContentEntryPixmapAlphaTest(pos = (5, 50), size = (510, 2), png = 5), # index 4 is the div pixmap
452 "fonts": [gFont("Regular", 22),gFont("Regular", 14)],
459 def __init__(self, session, plugin_path, args = None):
460 Screen.__init__(self, session)
461 self.session = session
462 self.skin_path = plugin_path
464 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
469 "green": self.reload,
474 self["list"] = List(self.list)
475 self["key_red"] = StaticText(_("Close"))
476 self["key_green"] = StaticText(_("Reload"))
478 self.list_updating = True
480 self.installed_packetlist = {}
481 self.Console = Console()
484 self.cache_ttl = 86400 #600 is default, 0 disables, Seconds cache is considered valid (24h should be ok for caching ipkgs)
485 self.cache_file = '/usr/lib/enigma2/python/Plugins/SystemPlugins/SoftwareManager/packetmanager.cache' #Path to cache directory
486 self.oktext = _("\nAfter pressing OK, please wait!")
487 self.unwanted_extensions = ('-dbg', '-dev', '-doc', 'busybox')
489 self.ipkg = IpkgComponent()
490 self.ipkg.addCallback(self.ipkgCallback)
491 self.onShown.append(self.setWindowTitle)
492 self.onLayoutFinish.append(self.rebuildList)
496 if self.Console is not None:
497 if len(self.Console.appContainers):
498 for name in self.Console.appContainers.keys():
499 self.Console.kill(name)
503 if (os_path.exists(self.cache_file) == True):
504 remove(self.cache_file)
505 self.list_updating = True
508 def setWindowTitle(self):
509 self.setTitle(_("Packet manager"))
511 def setStatus(self,status = None):
514 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
515 if status == 'update':
516 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
517 self.statuslist.append(( _("Package list update"), '', _("Trying to download a new packetlist. Please wait..." ),'',statuspng, divpng ))
518 self['list'].setList(self.statuslist)
519 elif status == 'error':
520 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
521 self.statuslist.append(( _("Error"), '', _("There was an error downloading the packetlist. Please try again." ),'',statuspng, divpng ))
522 self['list'].setList(self.statuslist)
524 def rebuildList(self):
525 self.setStatus('update')
527 self.vc = valid_cache(self.cache_file, self.cache_ttl)
528 if self.cache_ttl > 0 and self.vc != 0:
530 self.buildPacketList()
533 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
535 self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
537 def go(self, returnValue = None):
538 cur = self["list"].getCurrent()
543 if status == 'installed':
544 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package }))
545 if len(self.cmdList):
546 self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n") + package + "\n" + self.oktext)
547 elif status == 'upgradeable':
548 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package }))
549 if len(self.cmdList):
550 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to upgrade the package:\n") + package + "\n" + self.oktext)
551 elif status == "installable":
552 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package }))
553 if len(self.cmdList):
554 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n") + package + "\n" + self.oktext)
556 def runRemove(self, result):
558 self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
560 def runRemoveFinished(self):
561 self.session.openWithCallback(self.RemoveReboot, MessageBox, _("Remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
563 def RemoveReboot(self, result):
567 cur = self["list"].getCurrent()
569 item = self['list'].getIndex()
570 self.list[item] = self.buildEntryComponent(cur[0], cur[1], cur[2], 'installable')
571 self.cachelist[item] = [cur[0], cur[1], cur[2], 'installable']
572 self['list'].setList(self.list)
573 write_cache(self.cache_file, self.cachelist)
574 self.reloadPluginlist()
578 def runUpgrade(self, result):
580 self.session.openWithCallback(self.runUpgradeFinished, Ipkg, cmdList = self.cmdList)
582 def runUpgradeFinished(self):
583 self.session.openWithCallback(self.UpgradeReboot, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
585 def UpgradeReboot(self, result):
589 cur = self["list"].getCurrent()
591 item = self['list'].getIndex()
592 self.list[item] = self.buildEntryComponent(cur[0], cur[1], cur[2], 'installed')
593 self.cachelist[item] = [cur[0], cur[1], cur[2], 'installed']
594 self['list'].setList(self.list)
595 write_cache(self.cache_file, self.cachelist)
596 self.reloadPluginlist()
600 def ipkgCallback(self, event, param):
601 if event == IpkgComponent.EVENT_ERROR:
602 self.list_updating = False
603 self.setStatus('error')
604 elif event == IpkgComponent.EVENT_DONE:
605 if self.list_updating:
606 self.list_updating = False
608 self.Console = Console()
610 self.Console.ePopen(cmd, self.IpkgList_Finished)
611 #print event, "-", param
614 def IpkgList_Finished(self, result, retval, extra_args = None):
617 for x in result.splitlines():
618 split = x.split(' - ') #self.blacklisted_packages
619 if not any(split[0].strip().endswith(x) for x in self.unwanted_extensions):
620 self.packetlist.append([split[0].strip(), split[1].strip(),split[2].strip()])
622 self.Console = Console()
623 cmd = "ipkg list_installed"
624 self.Console.ePopen(cmd, self.IpkgListInstalled_Finished)
626 def IpkgListInstalled_Finished(self, result, retval, extra_args = None):
628 self.installed_packetlist = {}
629 for x in result.splitlines():
630 split = x.split(' - ')
631 if not any(split[0].strip().endswith(x) for x in self.unwanted_extensions):
632 self.installed_packetlist[split[0].strip()] = split[1].strip()
633 self.buildPacketList()
635 def buildEntryComponent(self, name, version, description, state):
636 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
637 if state == 'installed':
638 installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installed.png"))
639 return((name, version, description, state, installedpng, divpng))
640 elif state == 'upgradeable':
641 upgradeablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgradeable.png"))
642 return((name, version, description, state, upgradeablepng, divpng))
644 installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installable.png"))
645 return((name, version, description, state, installablepng, divpng))
647 def buildPacketList(self):
651 if self.cache_ttl > 0 and self.vc != 0:
652 print 'Loading packagelist cache from ',self.cache_file
654 self.cachelist = load_cache(self.cache_file)
655 if len(self.cachelist) > 0:
656 for x in self.cachelist:
657 self.list.append(self.buildEntryComponent(x[0], x[1], x[2], x[3]))
658 self['list'].setList(self.list)
662 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
663 print 'rebuilding fresh package list'
664 for x in self.packetlist:
666 if self.installed_packetlist.has_key(x[0].strip()):
667 if self.installed_packetlist[x[0].strip()] == x[1].strip():
669 self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), status))
671 status = "upgradeable"
672 self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), status))
674 status = "installable"
675 self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), status))
676 if not any(x[0].strip().endswith(x) for x in self.unwanted_extensions):
677 self.cachelist.append([x[0].strip(), x[1].strip(), x[2].strip(), status])
678 write_cache(self.cache_file, self.cachelist)
679 self['list'].setList(self.list)
681 def reloadPluginlist(self):
682 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
685 class PluginManager(Screen, DreamInfoHandler):
687 lastDownloadDate = None
690 <screen name="PluginManager" position="center,center" size="560,440" title="Plugin manager" >
691 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
692 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
693 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
694 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
695 <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" />
696 <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" />
697 <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" />
698 <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" />
699 <widget source="list" render="Listbox" position="5,50" size="550,360" scrollbarMode="showOnDemand">
700 <convert type="TemplatedMultiContent">
703 MultiContentEntryText(pos = (30, 1), size = (470, 24), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
704 MultiContentEntryText(pos = (30, 25), size = (470, 20), font=1, flags = RT_HALIGN_LEFT, text = 2), # index 2 is the description
705 MultiContentEntryPixmapAlphaTest(pos = (475, 0), size = (48, 48), png = 5), # index 5 is the status pixmap
706 MultiContentEntryPixmapAlphaTest(pos = (0, 49), size = (550, 2), png = 6), # index 6 is the div pixmap
709 MultiContentEntryText(pos = (30, 0), size = (500, 22), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
710 MultiContentEntryText(pos = (30, 22), size = (500, 16), font=1, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the description
711 MultiContentEntryPixmapAlphaTest(pos = (0, 38), size = (550, 2), png = 3), # index 3 is the div pixmap
714 "fonts": [gFont("Regular", 22),gFont("Regular", 16)],
719 <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" />
722 def __init__(self, session, plugin_path, args = None):
723 Screen.__init__(self, session)
724 self.session = session
725 self.skin_path = plugin_path
726 aboutInfo = about.getImageVersionString()
727 if aboutInfo.startswith("dev-"):
728 self.ImageVersion = 'Experimental'
730 self.ImageVersion = 'Stable'
731 self.language = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
733 DreamInfoHandler.__init__(self, self.statusCallback, blocking = False, neededTag = 'ALL_TAGS', neededFlag = self.ImageVersion, language = self.language)
734 self.directory = resolveFilename(SCOPE_METADIR)
736 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions", "InfobarEPGActions", "HelpActions" ],
738 "ok": self.handleCurrent,
741 "green": self.handleCurrent,
742 "yellow": self.handleSelected,
743 "showEventInfo": self.handleSelected,
744 "displayHelp": self.handleHelp,
749 self.selectedFiles = []
750 self.categoryList = []
751 self["list"] = List(self.list)
752 self["key_red"] = StaticText(_("Close"))
753 self["key_green"] = StaticText("")
754 self["key_yellow"] = StaticText("")
755 self["key_blue"] = StaticText("")
756 self["status"] = StaticText("")
758 self.list_updating = True
760 self.installed_packetlist = {}
761 self.available_packetlist = []
762 self.available_updates = 0
763 self.Console = Console()
765 self.oktext = _("\nAfter pressing OK, please wait!")
766 self.unwanted_extensions = ('-dbg', '-dev', '-doc')
768 self.ipkg = IpkgComponent()
769 self.ipkg.addCallback(self.ipkgCallback)
770 if not self.selectionChanged in self["list"].onSelectionChanged:
771 self["list"].onSelectionChanged.append(self.selectionChanged)
774 self.currentSelectedTag = None
775 self.currentSelectedIndex = None
777 self.onShown.append(self.setWindowTitle)
778 self.onLayoutFinish.append(self.rebuildList)
780 def setWindowTitle(self):
781 self.setTitle(_("Plugin manager"))
784 if self.currList == "packages":
785 self.currList = "category"
786 self.currentSelectedTag = None
787 self["list"].style = "category"
788 self['list'].setList(self.categoryList)
789 self["list"].setIndex(self.currentSelectedIndex)
790 self["list"].updateList(self.categoryList)
791 self.selectionChanged()
794 if self.Console is not None:
795 if len(self.Console.appContainers):
796 for name in self.Console.appContainers.keys():
797 self.Console.kill(name)
798 self.prepareInstall()
799 if len(self.cmdList):
800 self.session.openWithCallback(self.runExecute, PluginManagerInfo, self.skin_path, self.cmdList)
804 def handleHelp(self):
805 if self.currList != "status":
806 self.session.open(PluginManagerHelp, self.skin_path)
808 def setState(self,status = None):
810 self.currList = "status"
812 self["key_green"].setText("")
813 self["key_blue"].setText("")
814 self["key_yellow"].setText("")
815 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
816 if status == 'update':
817 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
818 self.statuslist.append(( _("Package list update"), '', _("Trying to download a new packetlist. Please wait..." ),'', '', statuspng, divpng, None, '' ))
819 self["list"].style = "default"
820 self['list'].setList(self.statuslist)
821 elif status == 'sync':
822 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
823 self.statuslist.append(( _("Package list update"), '', _("Searching for new installed or removed packages. Please wait..." ),'', '', statuspng, divpng, None, '' ))
824 self["list"].style = "default"
825 self['list'].setList(self.statuslist)
826 elif status == 'error':
827 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
828 self.statuslist.append(( _("Error"), '', _("There was an error downloading the packetlist. Please try again." ),'', '', statuspng, divpng, None, '' ))
829 self["list"].style = "default"
830 self['list'].setList(self.statuslist)
832 def statusCallback(self, status, progress):
835 def selectionChanged(self):
836 current = self["list"].getCurrent()
837 self["status"].setText("")
839 if self.currList == "packages":
840 self["key_red"].setText(_("Back"))
841 if current[4] == 'installed':
842 self["key_green"].setText(_("Remove"))
843 elif current[4] == 'installable':
844 self["key_green"].setText(_("Install"))
845 elif current[4] == 'remove':
846 self["key_green"].setText(_("Undo\nRemove"))
847 elif current[4] == 'install':
848 self["key_green"].setText(_("Undo\nInstall"))
849 self["key_yellow"].setText(_("View details"))
850 self["key_blue"].setText("")
851 if len(self.selectedFiles) == 0 and self.available_updates is not 0:
852 self["status"].setText(_("There are at least ") + str(self.available_updates) + _(" updates available."))
853 elif len(self.selectedFiles) is not 0:
854 self["status"].setText(str(len(self.selectedFiles)) + _(" packages selected."))
856 self["status"].setText(_("There is nothing to be done."))
857 elif self.currList == "category":
858 self["key_red"].setText(_("Close"))
859 self["key_green"].setText("")
860 self["key_yellow"].setText("")
861 self["key_blue"].setText("")
862 if len(self.selectedFiles) == 0 and self.available_updates is not 0:
863 self["status"].setText(_("There are at least ") + str(self.available_updates) + _(" updates available."))
864 self["key_yellow"].setText(_("Update"))
865 elif len(self.selectedFiles) is not 0:
866 self["status"].setText(str(len(self.selectedFiles)) + _(" packages selected."))
867 self["key_yellow"].setText(_("Process"))
869 self["status"].setText(_("There is nothing to be done."))
871 def getSelectionState(self, detailsFile):
872 for entry in self.selectedFiles:
873 if entry[0] == detailsFile:
877 def rebuildList(self):
878 self.setState('update')
879 if not PluginManager.lastDownloadDate or (time() - PluginManager.lastDownloadDate) > 3600:
880 # Only update from internet once per hour
881 PluginManager.lastDownloadDate = time()
882 print "last update time > 1h"
883 self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
885 print "last update time < 1h"
888 def ipkgCallback(self, event, param):
889 if event == IpkgComponent.EVENT_ERROR:
890 self.list_updating = False
891 self.setState('error')
892 elif event == IpkgComponent.EVENT_DONE:
896 def startIpkgList(self):
897 if self.list_updating:
899 self.Console = Console()
901 self.Console.ePopen(cmd, self.IpkgList_Finished)
903 def IpkgList_Finished(self, result, retval, extra_args = None):
905 self.available_packetlist = []
906 for x in result.splitlines():
907 split = x.split(' - ')
908 if not any(split[0].strip().endswith(x) for x in self.unwanted_extensions):
909 self.available_packetlist.append([split[0].strip(), split[1].strip(), split[2].strip()])
910 self.startInstallMetaPackage()
912 def startInstallMetaPackage(self):
913 if self.list_updating:
914 self.list_updating = False
916 self.Console = Console()
917 cmd = "ipkg install enigma2-meta enigma2-plugins-meta enigma2-skins-meta"
918 self.Console.ePopen(cmd, self.InstallMetaPackage_Finished)
920 def InstallMetaPackage_Finished(self, result, retval, extra_args = None):
922 self.fillPackagesIndexList()
924 self.Console = Console()
925 self.setState('sync')
926 cmd = "ipkg list_installed"
927 self.Console.ePopen(cmd, self.IpkgListInstalled_Finished)
929 def IpkgListInstalled_Finished(self, result, retval, extra_args = None):
931 self.installed_packetlist = {}
932 for x in result.splitlines():
933 split = x.split(' - ')
934 if not any(split[0].strip().endswith(x) for x in self.unwanted_extensions):
935 self.installed_packetlist[split[0].strip()] = split[1].strip()
937 if self.currentSelectedTag is None:
938 self.buildCategoryList()
940 self.buildPacketList(self.currentSelectedTag)
942 def countUpdates(self):
943 self.available_updates = 0
944 for package in self.packagesIndexlist[:]:
945 attributes = package[0]["attributes"]
946 packagename = attributes["packagename"]
947 for x in self.available_packetlist:
948 if x[0].strip() == packagename:
949 if self.installed_packetlist.has_key(packagename):
950 if self.installed_packetlist[packagename] != x[1].strip():
951 self.available_updates +=1
953 def handleCurrent(self):
954 current = self["list"].getCurrent()
956 if self.currList == "category":
957 self.currentSelectedIndex = self["list"].index
958 selectedTag = current[2]
959 self.buildPacketList(selectedTag)
960 elif self.currList == "packages":
961 if current[7] is not '':
962 idx = self["list"].getIndex()
963 detailsFile = self.list[idx][1]
964 if self.list[idx][7] == True:
965 for entry in self.selectedFiles:
966 if entry[0] == detailsFile:
967 self.selectedFiles.remove(entry)
969 alreadyinList = False
970 for entry in self.selectedFiles:
971 if entry[0] == detailsFile:
973 if not alreadyinList:
974 self.selectedFiles.append((detailsFile,current[4],current[3]))
975 if current[4] == 'installed':
976 self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'remove', True)
977 elif current[4] == 'installable':
978 self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'install', True)
979 elif current[4] == 'remove':
980 self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'installed', False)
981 elif current[4] == 'install':
982 self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'installable',False)
983 self["list"].setList(self.list)
984 self["list"].setIndex(idx)
985 self["list"].updateList(self.list)
986 self.selectionChanged()
988 def handleSelected(self):
989 current = self["list"].getCurrent()
991 if self.currList == "packages":
992 if current[7] is not '':
993 detailsfile = self.directory[0] + "/" + current[1]
994 if (os_path.exists(detailsfile) == True):
995 self.session.openWithCallback(self.detailsClosed, PluginDetails, self.skin_path, current)
997 self.session.open(MessageBox, _("Sorry, no Details available!"), MessageBox.TYPE_INFO, timeout = 10)
998 elif self.currList == "category":
999 self.prepareInstall()
1000 if len(self.cmdList):
1001 self.session.openWithCallback(self.runExecute, PluginManagerInfo, self.skin_path, self.cmdList)
1003 def detailsClosed(self, result):
1005 if not self.Console:
1006 self.Console = Console()
1007 self.setState('sync')
1008 PluginManager.lastDownloadDate = time()
1009 self.selectedFiles = []
1011 self.Console.ePopen(cmd, self.InstallMetaPackage_Finished)
1013 def buildEntryComponent(self, name, details, description, packagename, state, selected = False):
1014 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1015 if state == 'installed':
1016 installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installed.png"))
1017 return((name, details, description, packagename, state, installedpng, divpng, selected))
1018 elif state == 'installable':
1019 installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installable.png"))
1020 return((name, details, description, packagename, state, installablepng, divpng, selected))
1021 elif state == 'remove':
1022 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
1023 return((name, details, description, packagename, state, removepng, divpng, selected))
1024 elif state == 'install':
1025 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/install.png"))
1026 return((name, details, description, packagename, state, installpng, divpng, selected))
1028 def buildPacketList(self, categorytag = None):
1029 if categorytag is not None:
1030 self.currList = "packages"
1031 self.currentSelectedTag = categorytag
1032 self.packetlist = []
1033 for package in self.packagesIndexlist[:]:
1034 prerequisites = package[0]["prerequisites"]
1035 if prerequisites.has_key("tag"):
1036 for foundtag in prerequisites["tag"]:
1037 if categorytag == foundtag:
1038 attributes = package[0]["attributes"]
1039 if attributes.has_key("packagetype"):
1040 if attributes["packagetype"] == "internal":
1042 self.packetlist.append([attributes["name"], attributes["details"], attributes["shortdescription"], attributes["packagename"]])
1044 self.packetlist.append([attributes["name"], attributes["details"], attributes["shortdescription"], attributes["packagename"]])
1046 for x in self.packetlist:
1048 selectState = self.getSelectionState(x[1].strip())
1049 if self.installed_packetlist.has_key(x[3].strip()):
1050 if selectState == True:
1053 status = "installed"
1054 self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), x[3].strip(), status, selected = selectState))
1056 if selectState == True:
1059 status = "installable"
1060 self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), x[3].strip(), status, selected = selectState))
1062 self.list.sort(key=lambda x: x[0])
1063 self["list"].style = "default"
1064 self['list'].setList(self.list)
1065 self["list"].updateList(self.list)
1066 self.selectionChanged()
1068 def buildCategoryList(self):
1069 self.currList = "category"
1070 self.categories = []
1071 self.categoryList = []
1072 for package in self.packagesIndexlist[:]:
1073 prerequisites = package[0]["prerequisites"]
1074 if prerequisites.has_key("tag"):
1075 for foundtag in prerequisites["tag"]:
1076 attributes = package[0]["attributes"]
1077 if foundtag not in self.categories:
1078 self.categories.append(foundtag)
1079 self.categoryList.append(self.buildCategoryComponent(foundtag))
1080 self.categoryList.sort(key=lambda x: x[0])
1081 self["list"].style = "category"
1082 self['list'].setList(self.categoryList)
1083 self["list"].updateList(self.categoryList)
1084 self.selectionChanged()
1086 def buildCategoryComponent(self, tag = None):
1087 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1090 return(( _("System"), _("View list of available system extensions" ), tag, divpng ))
1092 return(( _("Skins"), _("View list of available skins" ), tag, divpng ))
1093 elif tag == 'Recording':
1094 return(( _("Recordings"), _("View list of available recording extensions" ), tag, divpng ))
1095 elif tag == 'Network':
1096 return(( _("Network"), _("View list of available networking extensions" ), tag, divpng ))
1098 return(( _("CommonInterface"), _("View list of available CommonInterface extensions" ), tag, divpng ))
1099 elif tag == 'Default':
1100 return(( _("Default Settings"), _("View list of available default settings" ), tag, divpng ))
1102 return(( _("Satteliteequipment"), _("View list of available Satteliteequipment extensions." ), tag, divpng ))
1103 elif tag == 'Software':
1104 return(( _("Software"), _("View list of available software extensions" ), tag, divpng ))
1105 elif tag == 'Multimedia':
1106 return(( _("Multimedia"), _("View list of available multimedia extensions." ), tag, divpng ))
1107 elif tag == 'Display':
1108 return(( _("Display and Userinterface"), _("View list of available Display and Userinterface extensions." ), tag, divpng ))
1110 return(( _("Electronic Program Guide"), _("View list of available EPG extensions." ), tag, divpng ))
1111 elif tag == 'Communication':
1112 return(( _("Communication"), _("View list of available communication extensions." ), tag, divpng ))
1113 else: # dynamically generate non existent tags
1114 return(( str(tag), _("View list of available ") + str(tag) + _(" extensions." ), tag, divpng ))
1116 def prepareInstall(self):
1118 if self.available_updates > 0:
1119 self.cmdList.append((IpkgComponent.CMD_UPGRADE, { "test_only": False }))
1120 if self.selectedFiles and len(self.selectedFiles):
1121 for plugin in self.selectedFiles:
1122 detailsfile = self.directory[0] + "/" + plugin[0]
1123 if (os_path.exists(detailsfile) == True):
1124 self.fillPackageDetails(plugin[0])
1125 self.package = self.packageDetails[0]
1126 if self.package[0].has_key("attributes"):
1127 self.attributes = self.package[0]["attributes"]
1128 if self.attributes.has_key("package"):
1129 self.packagefiles = self.attributes["package"]
1130 if plugin[1] == 'installed':
1131 if self.packagefiles:
1132 for package in self.packagefiles[:]:
1133 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package["name"] }))
1135 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": plugin[2] }))
1137 if self.packagefiles:
1138 for package in self.packagefiles[:]:
1139 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package["name"] }))
1141 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": plugin[2] }))
1143 if plugin[1] == 'installed':
1144 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": plugin[2] }))
1146 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": plugin[2] }))
1148 def runExecute(self, result):
1150 self.session.openWithCallback(self.runExecuteFinished, Ipkg, cmdList = self.cmdList)
1154 def runExecuteFinished(self):
1155 self.session.openWithCallback(self.ExecuteReboot, MessageBox, _("Install or remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1157 def ExecuteReboot(self, result):
1161 self.reloadPluginlist()
1162 self.detailsClosed(True)
1166 def reloadPluginlist(self):
1167 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
1170 class PluginManagerInfo(Screen):
1172 <screen name="PluginManagerInfo" position="center,center" size="560,440" title="Plugin manager activity information" >
1173 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1174 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1175 <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" />
1176 <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" />
1177 <widget source="list" render="Listbox" position="5,50" size="550,350" scrollbarMode="showOnDemand" selectionDisabled="1">
1178 <convert type="TemplatedMultiContent">
1180 MultiContentEntryText(pos = (50, 1), size = (150, 24), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
1181 MultiContentEntryText(pos = (50, 25), size = (540, 24), font=1, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the state
1182 MultiContentEntryPixmapAlphaTest(pos = (0, 1), size = (48, 48), png = 2), # index 2 is the status pixmap
1183 MultiContentEntryPixmapAlphaTest(pos = (0, 49), size = (550, 2), png = 3), # index 3 is the div pixmap
1185 "fonts": [gFont("Regular", 22),gFont("Regular", 18)],
1190 <ePixmap pixmap="skin_default/div-h.png" position="0,410" zPosition="10" size="560,2" transparent="1" alphatest="on" />
1191 <widget source="status" render="Label" position="5,420" zPosition="10" size="550,30" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
1194 def __init__(self, session, plugin_path, cmdlist = None):
1195 Screen.__init__(self, session)
1196 self.session = session
1197 self.skin_path = plugin_path
1198 self.cmdlist = cmdlist
1200 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
1205 "green": self.process,
1209 self["list"] = List(self.list)
1210 self["key_red"] = StaticText(_("Cancel"))
1211 self["key_green"] = StaticText(_("Continue"))
1212 self["status"] = StaticText(_("Following tasks will be done after you press continue!"))
1214 self.onShown.append(self.setWindowTitle)
1215 self.onLayoutFinish.append(self.rebuildList)
1217 def setWindowTitle(self):
1218 self.setTitle(_("Plugin manager activity information"))
1220 def rebuildList(self):
1222 if self.cmdlist is not None:
1223 for entry in self.cmdlist:
1235 info = args['package']
1237 info = args['package']
1239 info = _("Dreambox software because updates are available.")
1241 self.list.append(self.buildEntryComponent(action,info))
1242 self['list'].setList(self.list)
1243 self['list'].updateList(self.list)
1245 def buildEntryComponent(self, action,info):
1246 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1247 upgradepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
1248 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/install.png"))
1249 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
1250 if action == 'install':
1251 return(( _('Installing'), info, installpng, divpng))
1252 elif action == 'remove':
1253 return(( _('Removing'), info, removepng, divpng))
1255 return(( _('Upgrading'), info, upgradepng, divpng))
1264 class PluginManagerHelp(Screen):
1266 <screen name="PluginManagerHelp" position="center,center" size="560,440" title="Plugin manager help" >
1267 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1268 <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" />
1269 <widget source="list" render="Listbox" position="5,50" size="550,350" scrollbarMode="showOnDemand" selectionDisabled="1">
1270 <convert type="TemplatedMultiContent">
1272 MultiContentEntryText(pos = (50, 1), size = (540, 24), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
1273 MultiContentEntryText(pos = (50, 25), size = (540, 24), font=1, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the state
1274 MultiContentEntryPixmapAlphaTest(pos = (0, 1), size = (48, 48), png = 2), # index 2 is the status pixmap
1275 MultiContentEntryPixmapAlphaTest(pos = (0, 49), size = (550, 2), png = 3), # index 3 is the div pixmap
1277 "fonts": [gFont("Regular", 22),gFont("Regular", 18)],
1282 <ePixmap pixmap="skin_default/div-h.png" position="0,410" zPosition="10" size="550,2" transparent="1" alphatest="on" />
1283 <widget source="status" render="Label" position="5,420" zPosition="10" size="550,30" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
1286 def __init__(self, session, plugin_path):
1287 Screen.__init__(self, session)
1288 self.session = session
1289 self.skin_path = plugin_path
1291 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
1298 self["list"] = List(self.list)
1299 self["key_red"] = StaticText(_("Close"))
1300 self["status"] = StaticText(_("A small overview of the available icon states and actions."))
1302 self.onShown.append(self.setWindowTitle)
1303 self.onLayoutFinish.append(self.rebuildList)
1305 def setWindowTitle(self):
1306 self.setTitle(_("Plugin manager help"))
1308 def rebuildList(self):
1310 self.list.append(self.buildEntryComponent('install'))
1311 self.list.append(self.buildEntryComponent('installable'))
1312 self.list.append(self.buildEntryComponent('installed'))
1313 self.list.append(self.buildEntryComponent('remove'))
1314 self['list'].setList(self.list)
1315 self['list'].updateList(self.list)
1317 def buildEntryComponent(self, state):
1318 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1319 installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installed.png"))
1320 installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installable.png"))
1321 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
1322 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/install.png"))
1324 if state == 'installed':
1325 return(( _('This plugin is installed.'), _('You can remove this plugin.'), installedpng, divpng))
1326 elif state == 'installable':
1327 return(( _('This plugin is not installed.'), _('You can install this plugin.'), installablepng, divpng))
1328 elif state == 'install':
1329 return(( _('This plugin will be installed.'), _('You can cancel the installation.'), installpng, divpng))
1330 elif state == 'remove':
1331 return(( _('This plugin will be removed.'), _('You can cancel the removal.'), removepng, divpng))
1337 class PluginDetails(Screen, DreamInfoHandler):
1339 <screen name="PluginDetails" position="center,center" size="600,440" title="Plugin details" >
1340 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1341 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1342 <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" />
1343 <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" />
1344 <widget source="author" render="Label" position="10,50" size="500,25" zPosition="10" font="Regular;21" transparent="1" />
1345 <widget name="statuspic" position="550,40" size="48,48" alphatest="on"/>
1346 <widget name="divpic" position="0,80" size="600,2" alphatest="on"/>
1347 <widget name="detailtext" position="10,90" size="270,330" zPosition="10" font="Regular;21" transparent="1" halign="left" valign="top"/>
1348 <widget name="screenshot" position="290,90" size="300,330" alphatest="on"/>
1350 def __init__(self, session, plugin_path, packagedata = None):
1351 Screen.__init__(self, session)
1352 self.skin_path = plugin_path
1353 self.language = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
1354 self.attributes = None
1355 self.translatedAttributes = None
1356 DreamInfoHandler.__init__(self, self.statusCallback, blocking = False, language = self.language)
1357 self.directory = resolveFilename(SCOPE_METADIR)
1359 self.pluginname = packagedata[0]
1360 self.details = packagedata[1]
1361 self.pluginstate = packagedata[4]
1362 self.statuspicinstance = packagedata[5]
1363 self.divpicinstance = packagedata[6]
1364 self.fillPackageDetails(self.details)
1368 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
1374 "down": self.pageDown,
1375 "left": self.pageUp,
1376 "right": self.pageDown,
1379 self["key_red"] = StaticText(_("Close"))
1380 self["key_green"] = StaticText("")
1381 self["author"] = StaticText()
1382 self["statuspic"] = Pixmap()
1383 self["divpic"] = Pixmap()
1384 self["screenshot"] = Pixmap()
1385 self["detailtext"] = ScrollLabel()
1387 self["statuspic"].hide()
1388 self["screenshot"].hide()
1389 self["divpic"].hide()
1391 self.package = self.packageDetails[0]
1392 if self.package[0].has_key("attributes"):
1393 self.attributes = self.package[0]["attributes"]
1394 if self.package[0].has_key("translation"):
1395 self.translatedAttributes = self.package[0]["translation"]
1398 self.oktext = _("\nAfter pressing OK, please wait!")
1399 self.picload = ePicLoad()
1400 self.picload.PictureData.get().append(self.paintScreenshotPixmapCB)
1401 self.onShown.append(self.setWindowTitle)
1402 self.onLayoutFinish.append(self.setInfos)
1404 def setWindowTitle(self):
1405 self.setTitle(_("Package details for: " + self.pluginname))
1411 self["detailtext"].pageUp()
1414 self["detailtext"].pageDown()
1416 def statusCallback(self, status, progress):
1420 if self.translatedAttributes.has_key("name"):
1421 self.pluginname = self.translatedAttributes["name"]
1422 elif self.attributes.has_key("name"):
1423 self.pluginname = self.attributes["name"]
1425 self.pluginname = _("unknown")
1427 if self.translatedAttributes.has_key("author"):
1428 self.author = self.translatedAttributes["author"]
1429 elif self.attributes.has_key("author"):
1430 self.author = self.attributes["author"]
1432 self.author = _("unknown")
1434 if self.translatedAttributes.has_key("description"):
1435 self.description = self.translatedAttributes["description"]
1436 elif self.attributes.has_key("description"):
1437 self.description = self.attributes["description"]
1439 self.description = _("No description available.")
1441 if self.translatedAttributes.has_key("screenshot"):
1442 self.loadThumbnail(self.translatedAttributes)
1444 self.loadThumbnail(self.attributes)
1446 self["author"].setText(_("Author: ") + self.author)
1447 self["detailtext"].setText(self.description.strip())
1448 if self.pluginstate == 'installable':
1449 self["key_green"].setText(_("Install"))
1451 self["key_green"].setText(_("Remove"))
1453 def loadThumbnail(self, entry):
1455 if entry.has_key("screenshot"):
1456 thumbnailUrl = entry["screenshot"]
1457 if thumbnailUrl is not None:
1458 self.thumbnail = "/tmp/" + thumbnailUrl.split('/')[-1]
1459 print "[PluginDetails] downloading screenshot " + thumbnailUrl + " to " + self.thumbnail
1460 client.downloadPage(thumbnailUrl,self.thumbnail).addCallback(self.setThumbnail).addErrback(self.fetchFailed)
1462 self.setThumbnail(noScreenshot = True)
1464 def setThumbnail(self, noScreenshot = False):
1465 if not noScreenshot:
1466 filename = self.thumbnail
1468 filename = resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/noprev.png")
1470 sc = AVSwitch().getFramebufferScale()
1471 self.picload.setPara((self["screenshot"].instance.size().width(), self["screenshot"].instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
1472 self.picload.startDecode(filename)
1474 if self.statuspicinstance != None:
1475 self["statuspic"].instance.setPixmap(self.statuspicinstance.__deref__())
1476 self["statuspic"].show()
1477 if self.divpicinstance != None:
1478 self["divpic"].instance.setPixmap(self.divpicinstance.__deref__())
1479 self["divpic"].show()
1481 def paintScreenshotPixmapCB(self, picInfo=None):
1482 ptr = self.picload.getData()
1484 self["screenshot"].instance.setPixmap(ptr.__deref__())
1485 self["screenshot"].show()
1487 self.setThumbnail(noScreenshot = True)
1490 if self.attributes.has_key("package"):
1491 self.packagefiles = self.attributes["package"]
1493 if self.pluginstate == 'installed':
1494 if self.packagefiles:
1495 for package in self.packagefiles[:]:
1496 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package["name"] }))
1497 if len(self.cmdList):
1498 self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n") + self.pluginname + "\n" + self.oktext)
1500 if self.packagefiles:
1501 for package in self.packagefiles[:]:
1502 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package["name"] }))
1503 if len(self.cmdList):
1504 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n") + self.pluginname + "\n" + self.oktext)
1506 def runUpgrade(self, result):
1508 self.session.openWithCallback(self.runUpgradeFinished, Ipkg, cmdList = self.cmdList)
1510 def runUpgradeFinished(self):
1511 self.session.openWithCallback(self.UpgradeReboot, MessageBox, _("Installation finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1513 def UpgradeReboot(self, result):
1521 def runRemove(self, result):
1523 self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
1525 def runRemoveFinished(self):
1526 self.session.openWithCallback(self.RemoveReboot, MessageBox, _("Remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1528 def RemoveReboot(self, result):
1536 def reloadPluginlist(self):
1537 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
1539 def fetchFailed(self,string):
1540 self.setThumbnail(noScreenshot = True)
1541 print "[PluginDetails] fetch failed " + string.getErrorMessage()
1544 class UpdatePlugin(Screen):
1546 <screen name="UpdatePlugin" position="center,center" size="550,200" title="Software update" >
1547 <widget name="activityslider" position="0,0" size="550,5" />
1548 <widget name="slider" position="0,150" size="550,30" />
1549 <widget source="package" render="Label" position="10,30" size="540,20" font="Regular;18" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
1550 <widget source="status" render="Label" position="10,60" size="540,45" font="Regular;20" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
1553 def __init__(self, session, args = None):
1554 Screen.__init__(self, session)
1556 self.sliderPackages = { "dreambox-dvb-modules": 1, "enigma2": 2, "tuxbox-image-info": 3 }
1558 self.slider = Slider(0, 4)
1559 self["slider"] = self.slider
1560 self.activityslider = Slider(0, 100)
1561 self["activityslider"] = self.activityslider
1562 self.status = StaticText(_("Upgrading Dreambox... Please wait"))
1563 self["status"] = self.status
1564 self.package = StaticText()
1565 self["package"] = self.package
1571 self.activityTimer = eTimer()
1572 self.activityTimer.callback.append(self.doActivityTimer)
1573 self.activityTimer.start(100, False)
1575 self.ipkg = IpkgComponent()
1576 self.ipkg.addCallback(self.ipkgCallback)
1578 self.updating = True
1579 self.package.setText(_("Package list update"))
1580 self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
1582 self["actions"] = ActionMap(["WizardActions"],
1588 def doActivityTimer(self):
1590 if self.activity == 100:
1592 self.activityslider.setValue(self.activity)
1594 def ipkgCallback(self, event, param):
1595 if event == IpkgComponent.EVENT_DOWNLOAD:
1596 self.status.setText(_("Downloading"))
1597 elif event == IpkgComponent.EVENT_UPGRADE:
1598 if self.sliderPackages.has_key(param):
1599 self.slider.setValue(self.sliderPackages[param])
1600 self.package.setText(param)
1601 self.status.setText(_("Upgrading"))
1603 elif event == IpkgComponent.EVENT_INSTALL:
1604 self.package.setText(param)
1605 self.status.setText(_("Installing"))
1607 elif event == IpkgComponent.EVENT_CONFIGURING:
1608 self.package.setText(param)
1609 self.status.setText(_("Configuring"))
1610 elif event == IpkgComponent.EVENT_MODIFIED:
1611 self.session.openWithCallback(
1612 self.modificationCallback,
1614 _("A configuration file (%s) was modified since Installation.\nDo you want to keep your version?") % (param)
1616 elif event == IpkgComponent.EVENT_ERROR:
1618 elif event == IpkgComponent.EVENT_DONE:
1620 self.updating = False
1621 self.ipkg.startCmd(IpkgComponent.CMD_UPGRADE, args = {'test_only': False})
1622 elif self.error == 0:
1623 self.slider.setValue(4)
1625 self.activityTimer.stop()
1626 self.activityslider.setValue(0)
1628 self.package.setText("")
1629 self.status.setText(_("Done - Installed or upgraded %d packages") % self.packages)
1631 self.activityTimer.stop()
1632 self.activityslider.setValue(0)
1633 error = _("your dreambox might be unusable now. Please consult the manual for further assistance before rebooting your dreambox.")
1634 if self.packages == 0:
1635 error = _("No packages were upgraded yet. So you can check your network and try again.")
1637 error = _("Your dreambox isn't connected to the internet properly. Please check it and try again.")
1638 self.status.setText(_("Error") + " - " + error)
1639 #print event, "-", param
1642 def modificationCallback(self, res):
1643 self.ipkg.write(res and "N" or "Y")
1646 if not self.ipkg.isRunning():
1647 if self.packages != 0 and self.error == 0:
1648 self.session.openWithCallback(self.exitAnswer, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"))
1652 def exitAnswer(self, result):
1653 if result is not None and result:
1658 class IpkgInstaller(Screen):
1660 <screen name="IpkgInstaller" position="center,center" size="550,450" title="Install extensions" >
1661 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1662 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1663 <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" />
1664 <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" />
1665 <widget name="list" position="5,50" size="540,360" />
1666 <ePixmap pixmap="skin_default/div-h.png" position="0,410" zPosition="10" size="560,2" transparent="1" alphatest="on" />
1667 <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" />
1670 def __init__(self, session, list):
1671 Screen.__init__(self, session)
1673 self.list = SelectionList()
1674 self["list"] = self.list
1675 for listindex in range(len(list)):
1676 self.list.addSelection(list[listindex], list[listindex], listindex, True)
1678 self["key_red"] = StaticText(_("Close"))
1679 self["key_green"] = StaticText(_("Install"))
1680 self["introduction"] = StaticText(_("Press OK to toggle the selection."))
1682 self["actions"] = ActionMap(["OkCancelActions", "ColorActions"],
1684 "ok": self.list.toggleSelection,
1685 "cancel": self.close,
1687 "green": self.install
1691 list = self.list.getSelectionsList()
1694 cmdList.append((IpkgComponent.CMD_INSTALL, { "package": item[1] }))
1695 self.session.open(Ipkg, cmdList = cmdList)
1698 def filescan_open(list, session, **kwargs):
1699 filelist = [x.path for x in list]
1700 session.open(IpkgInstaller, filelist) # list
1702 def filescan(**kwargs):
1703 from Components.Scanner import Scanner, ScanPath
1705 Scanner(mimetypes = ["application/x-debian-package"],
1708 ScanPath(path = "ipk", with_subdirs = True),
1709 ScanPath(path = "", with_subdirs = False),
1712 description = _("Install extensions."),
1713 openfnc = filescan_open, )
1717 def UpgradeMain(session, **kwargs):
1718 session.open(UpdatePluginMenu)
1720 def startSetup(menuid):
1721 if menuid != "setup":
1723 return [(_("Software manager"), UpgradeMain, "software_manager", 50)]
1725 def Plugins(path, **kwargs):
1729 PluginDescriptor(name=_("Software manager"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_MENU, fnc=startSetup),
1730 PluginDescriptor(name=_("Ipkg"), where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)
1732 if config.usage.setup_level.index >= 2: # expert+
1733 list.append(PluginDescriptor(name=_("Software manager"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=UpgradeMain))