1 from Plugins.Plugin import PluginDescriptor
2 from Screens.Console import Console
3 from Screens.ChoiceBox import ChoiceBox
4 from Screens.MessageBox import MessageBox
5 from Screens.Screen import Screen
6 from Screens.Ipkg import Ipkg
7 from Components.ActionMap import ActionMap, NumberActionMap
8 from Components.Input import Input
9 from Components.Ipkg import IpkgComponent
10 from Components.Sources.StaticText import StaticText
11 from Components.ScrollLabel import ScrollLabel
12 from Components.Pixmap import Pixmap
13 from Components.MenuList import MenuList
14 from Components.Sources.List import List
15 from Components.Slider import Slider
16 from Components.Harddisk import harddiskmanager
17 from Components.config import config,getConfigListEntry, ConfigSubsection, ConfigText, ConfigLocations
18 from Components.Console import Console
19 from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest
20 from Components.SelectionList import SelectionList
21 from Components.PluginComponent import plugins
22 from Components.About import about
23 from Components.DreamInfoHandler import DreamInfoHandler
24 from Components.Language import language
25 from Components.AVSwitch import AVSwitch
26 from Tools.Directories import pathExists, fileExists, resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE, SCOPE_METADIR
27 from Tools.LoadPixmap import LoadPixmap
28 from enigma import eTimer, quitMainloop, RT_HALIGN_LEFT, RT_VALIGN_CENTER, eListboxPythonMultiContent, eListbox, gFont, getDesktop, ePicLoad
29 from cPickle import dump, load
30 from os import path as os_path, system as os_system, unlink, stat, mkdir, popen, makedirs, listdir, access, rename, remove, W_OK, R_OK, F_OK
31 from time import time, gmtime, strftime, localtime
32 from stat import ST_MTIME
33 from datetime import date
34 from twisted.web import client
35 from twisted.internet import reactor
37 from ImageWizard import ImageWizard
38 from BackupRestore import BackupSelection, RestoreMenu, BackupScreen, RestoreScreen, getBackupPath, getBackupFilename
40 config.plugins.configurationbackup = ConfigSubsection()
41 config.plugins.configurationbackup.backuplocation = ConfigText(default = '/media/hdd/', visible_width = 50, fixed_size = False)
42 config.plugins.configurationbackup.backupdirs = ConfigLocations(default=['/etc/enigma2/', '/etc/network/interfaces', '/etc/wpa_supplicant.conf', '/etc/resolv.conf', '/etc/default_gw', '/etc/hostname'])
44 def write_cache(cache_file, cache_data):
46 if not os_path.isdir( os_path.dirname(cache_file) ):
48 mkdir( os_path.dirname(cache_file) )
50 print os_path.dirname(cache_file), 'is a file'
51 fd = open(cache_file, 'w')
52 dump(cache_data, fd, -1)
55 def valid_cache(cache_file, cache_ttl):
56 #See if the cache file exists and is still living
58 mtime = stat(cache_file)[ST_MTIME]
62 if (curr_time - mtime) > cache_ttl:
67 def load_cache(cache_file):
75 class UpdatePluginMenu(Screen):
77 <screen name="UpdatePluginMenu" position="center,center" size="560,400" title="Software manager" >
78 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
79 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
80 <ePixmap pixmap="skin_default/border_menu_300.png" position="5,50" zPosition="1" size="300,300" transparent="1" alphatest="on" />
81 <widget source="menu" render="Listbox" position="10,60" size="290,260" scrollbarMode="showOnDemand">
82 <convert type="TemplatedMultiContent">
84 MultiContentEntryText(pos = (2, 2), size = (290, 22), flags = RT_HALIGN_LEFT, text = 1), # index 0 is the MenuText,
86 "fonts": [gFont("Regular", 20)],
91 <widget source="menu" render="Listbox" position="310,50" size="240,300" scrollbarMode="showNever" selectionDisabled="1">
92 <convert type="TemplatedMultiContent">
94 MultiContentEntryText(pos = (2, 2), size = (240, 300), flags = RT_HALIGN_CENTER|RT_VALIGN_CENTER|RT_WRAP, text = 2), # index 2 is the Description,
96 "fonts": [gFont("Regular", 20)],
103 def __init__(self, session, args = 0):
104 Screen.__init__(self, session)
105 self.skin_path = plugin_path
108 self.oktext = _("\nPress OK on your remote control to continue.")
109 self.backupdirs = ' '.join( config.plugins.configurationbackup.backupdirs.value )
111 self.list.append(("software-update", _("Software update"), _("\nOnline update of your Dreambox software." ) + self.oktext) )
112 #self.list.append(("install-plugins", _("Install extensions"), _("\nInstall new Extensions or Plugins to your dreambox" ) + self.oktext) )
113 self.list.append(("software-restore", _("Software restore"), _("\nRestore your Dreambox with a new firmware." ) + self.oktext))
114 self.list.append(("system-backup", _("Backup system settings"), _("\nBackup your Dreambox settings." ) + self.oktext))
115 self.list.append(("system-restore",_("Restore system settings"), _("\nRestore your Dreambox settings." ) + self.oktext))
116 self.list.append(("ipkg-install", _("Install local extension"), _("\nScan for local packages and install them." ) + self.oktext))
117 if config.usage.setup_level.index >= 2: # expert+
118 self.list.append(("advanced", _("Advanced Options"), _("\nAdvanced options and settings." ) + self.oktext))
120 self.list.append(("advancedrestore", _("Advanced restore"), _("\nRestore your backups by date." ) + self.oktext))
121 self.list.append(("backuplocation", _("Choose backup location"), _("\nSelect your backup device.\nCurrent device: " ) + config.plugins.configurationbackup.backuplocation.value + self.oktext ))
122 self.list.append(("backupfiles", _("Choose backup files"), _("Select files for backup. Currently selected:\n" ) + self.backupdirs + self.oktext))
123 if config.usage.setup_level.index >= 2: # expert+
124 self.list.append(("ipkg-manager", _("Packet management"), _("\nView, install and remove available or installed packages." ) + self.oktext))
125 self.list.append(("ipkg-source",_("Choose upgrade source"), _("\nEdit the upgrade source address." ) + self.oktext))
127 self["menu"] = List(self.list)
128 self["key_red"] = StaticText(_("Close"))
130 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
137 self.onLayoutFinish.append(self.layoutFinished)
138 self.backuppath = getBackupPath()
139 self.backupfile = getBackupFilename()
140 self.fullbackupfilename = self.backuppath + "/" + self.backupfile
141 self.onShown.append(self.setWindowTitle)
143 def layoutFinished(self):
145 self["menu"].index = idx
147 def setWindowTitle(self):
148 self.setTitle(_("Software manager"))
151 current = self["menu"].getCurrent()
155 if (current == "software-update"):
156 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to update your Dreambox?")+"\n"+_("\nAfter pressing OK, please wait!"))
157 elif (current == "software-restore"):
158 self.session.open(ImageWizard)
159 elif (current == "install-plugins"):
160 self.session.open(PluginManager, self.skin_path)
161 elif (current == "system-backup"):
162 self.session.openWithCallback(self.backupDone,BackupScreen, runBackup = True)
163 elif (current == "system-restore"):
164 if os_path.exists(self.fullbackupfilename):
165 self.session.openWithCallback(self.startRestore, MessageBox, _("Are you sure you want to restore your Enigma2 backup?\nEnigma2 will restart after the restore"))
167 self.session.open(MessageBox, _("Sorry no backups found!"), MessageBox.TYPE_INFO, timeout = 10)
168 elif (current == "ipkg-install"):
170 from Plugins.Extensions.MediaScanner.plugin import main
173 self.session.open(MessageBox, _("Sorry MediaScanner is not installed!"), MessageBox.TYPE_INFO, timeout = 10)
174 elif (current == "advanced"):
175 self.session.open(UpdatePluginMenu, 1)
177 if (current == "ipkg-manager"):
178 self.session.open(PacketManager, self.skin_path)
179 elif (current == "backuplocation"):
180 parts = [ (r.description, r.mountpoint, self.session) for r in harddiskmanager.getMountedPartitions(onlyhotplug = False)]
182 if not access(x[1], F_OK|R_OK|W_OK) or x[1] == '/':
185 if x[1].startswith('/autofs/'):
188 self.session.openWithCallback(self.backuplocation_choosen, ChoiceBox, title = _("Please select medium to use as backup location"), list = parts)
189 elif (current == "backupfiles"):
190 self.session.openWithCallback(self.backupfiles_choosen,BackupSelection)
191 elif (current == "advancedrestore"):
192 self.session.open(RestoreMenu, self.skin_path)
193 elif (current == "ipkg-source"):
194 self.session.open(IPKGMenu, self.skin_path)
196 def backupfiles_choosen(self, ret):
197 self.backupdirs = ' '.join( config.plugins.configurationbackup.backupdirs.value )
199 def backuplocation_choosen(self, option):
200 if option is not None:
201 config.plugins.configurationbackup.backuplocation.value = str(option[1])
202 config.plugins.configurationbackup.backuplocation.save()
203 config.plugins.configurationbackup.save()
205 self.createBackupfolders()
207 def runUpgrade(self, result):
209 self.session.open(UpdatePlugin, self.skin_path)
211 def createBackupfolders(self):
212 print "Creating backup folder if not already there..."
213 self.backuppath = getBackupPath()
215 if (os_path.exists(self.backuppath) == False):
216 makedirs(self.backuppath)
218 self.session.open(MessageBox, _("Sorry, your backup destination is not writeable.\n\nPlease choose another one."), MessageBox.TYPE_INFO, timeout = 10)
220 def backupDone(self,retval = None):
222 self.session.open(MessageBox, _("Backup done."), MessageBox.TYPE_INFO, timeout = 10)
224 self.session.open(MessageBox, _("Backup failed."), MessageBox.TYPE_INFO, timeout = 10)
226 def startRestore(self, ret = False):
229 self.session.open(RestoreScreen, runRestore = True)
231 class IPKGMenu(Screen):
233 <screen name="IPKGMenu" position="center,center" size="560,400" title="Select upgrade source to edit." >
234 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
235 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
236 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
237 <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
238 <widget name="filelist" position="5,50" size="550,340" scrollbarMode="showOnDemand" />
241 def __init__(self, session, plugin_path):
242 Screen.__init__(self, session)
243 self.skin_path = plugin_path
245 self["key_red"] = StaticText(_("Close"))
246 self["key_green"] = StaticText(_("Edit"))
255 self["actions"] = NumberActionMap(["SetupActions"],
258 "cancel": self.keyCancel
261 self["shortcuts"] = ActionMap(["ShortcutActions"],
263 "red": self.keyCancel,
267 self["filelist"] = MenuList(self.flist)
269 self.onLayoutFinish.append(self.layoutFinished)
271 def layoutFinished(self):
272 self.setWindowTitle()
274 def setWindowTitle(self):
275 self.setTitle(_("Select upgrade source to edit."))
279 self.path = '/etc/ipkg/'
280 if (os_path.exists(self.path) == False):
283 for file in listdir(self.path):
284 if (file.endswith(".conf")):
285 if file != 'arch.conf':
286 self.flist.append((file))
288 self["filelist"].l.setList(self.flist)
291 if (self.exe == False) and (self.entry == True):
292 self.sel = self["filelist"].getCurrent()
293 self.val = self.path + self.sel
294 self.session.open(IPKGSource, self.val)
303 class IPKGSource(Screen):
305 <screen name="IPKGSource" position="center,center" size="560,80" title="Edit upgrade source url." >
306 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
307 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
308 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
309 <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
310 <widget name="text" position="5,50" size="550,25" font="Regular;20" backgroundColor="background" foregroundColor="#cccccc" />
313 def __init__(self, session, configfile = None):
314 Screen.__init__(self, session)
315 self.session = session
316 self.configfile = configfile
320 fp = file(configfile, 'r')
321 sources = fp.readlines()
329 x= int(desk.size().width())
330 y= int(desk.size().height())
332 self["key_red"] = StaticText(_("Cancel"))
333 self["key_green"] = StaticText(_("Save"))
336 self["text"] = Input(text, maxSize=False, type=Input.TEXT)
338 self["text"] = Input(text, maxSize=False, visible_width = 55, type=Input.TEXT)
340 self["actions"] = NumberActionMap(["WizardActions", "InputActions", "TextEntryActions", "KeyboardInputActions","ShortcutActions"],
346 "left": self.keyLeft,
347 "right": self.keyRight,
348 "home": self.keyHome,
350 "deleteForward": self.keyDeleteForward,
351 "deleteBackward": self.keyDeleteBackward,
352 "1": self.keyNumberGlobal,
353 "2": self.keyNumberGlobal,
354 "3": self.keyNumberGlobal,
355 "4": self.keyNumberGlobal,
356 "5": self.keyNumberGlobal,
357 "6": self.keyNumberGlobal,
358 "7": self.keyNumberGlobal,
359 "8": self.keyNumberGlobal,
360 "9": self.keyNumberGlobal,
361 "0": self.keyNumberGlobal
364 self.onLayoutFinish.append(self.layoutFinished)
366 def layoutFinished(self):
367 self.setWindowTitle()
370 def setWindowTitle(self):
371 self.setTitle(_("Edit upgrade source url."))
374 text = self["text"].getText()
376 fp = file(self.configfile, 'w')
394 def keyDeleteForward(self):
395 self["text"].delete()
397 def keyDeleteBackward(self):
398 self["text"].deleteBackward()
400 def keyNumberGlobal(self, number):
401 self["text"].number(number)
404 class PacketManager(Screen):
406 <screen name="PacketManager" position="center,center" size="530,420" title="Packet manager" >
407 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
408 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
409 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
410 <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
411 <widget source="list" render="Listbox" position="5,50" size="520,365" scrollbarMode="showOnDemand">
412 <convert type="TemplatedMultiContent">
414 MultiContentEntryText(pos = (5, 1), size = (440, 28), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
415 MultiContentEntryText(pos = (5, 26), size = (440, 20), font=1, flags = RT_HALIGN_LEFT, text = 2), # index 2 is the description
416 MultiContentEntryPixmapAlphaTest(pos = (445, 2), size = (48, 48), png = 4), # index 4 is the status pixmap
417 MultiContentEntryPixmapAlphaTest(pos = (5, 50), size = (510, 2), png = 5), # index 4 is the div pixmap
419 "fonts": [gFont("Regular", 22),gFont("Regular", 14)],
426 def __init__(self, session, plugin_path, args = None):
427 Screen.__init__(self, session)
428 self.session = session
429 self.skin_path = plugin_path
431 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
436 "green": self.reload,
441 self["list"] = List(self.list)
442 self["key_red"] = StaticText(_("Close"))
443 self["key_green"] = StaticText(_("Reload"))
445 self.list_updating = True
447 self.installed_packetlist = {}
448 self.Console = Console()
451 self.cache_ttl = 86400 #600 is default, 0 disables, Seconds cache is considered valid (24h should be ok for caching ipkgs)
452 self.cache_file = '/usr/lib/enigma2/python/Plugins/SystemPlugins/SoftwareManager/packetmanager.cache' #Path to cache directory
453 self.oktext = _("\nAfter pressing OK, please wait!")
454 self.unwanted_extensions = ('-dbg', '-dev', '-doc', 'busybox')
456 self.ipkg = IpkgComponent()
457 self.ipkg.addCallback(self.ipkgCallback)
458 self.onShown.append(self.setWindowTitle)
459 self.onLayoutFinish.append(self.rebuildList)
463 if self.Console is not None:
464 if len(self.Console.appContainers):
465 for name in self.Console.appContainers.keys():
466 self.Console.kill(name)
470 if (os_path.exists(self.cache_file) == True):
471 remove(self.cache_file)
472 self.list_updating = True
475 def setWindowTitle(self):
476 self.setTitle(_("Packet manager"))
478 def setStatus(self,status = None):
481 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/div-h.png"))
482 if status == 'update':
483 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/upgrade.png"))
484 self.statuslist.append(( _("Package list update"), '', _("Trying to download a new packetlist. Please wait..." ),'',statuspng, divpng ))
485 self['list'].setList(self.statuslist)
486 elif status == 'error':
487 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/remove.png"))
488 self.statuslist.append(( _("Error"), '', _("There was an error downloading the packetlist. Please try again." ),'',statuspng, divpng ))
489 self['list'].setList(self.statuslist)
491 def rebuildList(self):
492 self.setStatus('update')
494 self.vc = valid_cache(self.cache_file, self.cache_ttl)
495 if self.cache_ttl > 0 and self.vc != 0:
497 self.buildPacketList()
500 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
502 self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
504 def go(self, returnValue = None):
505 cur = self["list"].getCurrent()
510 if status == 'installed':
511 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package }))
512 if len(self.cmdList):
513 self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n") + package + "\n" + self.oktext)
514 elif status == 'upgradeable':
515 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package }))
516 if len(self.cmdList):
517 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to upgrade the package:\n") + package + "\n" + self.oktext)
518 elif status == "installable":
519 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package }))
520 if len(self.cmdList):
521 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n") + package + "\n" + self.oktext)
523 def runRemove(self, result):
525 self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
527 def runRemoveFinished(self):
528 self.session.openWithCallback(self.RemoveReboot, MessageBox, _("Remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
530 def RemoveReboot(self, result):
534 cur = self["list"].getCurrent()
536 item = self['list'].getIndex()
537 self.list[item] = self.buildEntryComponent(cur[0], cur[1], cur[2], 'installable')
538 self.cachelist[item] = [cur[0], cur[1], cur[2], 'installable']
539 self['list'].setList(self.list)
540 write_cache(self.cache_file, self.cachelist)
541 self.reloadPluginlist()
545 def runUpgrade(self, result):
547 self.session.openWithCallback(self.runUpgradeFinished, Ipkg, cmdList = self.cmdList)
549 def runUpgradeFinished(self):
550 self.session.openWithCallback(self.UpgradeReboot, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
552 def UpgradeReboot(self, result):
556 cur = self["list"].getCurrent()
558 item = self['list'].getIndex()
559 self.list[item] = self.buildEntryComponent(cur[0], cur[1], cur[2], 'installed')
560 self.cachelist[item] = [cur[0], cur[1], cur[2], 'installed']
561 self['list'].setList(self.list)
562 write_cache(self.cache_file, self.cachelist)
563 self.reloadPluginlist()
567 def ipkgCallback(self, event, param):
568 if event == IpkgComponent.EVENT_ERROR:
569 self.list_updating = False
570 self.setStatus('error')
571 elif event == IpkgComponent.EVENT_DONE:
572 if self.list_updating:
573 self.list_updating = False
575 self.Console = Console()
577 self.Console.ePopen(cmd, self.IpkgList_Finished)
578 #print event, "-", param
581 def IpkgList_Finished(self, result, retval, extra_args = None):
584 for x in result.splitlines():
585 split = x.split(' - ') #self.blacklisted_packages
586 if not any(split[0].strip().endswith(x) for x in self.unwanted_extensions):
587 self.packetlist.append([split[0].strip(), split[1].strip(),split[2].strip()])
589 self.Console = Console()
590 cmd = "ipkg list_installed"
591 self.Console.ePopen(cmd, self.IpkgListInstalled_Finished)
593 def IpkgListInstalled_Finished(self, result, retval, extra_args = None):
595 self.installed_packetlist = {}
596 for x in result.splitlines():
597 split = x.split(' - ')
598 if not any(split[0].strip().endswith(x) for x in self.unwanted_extensions):
599 self.installed_packetlist[split[0].strip()] = split[1].strip()
600 self.buildPacketList()
602 def buildEntryComponent(self, name, version, description, state):
603 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/div-h.png"))
604 if state == 'installed':
605 installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/installed.png"))
606 return((name, version, description, state, installedpng, divpng))
607 elif state == 'upgradeable':
608 upgradeablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/upgradeable.png"))
609 return((name, version, description, state, upgradeablepng, divpng))
611 installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/installable.png"))
612 return((name, version, description, state, installablepng, divpng))
614 def buildPacketList(self):
618 if self.cache_ttl > 0 and self.vc != 0:
619 print 'Loading packagelist cache from ',self.cache_file
621 self.cachelist = load_cache(self.cache_file)
622 if len(self.cachelist) > 0:
623 for x in self.cachelist:
624 self.list.append(self.buildEntryComponent(x[0], x[1], x[2], x[3]))
625 self['list'].setList(self.list)
629 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
630 print 'rebuilding fresh package list'
631 for x in self.packetlist:
633 if self.installed_packetlist.has_key(x[0].strip()):
634 if self.installed_packetlist[x[0].strip()] == x[1].strip():
636 self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), status))
638 status = "upgradeable"
639 self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), status))
641 status = "installable"
642 self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), status))
643 if not any(x[0].strip().endswith(x) for x in self.unwanted_extensions):
644 self.cachelist.append([x[0].strip(), x[1].strip(), x[2].strip(), status])
645 write_cache(self.cache_file, self.cachelist)
646 self['list'].setList(self.list)
648 def reloadPluginlist(self):
649 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
652 class PluginManager(Screen, DreamInfoHandler):
654 lastDownloadDate = None
657 <screen name="PluginManager" position="center,center" size="560,440" title="Plugin manager" >
658 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
659 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
660 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
661 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
662 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
663 <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
664 <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
665 <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" transparent="1" />
666 <widget source="list" render="Listbox" position="5,50" size="550,360" scrollbarMode="showOnDemand">
667 <convert type="TemplatedMultiContent">
670 MultiContentEntryText(pos = (30, 1), size = (470, 24), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
671 MultiContentEntryText(pos = (30, 25), size = (470, 20), font=1, flags = RT_HALIGN_LEFT, text = 2), # index 2 is the description
672 MultiContentEntryPixmapAlphaTest(pos = (475, 0), size = (48, 48), png = 5), # index 5 is the status pixmap
673 MultiContentEntryPixmapAlphaTest(pos = (0, 49), size = (550, 2), png = 6), # index 6 is the div pixmap
676 MultiContentEntryText(pos = (30, 0), size = (500, 22), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
677 MultiContentEntryText(pos = (30, 22), size = (500, 16), font=1, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the description
678 MultiContentEntryPixmapAlphaTest(pos = (0, 38), size = (550, 2), png = 3), # index 3 is the div pixmap
681 "fonts": [gFont("Regular", 22),gFont("Regular", 16)],
686 <widget source="status" render="Label" position="5,410" zPosition="10" size="540,30" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
689 def __init__(self, session, plugin_path, args = None):
690 Screen.__init__(self, session)
691 self.session = session
692 self.skin_path = plugin_path
693 aboutInfo = about.getImageVersionString()
694 if aboutInfo.startswith("dev-"):
695 self.ImageVersion = 'Experimental'
697 self.ImageVersion = 'Stable'
698 self.language = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
700 DreamInfoHandler.__init__(self, self.statusCallback, blocking = False, neededTag = 'ALL_TAGS', neededFlag = self.ImageVersion, language = self.language)
701 self.directory = resolveFilename(SCOPE_METADIR)
703 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions", "InfobarEPGActions", "HelpActions" ],
705 "ok": self.handleCurrent,
708 "green": self.handleCurrent,
709 "yellow": self.handleSelected,
710 "showEventInfo": self.handleSelected,
711 "displayHelp": self.handleHelp,
716 self.selectedFiles = []
717 self.categoryList = []
718 self["list"] = List(self.list)
719 self["key_red"] = StaticText(_("Close"))
720 self["key_green"] = StaticText("")
721 self["key_yellow"] = StaticText("")
722 self["key_blue"] = StaticText("")
723 self["status"] = StaticText("")
725 self.list_updating = True
727 self.installed_packetlist = {}
728 self.available_packetlist = []
729 self.available_updates = 0
730 self.Console = Console()
732 self.oktext = _("\nAfter pressing OK, please wait!")
733 self.unwanted_extensions = ('-dbg', '-dev', '-doc')
735 self.ipkg = IpkgComponent()
736 self.ipkg.addCallback(self.ipkgCallback)
737 if not self.selectionChanged in self["list"].onSelectionChanged:
738 self["list"].onSelectionChanged.append(self.selectionChanged)
741 self.currentSelectedTag = None
742 self.currentSelectedIndex = None
744 self.onShown.append(self.setWindowTitle)
745 self.onLayoutFinish.append(self.rebuildList)
747 def setWindowTitle(self):
748 self.setTitle(_("Plugin manager"))
751 if self.currList == "packages":
752 self.currList = "category"
753 self.currentSelectedTag = None
754 self["list"].style = "category"
755 self['list'].setList(self.categoryList)
756 self["list"].setIndex(self.currentSelectedIndex)
757 self["list"].updateList(self.categoryList)
758 self.selectionChanged()
761 if self.Console is not None:
762 if len(self.Console.appContainers):
763 for name in self.Console.appContainers.keys():
764 self.Console.kill(name)
765 self.prepareInstall()
766 if len(self.cmdList):
767 self.session.openWithCallback(self.runExecute, PluginManagerInfo, self.skin_path, self.cmdList)
771 def handleHelp(self):
772 if self.currList != "status":
773 self.session.open(PluginManagerHelp, self.skin_path)
775 def setState(self,status = None):
777 self.currList = "status"
779 self["key_green"].setText("")
780 self["key_blue"].setText("")
781 self["key_yellow"].setText("")
782 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/div-h.png"))
783 if status == 'update':
784 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/upgrade.png"))
785 self.statuslist.append(( _("Package list update"), '', _("Trying to download a new packetlist. Please wait..." ),'', '', statuspng, divpng, None, '' ))
786 self["list"].style = "default"
787 self['list'].setList(self.statuslist)
788 elif status == 'sync':
789 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/upgrade.png"))
790 self.statuslist.append(( _("Package list update"), '', _("Searching for new installed or removed packages. Please wait..." ),'', '', statuspng, divpng, None, '' ))
791 self["list"].style = "default"
792 self['list'].setList(self.statuslist)
793 elif status == 'error':
794 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/remove.png"))
795 self.statuslist.append(( _("Error"), '', _("There was an error downloading the packetlist. Please try again." ),'', '', statuspng, divpng, None, '' ))
796 self["list"].style = "default"
797 self['list'].setList(self.statuslist)
799 def statusCallback(self, status, progress):
802 def selectionChanged(self):
803 current = self["list"].getCurrent()
804 self["status"].setText("")
806 if self.currList == "packages":
807 self["key_red"].setText(_("Back"))
808 if current[4] == 'installed':
809 self["key_green"].setText(_("Remove"))
810 elif current[4] == 'installable':
811 self["key_green"].setText(_("Install"))
812 elif current[4] == 'remove':
813 self["key_green"].setText(_("Undo\nRemove"))
814 elif current[4] == 'install':
815 self["key_green"].setText(_("Undo\nInstall"))
816 self["key_yellow"].setText(_("View details"))
817 self["key_blue"].setText("")
818 if len(self.selectedFiles) == 0 and self.available_updates is not 0:
819 self["status"].setText(_("There are at least ") + str(self.available_updates) + _(" updates available."))
820 elif len(self.selectedFiles) is not 0:
821 self["status"].setText(str(len(self.selectedFiles)) + _(" packages selected."))
823 self["status"].setText(_("There is nothing to be done."))
824 elif self.currList == "category":
825 self["key_red"].setText(_("Close"))
826 self["key_green"].setText("")
827 self["key_yellow"].setText("")
828 self["key_blue"].setText("")
829 if len(self.selectedFiles) == 0 and self.available_updates is not 0:
830 self["status"].setText(_("There are at least ") + str(self.available_updates) + _(" updates available."))
831 self["key_yellow"].setText(_("Update"))
832 elif len(self.selectedFiles) is not 0:
833 self["status"].setText(str(len(self.selectedFiles)) + _(" packages selected."))
834 self["key_yellow"].setText(_("Process"))
836 self["status"].setText(_("There is nothing to be done."))
838 def getSelectionState(self, detailsFile):
839 for entry in self.selectedFiles:
840 if entry[0] == detailsFile:
844 def rebuildList(self):
845 self.setState('update')
846 if not PluginManager.lastDownloadDate or (time() - PluginManager.lastDownloadDate) > 3600:
847 # Only update from internet once per hour
848 PluginManager.lastDownloadDate = time()
849 print "last update time > 1h"
850 self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
852 print "last update time < 1h"
855 def ipkgCallback(self, event, param):
856 if event == IpkgComponent.EVENT_ERROR:
857 self.list_updating = False
858 self.setState('error')
859 elif event == IpkgComponent.EVENT_DONE:
863 def startIpkgList(self):
864 if self.list_updating:
866 self.Console = Console()
868 self.Console.ePopen(cmd, self.IpkgList_Finished)
870 def IpkgList_Finished(self, result, retval, extra_args = None):
872 self.available_packetlist = []
873 for x in result.splitlines():
874 split = x.split(' - ')
875 if not any(split[0].strip().endswith(x) for x in self.unwanted_extensions):
876 self.available_packetlist.append([split[0].strip(), split[1].strip(), split[2].strip()])
877 self.startInstallMetaPackage()
879 def startInstallMetaPackage(self):
880 if self.list_updating:
881 self.list_updating = False
883 self.Console = Console()
884 cmd = "ipkg install enigma2-meta" #dummy,will change probably"
885 self.Console.ePopen(cmd, self.InstallMetaPackage_Finished)
887 def InstallMetaPackage_Finished(self, result, retval, extra_args = None):
889 self.fillPackagesIndexList()
891 self.Console = Console()
892 self.setState('sync')
893 cmd = "ipkg list_installed"
894 self.Console.ePopen(cmd, self.IpkgListInstalled_Finished)
896 def IpkgListInstalled_Finished(self, result, retval, extra_args = None):
898 self.installed_packetlist = {}
899 for x in result.splitlines():
900 split = x.split(' - ')
901 if not any(split[0].strip().endswith(x) for x in self.unwanted_extensions):
902 self.installed_packetlist[split[0].strip()] = split[1].strip()
904 if self.currentSelectedTag is None:
905 self.buildCategoryList()
907 self.buildPacketList(self.currentSelectedTag)
909 def countUpdates(self):
910 self.available_updates = 0
911 for package in self.packagesIndexlist[:]:
912 attributes = package[0]["attributes"]
913 packagename = attributes["packagename"]
914 for x in self.available_packetlist:
915 if x[0].strip() == packagename:
916 if self.installed_packetlist.has_key(packagename):
917 if self.installed_packetlist[packagename] != x[1].strip():
918 self.available_updates +=1
920 def handleCurrent(self):
921 current = self["list"].getCurrent()
923 if self.currList == "category":
924 self.currentSelectedIndex = self["list"].index
925 selectedTag = current[2]
926 self.buildPacketList(selectedTag)
927 elif self.currList == "packages":
928 if current[7] is not '':
929 idx = self["list"].getIndex()
930 detailsFile = self.list[idx][1]
931 if self.list[idx][7] == True:
932 for entry in self.selectedFiles:
933 if entry[0] == detailsFile:
934 self.selectedFiles.remove(entry)
936 alreadyinList = False
937 for entry in self.selectedFiles:
938 if entry[0] == detailsFile:
940 if not alreadyinList:
941 self.selectedFiles.append((detailsFile,current[4],current[3]))
942 if current[4] == 'installed':
943 self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'remove', True)
944 elif current[4] == 'installable':
945 self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'install', True)
946 elif current[4] == 'remove':
947 self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'installed', False)
948 elif current[4] == 'install':
949 self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'installable',False)
950 self["list"].setList(self.list)
951 self["list"].setIndex(idx)
952 self["list"].updateList(self.list)
953 self.selectionChanged()
955 def handleSelected(self):
956 current = self["list"].getCurrent()
958 if self.currList == "packages":
959 if current[7] is not '':
960 detailsfile = self.directory[0] + "/" + current[1]
961 if (os_path.exists(detailsfile) == True):
962 self.session.openWithCallback(self.detailsClosed, PluginDetails, self.skin_path, current)
964 self.session.open(MessageBox, _("Sorry, no Details available!"), MessageBox.TYPE_INFO, timeout = 10)
965 elif self.currList == "category":
966 self.prepareInstall()
967 if len(self.cmdList):
968 self.session.openWithCallback(self.runExecute, PluginManagerInfo, self.skin_path, self.cmdList)
970 def detailsClosed(self, result):
973 self.Console = Console()
974 self.setState('sync')
975 PluginManager.lastDownloadDate = time()
976 self.selectedFiles = []
978 self.Console.ePopen(cmd, self.InstallMetaPackage_Finished)
980 def buildEntryComponent(self, name, details, description, packagename, state, selected = False):
981 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/div-h.png"))
982 if state == 'installed':
983 installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/installed.png"))
984 return((name, details, description, packagename, state, installedpng, divpng, selected))
985 elif state == 'installable':
986 installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/installable.png"))
987 return((name, details, description, packagename, state, installablepng, divpng, selected))
988 elif state == 'remove':
989 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/remove.png"))
990 return((name, details, description, packagename, state, removepng, divpng, selected))
991 elif state == 'install':
992 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/install.png"))
993 return((name, details, description, packagename, state, installpng, divpng, selected))
995 def buildPacketList(self, categorytag = None):
996 if categorytag is not None:
997 self.currList = "packages"
998 self.currentSelectedTag = categorytag
1000 for package in self.packagesIndexlist[:]:
1001 prerequisites = package[0]["prerequisites"]
1002 if prerequisites.has_key("tag"):
1003 for foundtag in prerequisites["tag"]:
1004 if categorytag == foundtag:
1005 attributes = package[0]["attributes"]
1006 if attributes.has_key("packagetype"):
1007 if attributes["packagetype"] == "internal":
1009 self.packetlist.append([attributes["name"], attributes["details"], attributes["shortdescription"], attributes["packagename"]])
1011 self.packetlist.append([attributes["name"], attributes["details"], attributes["shortdescription"], attributes["packagename"]])
1013 for x in self.packetlist:
1015 selectState = self.getSelectionState(x[1].strip())
1016 if self.installed_packetlist.has_key(x[3].strip()):
1017 if selectState == True:
1020 status = "installed"
1021 self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), x[3].strip(), status, selected = selectState))
1023 if selectState == True:
1026 status = "installable"
1027 self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), x[3].strip(), status, selected = selectState))
1029 self.list.sort(key=lambda x: x[0])
1030 self["list"].style = "default"
1031 self['list'].setList(self.list)
1032 self["list"].updateList(self.list)
1033 self.selectionChanged()
1035 def buildCategoryList(self):
1036 self.currList = "category"
1037 self.categories = []
1038 self.categoryList = []
1039 for package in self.packagesIndexlist[:]:
1040 prerequisites = package[0]["prerequisites"]
1041 if prerequisites.has_key("tag"):
1042 for foundtag in prerequisites["tag"]:
1043 attributes = package[0]["attributes"]
1044 if foundtag not in self.categories:
1045 self.categories.append(foundtag)
1046 self.categoryList.append(self.buildCategoryComponent(foundtag))
1047 self.categoryList.sort(key=lambda x: x[0])
1048 self["list"].style = "category"
1049 self['list'].setList(self.categoryList)
1050 self["list"].updateList(self.categoryList)
1051 self.selectionChanged()
1053 def buildCategoryComponent(self, tag = None):
1054 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/div-h.png"))
1057 return(( _("System"), _("View list of available system extensions" ), tag, divpng ))
1059 return(( _("Skins"), _("View list of available skins" ), tag, divpng ))
1060 elif tag == 'Recording':
1061 return(( _("Recordings"), _("View list of available recording extensions" ), tag, divpng ))
1062 elif tag == 'Network':
1063 return(( _("Network"), _("View list of available networking extensions" ), tag, divpng ))
1065 return(( _("CommonInterface"), _("View list of available CommonInterface extensions" ), tag, divpng ))
1066 elif tag == 'Default':
1067 return(( _("Default Settings"), _("View list of available default settings" ), tag, divpng ))
1069 return(( _("Satteliteequipment"), _("View list of available Satteliteequipment extensions." ), tag, divpng ))
1070 elif tag == 'Software':
1071 return(( _("Software"), _("View list of available software extensions" ), tag, divpng ))
1072 elif tag == 'Multimedia':
1073 return(( _("Multimedia"), _("View list of available multimedia extensions." ), tag, divpng ))
1074 elif tag == 'Display':
1075 return(( _("Display and Userinterface"), _("View list of available Display and Userinterface extensions." ), tag, divpng ))
1077 return(( _("Electronic Program Guide"), _("View list of available EPG extensions." ), tag, divpng ))
1078 elif tag == 'Communication':
1079 return(( _("Communication"), _("View list of available communication extensions." ), tag, divpng ))
1080 else: # dynamically generate non existent tags
1081 return(( str(tag), _("View list of available ") + str(tag) + _(" extensions." ), tag, divpng ))
1083 def prepareInstall(self):
1085 if self.available_updates > 0:
1086 self.cmdList.append((IpkgComponent.CMD_UPGRADE, { "test_only": False }))
1087 if self.selectedFiles and len(self.selectedFiles):
1088 for plugin in self.selectedFiles:
1089 detailsfile = self.directory[0] + "/" + plugin[0]
1090 if (os_path.exists(detailsfile) == True):
1091 self.fillPackageDetails(plugin[0])
1092 self.package = self.packageDetails[0]
1093 if self.package[0].has_key("attributes"):
1094 self.attributes = self.package[0]["attributes"]
1095 if self.attributes.has_key("package"):
1096 self.packagefiles = self.attributes["package"]
1097 if plugin[1] == 'installed':
1098 if self.packagefiles:
1099 for package in self.packagefiles[:]:
1100 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package["name"] }))
1102 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": plugin[2] }))
1104 if self.packagefiles:
1105 for package in self.packagefiles[:]:
1106 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package["name"] }))
1108 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": plugin[2] }))
1110 if plugin[1] == 'installed':
1111 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": plugin[2] }))
1113 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": plugin[2] }))
1115 def runExecute(self, result):
1117 self.session.openWithCallback(self.runExecuteFinished, Ipkg, cmdList = self.cmdList)
1121 def runExecuteFinished(self):
1122 self.session.openWithCallback(self.ExecuteReboot, MessageBox, _("Install or remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1124 def ExecuteReboot(self, result):
1128 self.reloadPluginlist()
1129 self.detailsClosed(True)
1133 def reloadPluginlist(self):
1134 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
1137 class PluginManagerInfo(Screen):
1139 <screen name="PluginManagerInfo" position="center,center" size="560,440" title="Plugin manager activity information" >
1140 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1141 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1142 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
1143 <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
1144 <widget source="list" render="Listbox" position="5,50" size="550,350" scrollbarMode="showOnDemand" selectionDisabled="1">
1145 <convert type="TemplatedMultiContent">
1147 MultiContentEntryText(pos = (50, 1), size = (150, 24), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
1148 MultiContentEntryText(pos = (50, 25), size = (540, 24), font=1, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the state
1149 MultiContentEntryPixmapAlphaTest(pos = (0, 1), size = (48, 48), png = 2), # index 2 is the status pixmap
1150 MultiContentEntryPixmapAlphaTest(pos = (0, 49), size = (550, 2), png = 3), # index 3 is the div pixmap
1152 "fonts": [gFont("Regular", 22),gFont("Regular", 18)],
1157 <ePixmap pixmap="skin_default/div-h.png" position="0,410" zPosition="10" size="560,2" transparent="1" alphatest="on" />
1158 <widget source="status" render="Label" position="5,420" zPosition="10" size="550,30" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
1161 def __init__(self, session, plugin_path, cmdlist = None):
1162 Screen.__init__(self, session)
1163 self.session = session
1164 self.skin_path = plugin_path
1165 self.cmdlist = cmdlist
1167 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
1172 "green": self.process,
1176 self["list"] = List(self.list)
1177 self["key_red"] = StaticText(_("Cancel"))
1178 self["key_green"] = StaticText(_("Continue"))
1179 self["status"] = StaticText(_("Following tasks will be done after you press continue!"))
1181 self.onShown.append(self.setWindowTitle)
1182 self.onLayoutFinish.append(self.rebuildList)
1184 def setWindowTitle(self):
1185 self.setTitle(_("Plugin manager activity information"))
1187 def rebuildList(self):
1189 if self.cmdlist is not None:
1190 for entry in self.cmdlist:
1202 info = args['package']
1204 info = args['package']
1206 info = _("Dreambox software because updates are available.")
1208 self.list.append(self.buildEntryComponent(action,info))
1209 self['list'].setList(self.list)
1210 self['list'].updateList(self.list)
1212 def buildEntryComponent(self, action,info):
1213 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/div-h.png"))
1214 upgradepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/upgrade.png"))
1215 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/install.png"))
1216 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/remove.png"))
1217 if action == 'install':
1218 return(( _('Installing'), info, installpng, divpng))
1219 elif action == 'remove':
1220 return(( _('Removeing'), info, removepng, divpng))
1222 return(( _('Upgradeing'), info, upgradepng, divpng))
1231 class PluginManagerHelp(Screen):
1233 <screen name="PluginManagerHelp" position="center,center" size="560,440" title="Plugin manager help" >
1234 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1235 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
1236 <widget source="list" render="Listbox" position="5,50" size="550,350" scrollbarMode="showOnDemand" selectionDisabled="1">
1237 <convert type="TemplatedMultiContent">
1239 MultiContentEntryText(pos = (50, 1), size = (540, 24), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
1240 MultiContentEntryText(pos = (50, 25), size = (540, 24), font=1, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the state
1241 MultiContentEntryPixmapAlphaTest(pos = (0, 1), size = (48, 48), png = 2), # index 2 is the status pixmap
1242 MultiContentEntryPixmapAlphaTest(pos = (0, 49), size = (550, 2), png = 3), # index 3 is the div pixmap
1244 "fonts": [gFont("Regular", 22),gFont("Regular", 18)],
1249 <ePixmap pixmap="skin_default/div-h.png" position="0,410" zPosition="10" size="550,2" transparent="1" alphatest="on" />
1250 <widget source="status" render="Label" position="5,420" zPosition="10" size="550,30" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
1253 def __init__(self, session, plugin_path):
1254 Screen.__init__(self, session)
1255 self.session = session
1256 self.skin_path = plugin_path
1258 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
1265 self["list"] = List(self.list)
1266 self["key_red"] = StaticText(_("Close"))
1267 self["status"] = StaticText(_("A small overview of the available icon states and actions."))
1269 self.onShown.append(self.setWindowTitle)
1270 self.onLayoutFinish.append(self.rebuildList)
1272 def setWindowTitle(self):
1273 self.setTitle(_("Plugin manager help"))
1275 def rebuildList(self):
1277 self.list.append(self.buildEntryComponent('install'))
1278 self.list.append(self.buildEntryComponent('installable'))
1279 self.list.append(self.buildEntryComponent('installed'))
1280 self.list.append(self.buildEntryComponent('remove'))
1281 self['list'].setList(self.list)
1282 self['list'].updateList(self.list)
1284 def buildEntryComponent(self, state):
1285 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/div-h.png"))
1286 installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/installed.png"))
1287 installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/installable.png"))
1288 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/remove.png"))
1289 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/install.png"))
1291 if state == 'installed':
1292 return(( _('This plugin is installed.'), _('You can remove this plugin.'), installedpng, divpng))
1293 elif state == 'installable':
1294 return(( _('This plugin is not installed.'), _('You can install this plugin.'), installablepng, divpng))
1295 elif state == 'install':
1296 return(( _('This plugin will be installed.'), _('You can cancel the installation.'), installpng, divpng))
1297 elif state == 'remove':
1298 return(( _('This plugin will be removed.'), _('You can cancel the removal.'), removepng, divpng))
1304 class PluginDetails(Screen, DreamInfoHandler):
1306 <screen name="PluginDetails" position="center,center" size="600,440" title="Plugin details" >
1307 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1308 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1309 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
1310 <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
1311 <widget source="author" render="Label" position="10,50" size="500,25" zPosition="10" font="Regular;21" transparent="1" />
1312 <widget name="statuspic" position="550,40" size="48,48" alphatest="on"/>
1313 <widget name="divpic" position="0,80" size="600,2" alphatest="on"/>
1314 <widget name="detailtext" position="10,90" size="270,330" zPosition="10" font="Regular;21" transparent="1" halign="left" valign="top"/>
1315 <widget name="screenshot" position="290,90" size="300,330" alphatest="on"/>
1317 def __init__(self, session, plugin_path, packagedata = None):
1318 Screen.__init__(self, session)
1319 self.skin_path = plugin_path
1320 self.language = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
1321 self.attributes = None
1322 self.translatedAttributes = None
1323 DreamInfoHandler.__init__(self, self.statusCallback, blocking = False, language = self.language)
1324 self.directory = resolveFilename(SCOPE_METADIR)
1326 self.pluginname = packagedata[0]
1327 self.details = packagedata[1]
1328 self.pluginstate = packagedata[4]
1329 self.statuspicinstance = packagedata[5]
1330 self.divpicinstance = packagedata[6]
1331 self.fillPackageDetails(self.details)
1335 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
1341 "down": self.pageDown,
1342 "left": self.pageUp,
1343 "right": self.pageDown,
1346 self["key_red"] = StaticText(_("Close"))
1347 self["key_green"] = StaticText("")
1348 self["author"] = StaticText()
1349 self["statuspic"] = Pixmap()
1350 self["divpic"] = Pixmap()
1351 self["screenshot"] = Pixmap()
1352 self["detailtext"] = ScrollLabel()
1354 self["statuspic"].hide()
1355 self["screenshot"].hide()
1356 self["divpic"].hide()
1358 self.package = self.packageDetails[0]
1359 if self.package[0].has_key("attributes"):
1360 self.attributes = self.package[0]["attributes"]
1361 if self.package[0].has_key("translation"):
1362 self.translatedAttributes = self.package[0]["translation"]
1365 self.oktext = _("\nAfter pressing OK, please wait!")
1366 self.picload = ePicLoad()
1367 self.picload.PictureData.get().append(self.paintScreenshotPixmapCB)
1368 self.onShown.append(self.setWindowTitle)
1369 self.onLayoutFinish.append(self.setInfos)
1371 def setWindowTitle(self):
1372 self.setTitle(_("Package details for: " + self.pluginname))
1378 self["detailtext"].pageUp()
1381 self["detailtext"].pageDown()
1383 def statusCallback(self, status, progress):
1387 if self.translatedAttributes.has_key("name"):
1388 self.pluginname = self.translatedAttributes["name"]
1389 elif self.attributes.has_key("name"):
1390 self.pluginname = self.attributes["name"]
1392 self.pluginname = _("unknown")
1394 if self.translatedAttributes.has_key("author"):
1395 self.author = self.translatedAttributes["author"]
1396 elif self.attributes.has_key("author"):
1397 self.author = self.attributes["author"]
1399 self.author = _("unknown")
1401 if self.translatedAttributes.has_key("description"):
1402 self.description = self.translatedAttributes["description"]
1403 elif self.attributes.has_key("description"):
1404 self.description = self.attributes["description"]
1406 self.description = _("No description available.")
1408 if self.translatedAttributes.has_key("screenshot"):
1409 self.loadThumbnail(self.translatedAttributes)
1411 self.loadThumbnail(self.attributes)
1413 self["author"].setText(_("Author: ") + self.author)
1414 self["detailtext"].setText(self.description.strip())
1415 if self.pluginstate == 'installable':
1416 self["key_green"].setText(_("Install"))
1418 self["key_green"].setText(_("Remove"))
1420 def loadThumbnail(self, entry):
1422 if entry.has_key("screenshot"):
1423 thumbnailUrl = entry["screenshot"]
1424 if thumbnailUrl is not None:
1425 self.thumbnail = "/tmp/" + thumbnailUrl.split('/')[-1]
1426 print "[PluginDetails] downloading screenshot " + thumbnailUrl + " to " + self.thumbnail
1427 client.downloadPage(thumbnailUrl,self.thumbnail).addCallback(self.setThumbnail).addErrback(self.fetchFailed)
1429 self.setThumbnail(noScreenshot = True)
1431 def setThumbnail(self, noScreenshot = False):
1432 if not noScreenshot:
1433 filename = self.thumbnail
1435 filename = resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/noprev.png")
1437 sc = AVSwitch().getFramebufferScale()
1438 self.picload.setPara((self["screenshot"].instance.size().width(), self["screenshot"].instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
1439 self.picload.startDecode(filename)
1441 if self.statuspicinstance != None:
1442 self["statuspic"].instance.setPixmap(self.statuspicinstance.__deref__())
1443 self["statuspic"].show()
1444 if self.divpicinstance != None:
1445 self["divpic"].instance.setPixmap(self.divpicinstance.__deref__())
1446 self["divpic"].show()
1448 def paintScreenshotPixmapCB(self, picInfo=None):
1449 ptr = self.picload.getData()
1451 self["screenshot"].instance.setPixmap(ptr.__deref__())
1452 self["screenshot"].show()
1454 self.setThumbnail(noScreenshot = True)
1457 if self.attributes.has_key("package"):
1458 self.packagefiles = self.attributes["package"]
1460 if self.pluginstate == 'installed':
1461 if self.packagefiles:
1462 for package in self.packagefiles[:]:
1463 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package["name"] }))
1464 if len(self.cmdList):
1465 self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n") + self.pluginname + "\n" + self.oktext)
1467 if self.packagefiles:
1468 for package in self.packagefiles[:]:
1469 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package["name"] }))
1470 if len(self.cmdList):
1471 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n") + self.pluginname + "\n" + self.oktext)
1473 def runUpgrade(self, result):
1475 self.session.openWithCallback(self.runUpgradeFinished, Ipkg, cmdList = self.cmdList)
1477 def runUpgradeFinished(self):
1478 self.session.openWithCallback(self.UpgradeReboot, MessageBox, _("Installation finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1480 def UpgradeReboot(self, result):
1488 def runRemove(self, result):
1490 self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
1492 def runRemoveFinished(self):
1493 self.session.openWithCallback(self.RemoveReboot, MessageBox, _("Remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1495 def RemoveReboot(self, result):
1503 def reloadPluginlist(self):
1504 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
1506 def fetchFailed(self,string):
1507 self.setThumbnail(noScreenshot = True)
1508 print "[PluginDetails] fetch failed " + string.getErrorMessage()
1511 class UpdatePlugin(Screen):
1513 <screen name="UpdatePlugin" position="center,center" size="550,200" title="Software update" >
1514 <widget name="activityslider" position="0,0" size="550,5" />
1515 <widget name="slider" position="0,150" size="550,30" />
1516 <widget source="package" render="Label" position="10,30" size="540,20" font="Regular;18" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
1517 <widget source="status" render="Label" position="10,60" size="540,45" font="Regular;20" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
1520 def __init__(self, session, args = None):
1521 Screen.__init__(self, session)
1523 self.sliderPackages = { "dreambox-dvb-modules": 1, "enigma2": 2, "tuxbox-image-info": 3 }
1525 self.slider = Slider(0, 4)
1526 self["slider"] = self.slider
1527 self.activityslider = Slider(0, 100)
1528 self["activityslider"] = self.activityslider
1529 self.status = StaticText(_("Upgrading Dreambox... Please wait"))
1530 self["status"] = self.status
1531 self.package = StaticText()
1532 self["package"] = self.package
1538 self.activityTimer = eTimer()
1539 self.activityTimer.callback.append(self.doActivityTimer)
1540 self.activityTimer.start(100, False)
1542 self.ipkg = IpkgComponent()
1543 self.ipkg.addCallback(self.ipkgCallback)
1545 self.updating = True
1546 self.package.setText(_("Package list update"))
1547 self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
1549 self["actions"] = ActionMap(["WizardActions"],
1555 def doActivityTimer(self):
1557 if self.activity == 100:
1559 self.activityslider.setValue(self.activity)
1561 def ipkgCallback(self, event, param):
1562 if event == IpkgComponent.EVENT_DOWNLOAD:
1563 self.status.setText(_("Downloading"))
1564 elif event == IpkgComponent.EVENT_UPGRADE:
1565 if self.sliderPackages.has_key(param):
1566 self.slider.setValue(self.sliderPackages[param])
1567 self.package.setText(param)
1568 self.status.setText(_("Upgrading"))
1570 elif event == IpkgComponent.EVENT_INSTALL:
1571 self.package.setText(param)
1572 self.status.setText(_("Installing"))
1574 elif event == IpkgComponent.EVENT_CONFIGURING:
1575 self.package.setText(param)
1576 self.status.setText(_("Configuring"))
1577 elif event == IpkgComponent.EVENT_MODIFIED:
1578 self.session.openWithCallback(
1579 self.modificationCallback,
1581 _("A configuration file (%s) was modified since Installation.\nDo you want to keep your version?") % (param)
1583 elif event == IpkgComponent.EVENT_ERROR:
1585 elif event == IpkgComponent.EVENT_DONE:
1587 self.updating = False
1588 self.ipkg.startCmd(IpkgComponent.CMD_UPGRADE, args = {'test_only': False})
1589 elif self.error == 0:
1590 self.slider.setValue(4)
1592 self.activityTimer.stop()
1593 self.activityslider.setValue(0)
1595 self.package.setText("")
1596 self.status.setText(_("Done - Installed or upgraded %d packages") % self.packages)
1598 self.activityTimer.stop()
1599 self.activityslider.setValue(0)
1600 error = _("your dreambox might be unusable now. Please consult the manual for further assistance before rebooting your dreambox.")
1601 if self.packages == 0:
1602 error = _("No packages were upgraded yet. So you can check your network and try again.")
1604 error = _("Your dreambox isn't connected to the internet properly. Please check it and try again.")
1605 self.status.setText(_("Error") + " - " + error)
1606 #print event, "-", param
1609 def modificationCallback(self, res):
1610 self.ipkg.write(res and "N" or "Y")
1613 if not self.ipkg.isRunning():
1614 if self.packages != 0 and self.error == 0:
1615 self.session.openWithCallback(self.exitAnswer, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"))
1619 def exitAnswer(self, result):
1620 if result is not None and result:
1625 class IpkgInstaller(Screen):
1627 <screen name="IpkgInstaller" position="center,center" size="550,450" title="Install extensions" >
1628 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1629 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1630 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
1631 <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
1632 <widget name="list" position="5,50" size="540,360" />
1633 <ePixmap pixmap="skin_default/div-h.png" position="0,410" zPosition="10" size="560,2" transparent="1" alphatest="on" />
1634 <widget source="introduction" render="Label" position="5,420" zPosition="10" size="550,30" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
1637 def __init__(self, session, list):
1638 Screen.__init__(self, session)
1640 self.list = SelectionList()
1641 self["list"] = self.list
1642 for listindex in range(len(list)):
1643 self.list.addSelection(list[listindex], list[listindex], listindex, True)
1645 self["key_red"] = StaticText(_("Close"))
1646 self["key_green"] = StaticText(_("Install"))
1647 self["introduction"] = StaticText(_("Press OK to toggle the selection."))
1649 self["actions"] = ActionMap(["OkCancelActions", "ColorActions"],
1651 "ok": self.list.toggleSelection,
1652 "cancel": self.close,
1654 "green": self.install
1658 list = self.list.getSelectionsList()
1661 cmdList.append((IpkgComponent.CMD_INSTALL, { "package": item[1] }))
1662 self.session.open(Ipkg, cmdList = cmdList)
1665 def filescan_open(list, session, **kwargs):
1666 filelist = [x.path for x in list]
1667 session.open(IpkgInstaller, filelist) # list
1669 def filescan(**kwargs):
1670 from Components.Scanner import Scanner, ScanPath
1672 Scanner(mimetypes = ["application/x-debian-package"],
1675 ScanPath(path = "ipk", with_subdirs = True),
1676 ScanPath(path = "", with_subdirs = False),
1679 description = _("Install extensions."),
1680 openfnc = filescan_open, )
1684 def UpgradeMain(session, **kwargs):
1685 session.open(UpdatePluginMenu)
1687 def startSetup(menuid):
1688 if menuid != "setup":
1690 return [(_("Software manager"), UpgradeMain, "software_manager", 50)]
1692 def Plugins(path, **kwargs):
1696 PluginDescriptor(name=_("Software manager"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_MENU, fnc=startSetup),
1697 PluginDescriptor(name=_("Ipkg"), where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)
1699 if config.usage.setup_level.index >= 2: # expert+
1700 list.append(PluginDescriptor(name=_("Software manager"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=UpgradeMain))