revert picture background to old behavior
[vuplus_dvbapp-plugin] / webcamviewer / src / plugin.py
1 from enigma import eListbox
2 from enigma import eListboxPythonMultiContent
3 from enigma import ePicLoad
4 from enigma import loadPNG
5 from enigma import gFont
6 ### Picturelist
7 from Screens.Screen import Screen
8 from Screens.MessageBox import MessageBox
9 from Screens.InputBox import InputBox
10 from Screens.ChoiceBox import ChoiceBox
11 from Components.ActionMap import ActionMap
12 from Components.Label import Label
13 from Components.MenuList import MenuList
14 from Components.FileList import EXTENSIONS
15 ## configmenu
16 from Components.config import config, ConfigSubsection,ConfigSelection,ConfigText,ConfigYesNo
17 ####
18 from Components.Input import Input
19 from Components.Pixmap import Pixmap
20 from Plugins.Plugin import PluginDescriptor
21 ### System
22 import os
23 from re import compile
24 ## XML
25 from pyexpat import ExpatError
26 import xml.dom.minidom
27 from Tools.XMLTools import elementsWithTag
28
29 ### my
30 from WebcamViewConfig import WebcamViewerMenu
31 from PictureScreen import PictureScreen
32 ###
33 myname = "Webcam/Picture Viewer"
34 myversion = "1.1"
35
36 config.plugins.pictureviewer = ConfigSubsection()
37 config.plugins.pictureviewer.slideshowtime = ConfigSelection(default="5000", choices = [("5000", _("5 Sekunden")), ("10000", _("10 Sekunden")), ("20000", _("20 Sekunden")), ("60000", _("1 Minute"))])
38 config.plugins.pictureviewer.slideshowmode = ConfigSelection(default="0", choices = [("0", _("normal")), ("1", _("endlos"))])
39 #not editable configs
40 config.plugins.pictureviewer.slideshowext = ConfigText(default=".3ssl")
41 config.plugins.pictureviewer.matchingPattern = ConfigText(default="(?i)^.*\.(jpeg|jpg|jpe|png|bmp|gif)")
42 config.plugins.pictureviewer.slideshowdir = ConfigText(default="/media/hdd/slideshows/")
43 config.plugins.pictureviewer.rootdir = ConfigText(default="/media/")
44 config.plugins.pictureviewer.stopserviceonstart = ConfigYesNo(default = False)
45 SLIDESHOWMODE_NORMAL = 0
46 SLIDESHOWMODE_REPEAT = 1
47
48 originalservice = None
49 mysession = None
50
51 def main1(session, **kwargs):
52         global originalservice, mysession
53         mysession = session
54         originalservice = session.nav.getCurrentlyPlayingServiceReference()
55         if config.plugins.pictureviewer.stopserviceonstart.value:
56                 session.nav.stopService()
57         session.openWithCallback(mainCB, PictureViewer)
58
59 def main2(session, **kwargs):
60         global originalservice, mysession
61         mysession = session
62         originalservice = session.nav.getCurrentlyPlayingServiceReference()
63         if config.plugins.pictureviewer.stopserviceonstart.value:
64                 session.nav.stopService()
65         xmlfile = "/usr/lib/enigma2/python/Plugins/Extensions/WebcamViewer/webcam.xml"
66         if os.path.isfile(xmlfile):
67                 try:
68                         xmlnode = xml.dom.minidom.parse(open(xmlfile))
69                         session.openWithCallback(mainCB, WebcamViewer, xmlnode.childNodes[1])
70                 except ExpatError,e:
71                         session.open(
72                                 MessageBox,
73                                 _("Loading config file failed!\n\n%s") % e,
74                                 MessageBox.TYPE_WARNING
75                         )
76         else:
77                 session.open(
78                         MessageBox,
79                         _("Loading config file failed!\n\nconfigfile not found!"),
80                         MessageBox.TYPE_WARNING
81                 )
82
83 def mainCB():
84         global originalservice, mysession
85         if config.plugins.pictureviewer.stopserviceonstart.value:
86                 mysession.nav.playService(originalservice)
87
88 def Plugins(path, **kwargs):
89         p = [
90                         PluginDescriptor(
91                                                         name="PictureViewer",
92                                                         description="browse your local pictures",
93                                                         where = PluginDescriptor.WHERE_PLUGINMENU,
94                                                         fnc = main1,
95                                                         icon="pictureviewer.png"
96                           ),
97                         PluginDescriptor(
98                                                         name="WebcamViewer",
99                                                         description="view webcams around the world",
100                                                         where = PluginDescriptor.WHERE_PLUGINMENU,
101                                                         fnc = main2,
102                                                         icon="webcamviewer.png"
103                         )
104                  ]
105         return p
106
107 ###################
108 class Slideshow:
109         filelist = []
110         currentslideshowitem = 0
111         wbviewer = False
112
113         def __init__(self, session, callback):
114                 self.session = session
115                 self.callback = callback
116
117         def setfiles(self, filelist):
118                 self.filelist = filelist
119
120         def start(self):
121                 if len(self.filelist) > 0:
122                         self.currentslideshowitem = -1
123                         self.nextSlideshowItem()
124
125         def nextSlideshowItem(self):
126                 if self.currentslideshowitem is not (len(self.filelist) - 1):
127                         self.currentslideshowitem = self.currentslideshowitem + 1
128                         filetoshow = self.filelist[self.currentslideshowitem][1]
129                         if not self.wbviewer:
130                                 self.wbviewer = self.session.openWithCallback(
131                                                                         self.cb,
132                                                                         PictureScreen,
133                                                                         filetoshow.split("/")[-1],
134                                                                         filetoshow,
135                                                                         slideshowcallback = self.nextSlideshowItem
136                                 )
137                         else:
138                                 self.wbviewer.filename = filetoshow
139                                 self.wbviewer.do()
140                 elif self.currentslideshowitem is (len(self.filelist) - 1) and int(config.plugins.pictureviewer.slideshowmode.value) is SLIDESHOWMODE_REPEAT:
141                         print "["+myname+"] restarting slideshow"
142                         self.start()
143                 else:
144                         print "["+myname+"] slideshow finished"
145                         self.wbviewer.exit()
146                         self.cb()
147
148         def cb(self):
149                 self.callback()
150 ###################
151 class PictureViewer(Screen):
152         skin = ""
153         filelist = []
154         currList = "slideshowlist"
155         wbviewer = False
156         loadedslideshowlistlistname = False
157
158         def __init__(self, session, args = 0):
159                 skin =  """<screen position="93,70" size="550,450" title="%s">
160                 <widget name="menu" position="1,1" size="275,400"  scrollbarMode="showOnDemand" />
161                 <widget name="pixmap" position="550,450" size="275,200" backgroundColor="red" />
162                 <widget name="slist" position="275,200" size="275,200"  scrollbarMode="showOnDemand" />
163                 <widget name="buttonred" position="6,405" size="130,40" backgroundColor="red" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
164                 <widget name="buttongreen" position="142,405" size="130,40" backgroundColor="green" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
165                 <widget name="buttonyellow" position="278,405" size="130,40" backgroundColor="yellow" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
166                 <widget name="buttonblue" position="414,405" size="130,40" backgroundColor="blue" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
167                 </screen>""" % config.plugins.pictureviewer.rootdir.value
168                 self.skin = skin
169                 Screen.__init__(self, session)
170
171                 self.filelist = PictureList(config.plugins.pictureviewer.rootdir.value, matchingPattern = config.plugins.pictureviewer.matchingPattern.value)
172                 self["menu"] = self.filelist
173
174                 self.picload = ePicLoad()
175                 self.picload.PictureData.get().append(self.updateInfoPanelCB)
176                 self.picload.setPara((275, 200, 1, 1, False, 1, "#ff000000"))
177                 self.preview = Pixmap()
178                 self["pixmap"] = self.preview
179
180                 self.slideshowfiles = []
181                 self.slideshowlist =MenuList(self.slideshowfiles)
182                 self["slist"] = self.slideshowlist
183
184                 self["buttonred"] = Label("")
185                 self["buttongreen"] = Label("")
186                 self["buttonyellow"] = Label("")
187                 self["buttonblue"] = Label("")
188
189                 self["actions"] = ActionMap(["WizardActions", "MenuActions", "DirectionActions", "ShortcutActions"],
190                         {
191                          "ok": self.go,
192                          "back": self.close,
193                          "menu": self.openMenu,
194                          "up": self.up,
195                          "down": self.down,
196                          "left": self.leftUp,
197                          "right": self.rightUp,
198                          "red": self.KeyRed,
199                          "green": self.KeyGreen,
200                          "yellow": self.KeyYellow,
201                          "blue": self.switchList,
202                          }, -1)
203
204                 self.onLayoutFinish.append(self.switchList)
205                 self.onLayoutFinish.append(self.updateInfoPanel)
206
207         def KeyGreen(self):
208                 if self.currList is "filelist":
209                         # adding all files in current dir to slideshowlist
210                         dirname = self["menu"].getCurrentDir()
211                         if os.path.isdir(dirname):
212                                 s = os.listdir(dirname)
213                                 s.sort()
214                                 for file in s:
215                                         if compile(config.plugins.pictureviewer.matchingPattern.value).search(dirname + file):
216                                                 self.slideshowfiles.append((_(file),dirname + file))
217                                 self["slist"].l.setList(self.slideshowfiles)
218                 else:
219                         #loading list
220                         list = []
221                         try:
222                                 for file in os.listdir(config.plugins.pictureviewer.slideshowdir.value):
223                                         if file.endswith(config.plugins.pictureviewer.slideshowext.value):
224                                                 list.append((_(file.split("/")[-1]),file))
225                                 self.session.openWithCallback(
226                                                 self.fileToLoadFilelistEntered,
227                                                 ChoiceBox,
228                                                 _("select List to load"),
229                                                 list
230                                 )
231                         except IOError,e:
232                                 print "["+myname+"] IOError:",e
233                         except OSError,e:
234                                 print "["+myname+"] OSError:",e
235
236         def KeyRed(self):
237                 if self.currList is "filelist" :
238                         #do slideshow
239                         self.hide()
240                         x = Slideshow(self.session, self.show)
241                         x.setfiles(self.slideshowfiles)
242                         x.start()
243                 else:
244                         # save filelist
245                         if not self.loadedslideshowlistlistname:
246                                 newname = "slideshowlist"
247                         else:
248                                 newname = self.loadedslideshowlistlistname
249                         self.session.openWithCallback(
250                                         self.fileToSaveFilelistEntered,
251                                         InputBox,
252                                         title = _("Enter filename to save the List:"),
253                                         text = newname,
254                                         maxSize = False,
255                                         type = Input.TEXT
256                         )
257
258         def fileToLoadFilelistEntered(self, fileselection):
259                 if fileselection is not None:
260                            try:
261                                    filename = fileselection[1]
262                                    fp = open(config.plugins.pictureviewer.slideshowdir.value + filename)
263                                    list = []
264                                    for x in fp.readlines():
265                                            file = x.replace("\n","")
266                                            if x.startswith("#"):
267                                                    pass
268                                            elif not os.path.exists(file):
269                                                    print "["+myname+"] loaded file from filelist isnt avaible! ignoreing ->", file
270                                            else:
271                                                    list.append((_(file.split("/")[-1]), file))
272                                    self.slideshowfiles = list
273                                    self["slist"].l.setList(self.slideshowfiles)
274                                    self.loadedslideshowlistlistname = filename.replace(config.plugins.pictureviewer.slideshowext.value, "")
275                            except IOError, e:
276                                    print "["+myname+"] error:", e
277
278         def fileToSaveFilelistEntered(self, filename):
279                 if filename is not None:
280                         print "["+myname+"] saving list to ", config.plugins.pictureviewer.slideshowdir.value+filename + config.plugins.pictureviewer.slideshowext.value
281                         try:
282                                 if not os.path.exists(config.plugins.pictureviewer.slideshowdir.value):
283                                         print "+" * 10, os.path.basename(filename)
284                                         os.mkdir(config.plugins.pictureviewer.slideshowdir.value)
285                                 fp = open(config.plugins.pictureviewer.slideshowdir.value + filename+config.plugins.pictureviewer.slideshowext.value, "w")
286                                 fp.write("# this is a slideshow file for "+myname+" made by V"+myversion+"\n")
287                                 fp.write("# you can make your own... each line with full path of the imagefile\n")
288                                 fp.write("# by importing this file,we will ignoring a file if is doesnt exist\n")
289                                 for x in self.slideshowfiles:
290                                         fp.write(x[1] + "\n")
291                                 fp.close()
292                         except IOError, e:
293                                 print "["+myname+"] error:", e
294
295         def KeyYellow(self):
296                 if self.currList is "filelist":
297                         # add picture to list
298                         fullfile = self["menu"].getSelection()[0]
299                         if os.path.isfile(fullfile):
300                                 self.slideshowfiles.append((_(fullfile.split("/")[-1]), fullfile))
301                                 self["slist"].l.setList(self.slideshowfiles)
302                 else:
303                         # deleting an Picture
304                         if len(self.slideshowfiles) >= 1:
305                                 indexinlist = self["slist"].l.getCurrentSelectionIndex()
306                                 self.slideshowfiles.pop(indexinlist)
307                                 self["slist"].l.setList(self.slideshowfiles)
308
309         def switchList(self):
310                 if self.currList is "filelist" :
311                         # Slideshow activieren
312                         self.filelist.selectionEnabled(0)
313                         self.slideshowlist.selectionEnabled(1)
314                         self["buttonred"].setText("speichern")
315                         self["buttongreen"].setText("laden")
316                         self["buttonyellow"].setText("loeschen")
317                         self["buttonblue"].setText("Dateien")
318                         self.currList = "slideshowlist"
319                 else:
320                         # filelist activieren
321                         self.filelist.selectionEnabled(1)
322                         self.slideshowlist.selectionEnabled(0)
323                         self["buttonred"].setText("starte Slideshow")
324                         self["buttongreen"].setText("alle hinzufuegen")
325                         self["buttonyellow"].setText("hinzufuegen")
326                         self["buttonblue"].setText("Slideshow bearbeiten")
327                         self.currList = "filelist"
328
329         def go(self):
330                 if self.currList is "filelist" :
331                         selection = self["menu"].getSelection()
332                         if self.filelist.canDescent():
333                                 self.setTitle(selection[0])
334                                 self.filelist.descent()
335                         else:
336                                 if selection[1] == True: # isDir
337                                         pass
338                                 else:
339                                         print "["+myname+"] file selected ", selection[0]
340                                         if os.path.isfile(selection[0]):
341                                                 self.session.open(PictureScreen,selection[0].split("/")[-1], selection[0])
342                                         else:
343                                                 print "["+myname+"] file not found ", selection[0]
344                 else:
345                         self.updateInfoPanel()
346
347         def up(self):
348                  if self.currList is "filelist":
349                          self.filelist.up()
350                          self.updateInfoPanel()
351                  else:
352                          self.slideshowlist.up()
353
354         def leftUp(self):
355                  if self.currList is "filelist":
356                          self.filelist.pageUp()
357                          self.updateInfoPanel()
358                  else:
359                          self.slideshowlist.pageUp()
360
361         def rightUp(self):
362                 if self.currList is "filelist":
363                          self.filelist.pageDown()
364                          self.updateInfoPanel()
365                 else:
366                          self.slideshowlist.pageDown()
367
368         def down(self):
369                  if self.currList is "filelist":
370                          self.filelist.down()
371                          self.updateInfoPanel()
372                  else:
373                          self.slideshowlist.down()
374
375         def updateInfoPanel(self):
376                 if self.currList is "filelist":
377                         selectedfile = self["menu"].getSelection()[0]
378                 else:
379                         selectedfile = self["slist"].l.getCurrentSelection()[1]
380                 self.picload.startDecode(selectedfile)
381
382         def updateInfoPanelCB(self, picInfo = None):
383                 ptr = self.picload.getData()
384                 if ptr is not None:
385                         self["pixmap"].instance.setPixmap(ptr.__deref__())
386                         self["pixmap"].move(275,0)
387                 else:
388                         pass
389
390         def output(self,str):
391                 print "+" * 10, str
392
393         def openMenu(self):
394                 self.session.open(WebcamViewerMenu)
395 ###################
396 class WebcamViewer(Screen):
397         skin = ""
398         filelist = []
399         def __init__(self, session,xmlnode, args = 0):
400                 self.xmlnode = xmlnode
401                 screen_x = 736
402                 screen_y = 576
403                 size_x = 350
404                 size_y = 250
405                 pos_x = (screen_x/2)-(size_x/2)
406                 pos_y = (screen_y/2)-(size_y/2)
407                 skin = """
408                 <screen position="%i,%i" size="%i,%i" title="%s">
409                         <widget name="menu" position="1,1" size="%i,%i"  scrollbarMode="showOnDemand"/>
410                 </screen>""" % (pos_x,pos_y,size_x,size_y,myname,size_x,size_y)
411                 self.skin = skin
412                 Screen.__init__(self, session)
413
414                 self.filelist = MenuList(self.getMenuData())
415                 self["menu"] = self.filelist
416                 self["actions"] = ActionMap(["WizardActions", "DirectionActions"],
417                         {
418                          "ok": self.go,
419                          "back": self.close,
420                          }, -1)
421                 self.onLayoutFinish.append(self.settingTitle)
422
423         def settingTitle(self):
424                 self.setTitle(myname + ": " + self.menutitle)
425
426         def go(self):
427                 selected = self["menu"].l.getCurrentSelection()[1]
428                 menuitemtitle = self["menu"].l.getCurrentSelection()[0]
429                 type = selected[0]
430                 data = selected[1]
431                 if type.startswith("cam"):
432                         self.session.open(PictureScreen, menuitemtitle, data)
433                 else:
434                         self.hide()
435                         self.session.openWithCallback(self.cb, WebcamViewer, data)
436
437         def cb(self):
438                 self.show()
439
440         def getMenuData(self):
441                 xloader = XMLloader()
442                 self.menutitle = xloader.getScreenXMLTitle(self.xmlnode)
443                 data =[]
444                 for node in elementsWithTag(self.xmlnode._get_childNodes(), 'menu'):
445                         nodex = {}
446                         nodex['name'] = xloader.get_txt(node, "name", "no name")
447                         data.append((_("*" + nodex['name']), ["node", node]))
448
449                 for node in elementsWithTag(self.xmlnode._get_childNodes(), 'cam'):
450                         nodex = {}
451                         nodex['name'] = xloader.get_txt(node, "name", "no name")
452                         nodex['url'] =xloader.get_txt(node, "url", "no url")
453                         data.append((_(nodex['name']), ["cam", nodex['url']]))
454                 return data
455 ###################
456
457 ##################
458 class PictureList(MenuList):
459         def __init__(self, directory, matchingPattern = None, enableWrapAround = False):
460                 MenuList.__init__(self, None, enableWrapAround, eListboxPythonMultiContent)
461                 self.showDirectories = True
462                 self.showFiles = True
463                 self.isTop = False
464                 self.matchingPattern = matchingPattern
465                 self.changeDir(directory)
466                 self.l.setFont(0, gFont("Regular", 18))
467                 self.currentDir = directory
468
469         def getCurrentDir(self):
470                 return self.currentDir
471
472         def getSelection(self):
473                 return self.l.getCurrentSelection()[0]
474
475         def getFileList(self):
476                 return self.list
477
478         def changeDir(self, directory):
479                 self.currentDir = directory
480                 self.list = []
481
482                 directories = []
483                 files = []
484                 files = os.listdir(directory)
485                 files.sort()
486                 tmpfiles = files[:]
487                 for x in tmpfiles:
488                         if os.path.isdir(directory + "/" + x):
489                                 directories.append(x)
490                                 files.remove(x)
491                 directories.sort()
492                 files.sort()
493                 if directory != "/" and self.showDirectories and not self.isTop:
494                         self.list.append(self.getPictureEntryComponent("..", '/'.join(directory.split('/')[:-2]) + '/', True))
495
496                 if self.showDirectories:
497                         for x in directories:
498                                 name = (directory+x).split('/')[-1]
499                                 self.list.append(self.getPictureEntryComponent(name, '/'.join(directory.split('/')[:-1]) + '/' + x + '/', True))
500
501                 if self.showFiles:
502                         for x in files:
503                                 path = directory + x
504                                 name = x
505                                 if self.matchingPattern is not None:
506                                         if compile(self.matchingPattern).search(path):
507                                                 self.list.append(self.getPictureEntryComponent(name,path, False))
508                                 else:
509                                         pass
510
511                 self.l.setList(self.list)
512
513         def canDescent(self):
514                 return self.getSelection()[1]
515
516         def descent(self):
517                 self.changeDir(self.getSelection()[0])
518
519         def getFilename(self):
520                 return self.getSelection()[0].getPath()
521
522         def getServiceRef(self):
523                 return self.getSelection()[0]
524
525         def postWidgetCreate(self, instance):
526                 MenuList.postWidgetCreate(self, instance)
527                 instance.setItemHeight(23)
528
529         def getPictureEntryComponent(self,name, absolute, isDir):
530                 """ name={angezeigter Name}, absolute={vollstaendiger Pfad}, isDir={True,False} """
531                 res = [ (absolute, isDir) ]
532                 res.append((eListboxPythonMultiContent.TYPE_TEXT, 35, 1, 200, 20, 0, 0, name))
533                 if isDir:
534                         png = loadPNG("/usr/share/enigma2/extensions/directory.png")
535                 else:
536                         extension = name.split('.')
537                         extension = extension[-1].lower()
538                         if EXTENSIONS.has_key(extension):
539                                 png = loadPNG("/usr/share/enigma2/extensions/" + EXTENSIONS[extension] + ".png")
540                         else:
541                                 png = None
542                 if png is not None:
543                         res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, 10, 2, 20, 20, png))
544                 return res
545
546
547 ##################
548 class XMLloader:
549         DEFAULT_NAMESPACES = (
550                   None, # RSS 0.91, 0.92, 0.93, 0.94, 2.0
551                   'http://purl.org/rss/1.0/', # RSS 1.0
552                   'http://my.netscape.com/rdf/simple/0.9/' # RSS 0.90
553                 )
554         DUBLIN_CORE = ('http://purl.org/dc/elements/1.1/',)
555         def getElementsByTagName(self, node, tagName, possibleNamespaces = DEFAULT_NAMESPACES):
556                 for namespace in possibleNamespaces:
557                         children = node.getElementsByTagNameNS(namespace, tagName)
558                         if len(children):
559                                 return children
560                 return []
561
562         def node_data(self, node, tagName, possibleNamespaces = DEFAULT_NAMESPACES):
563                 children = self.getElementsByTagName(node, tagName, possibleNamespaces)
564                 node = len(children) and children[0] or None
565                 return node and "".join([child.data.encode("utf-8") for child in node.childNodes]) or None
566
567         def get_txt(self, node, tagName, default_txt = ""):
568                 """
569                 Liefert den Inhalt >tagName< des >node< zurueck, ist dieser nicht
570                 vorhanden, wird >default_txt< zurueck gegeben.
571                 """
572                 return self.node_data(node, tagName) or self.node_data(node, tagName, self.DUBLIN_CORE) or default_txt
573
574         def getScreenXMLTitle(self,node):
575                 return self.get_txt(node, "name", "no title")
576