IMDb: fix runtime parsing
[enigma2-plugins.git] / weatherplugin / src / setup.py
1 # -*- coding: utf-8 -*-
2 #
3 # WeatherPlugin E2
4 #
5 # Coded by Dr.Best (c) 2012
6 # Support: www.dreambox-tools.info
7 # E-Mail: dr.best@dreambox-tools.info
8 #
9 # This plugin is open source but it is NOT free software.
10 #
11 # This plugin may only be distributed to and executed on hardware which
12 # is licensed by Dream Property GmbH.
13 # In other words:
14 # It's NOT allowed to distribute any parts of this plugin or its source code in ANY way
15 # to hardware which is NOT licensed by Dream Property GmbH.
16 # It's NOT allowed to execute this plugin and its source code or even parts of it in ANY way
17 # on hardware which is NOT licensed by Dream Property GmbH.
18 #
19 # If you want to use or modify the code or parts of it,
20 # you have to keep MY license and inform me about the modifications by mail.
21 #
22 from enigma import eListboxPythonMultiContent, gFont, RT_HALIGN_LEFT, \
23         RT_VALIGN_CENTER
24 from Screens.Screen import Screen
25 from Screens.MessageBox import MessageBox
26 from Components.MenuList import MenuList
27 from Components.Sources.StaticText import StaticText
28 from Components.ActionMap import ActionMap
29 from Components.ConfigList import ConfigList, ConfigListScreen
30 from Components.config import ConfigSubsection, ConfigText, ConfigSelection, \
31         getConfigListEntry, config, configfile
32 from xml.etree.cElementTree import fromstring as cet_fromstring
33 from twisted.web.client import getPage
34 from urllib import quote as urllib_quote
35 from skin import TemplatedListFonts, componentSizes
36
37 def initWeatherPluginEntryConfig():
38         s = ConfigSubsection()
39         s.city = ConfigText(default = "Heidelberg", visible_width = 100, fixed_size = False)
40         s.degreetype = ConfigSelection(choices = [("C", _("metric system")), ("F", _("imperial system"))], default = "C")
41         s.weatherlocationcode = ConfigText(default = "", visible_width = 100, fixed_size = False)
42         config.plugins.WeatherPlugin.Entry.append(s)
43         return s
44
45 def initConfig():
46         count = config.plugins.WeatherPlugin.entrycount.value
47         if count != 0:
48                 i = 0
49                 while i < count:
50                         initWeatherPluginEntryConfig()
51                         i += 1
52
53 class MSNWeatherPluginEntriesListConfigScreen(Screen):
54         skin = """
55                 <screen name="MSNWeatherPluginEntriesListConfigScreen" position="center,120" size="820,520">
56                         <ePixmap pixmap="skin_default/buttons/red.png" position="10,5" size="200,40" alphatest="on" />
57                 <ePixmap pixmap="skin_default/buttons/green.png" position="210,5" size="200,40" alphatest="on" />
58                 <ePixmap pixmap="skin_default/buttons/yellow.png" position="410,5" size="200,40" alphatest="on" />
59                 <ePixmap pixmap="skin_default/buttons/blue.png" position="610,5" size="200,40" alphatest="on" />
60                 <widget source="key_red" render="Label" position="10,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" shadowColor="black" shadowOffset="-2,-2" />
61                 <widget source="key_green" render="Label" position="210,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" shadowColor="black" shadowOffset="-2,-2" />
62                 <widget source="key_yellow" render="Label" position="410,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" transparent="1" shadowColor="black" shadowOffset="-2,-2" />
63                 <widget source="key_blue" render="Label" position="610,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" transparent="1" shadowColor="black" shadowOffset="-2,-2" />
64                 <eLabel position="10,50" size="800,1" backgroundColor="grey" />
65                 <widget render="Label" source="city" position="15,60" size="500,50" font="Regular;20" halign="left"/>
66                         <widget render="Label" source="degreetype" position="520,60" size="130,50" font="Regular;20" halign="left"/>
67                 <widget name="entrylist" position="10,90" size="800,400" enableWrapAround="1" scrollbarMode="showOnDemand" />
68                 </screen>"""
69
70         def __init__(self, session):
71                 Screen.__init__(self, session)
72                 self.title = _("WeatherPlugin: List of Entries")
73                 self["city"] = StaticText(_("City"))
74                 self["degreetype"] = StaticText(_("System"))
75                 self["key_red"] = StaticText(_("Back"))
76                 self["key_green"] = StaticText(_("Add"))                
77                 self["key_yellow"] = StaticText(_("Edit"))
78                 self["key_blue"] = StaticText(_("Delete"))
79                 self["entrylist"] = WeatherPluginEntryList([])
80                 self["actions"] = ActionMap(["WizardActions","MenuActions","ShortcutActions"],
81                         {
82                          "ok"   :       self.keyOK,
83                          "back" :       self.keyClose,
84                          "red"  :       self.keyClose,
85                          "green":       self.keyGreen,                   
86                          "yellow":      self.keyYellow,
87                          "blue":        self.keyDelete,
88                          }, -1)
89                 self.updateList()
90
91         def updateList(self):
92                 self["entrylist"].buildList()
93
94         def keyClose(self):
95                 self.close(-1, None)
96
97         def keyGreen(self):
98                 self.session.openWithCallback(self.updateList,MSNWeatherPluginEntryConfigScreen,None)
99
100         def keyOK(self):
101                 try:sel = self["entrylist"].l.getCurrentSelection()[0]
102                 except: sel = None
103                 self.close(self["entrylist"].getCurrentIndex(), sel)
104
105         def keyYellow(self):
106                 try:sel = self["entrylist"].l.getCurrentSelection()[0]
107                 except: sel = None
108                 if sel is None:
109                         return
110                 self.session.openWithCallback(self.updateList,MSNWeatherPluginEntryConfigScreen,sel)
111
112         def keyDelete(self):
113                 try:sel = self["entrylist"].l.getCurrentSelection()[0]
114                 except: sel = None
115                 if sel is None:
116                         return
117                 self.session.openWithCallback(self.deleteConfirm, MessageBox, _("Really delete this WeatherPlugin Entry?"))
118
119         def deleteConfirm(self, result):
120                 if not result:
121                         return
122                 sel = self["entrylist"].l.getCurrentSelection()[0]
123                 config.plugins.WeatherPlugin.entrycount.value -= 1
124                 config.plugins.WeatherPlugin.entrycount.save()
125                 config.plugins.WeatherPlugin.Entry.remove(sel)
126                 config.plugins.WeatherPlugin.Entry.save()
127                 config.plugins.WeatherPlugin.save()
128                 configfile.save()
129                 self.updateList()
130
131 class WeatherPluginEntryList(MenuList):
132         SKIN_COMPONENT_KEY = "WeatherPluginList"
133         SKIN_COMPONENT_TEXT_HEIGHT = "textHeight"
134         SKIN_COMPONENT_TEXT_WIDTH = "textWidth"
135         SKIN_COMPONENT_TEXT2_WIDTH = "text2Width"
136         SKIN_COMPONENT_ITEM_MARGIN = "itemMargin"
137
138         def __init__(self, list, enableWrapAround = True):
139                 MenuList.__init__(self, list, enableWrapAround, eListboxPythonMultiContent)
140                 tlf = TemplatedListFonts()
141                 self.l.setFont(0, gFont(tlf.face(tlf.SMALL), tlf.size(tlf.SMALL)))
142
143         def postWidgetCreate(self, instance):
144                 MenuList.postWidgetCreate(self, instance)
145                 instance.setItemHeight(componentSizes.itemHeight(self.SKIN_COMPONENT_KEY, 30))
146
147         def getCurrentIndex(self):
148                 return self.instance.getCurrentIndex()
149
150         def buildList(self):
151                 sizes = componentSizes[WeatherPluginEntryList.SKIN_COMPONENT_KEY]
152                 textHeight = sizes.get(WeatherPluginEntryList.SKIN_COMPONENT_TEXT_HEIGHT, 30)
153                 textWidth = sizes.get(WeatherPluginEntryList.SKIN_COMPONENT_TEXT_WIDTH, 500)
154                 text2Width = sizes.get(WeatherPluginEntryList.SKIN_COMPONENT_TEXT2_WIDTH, 80)   
155                 itemMargin = sizes.get(WeatherPluginEntryList.SKIN_COMPONENT_ITEM_MARGIN, 10)   
156                 list = []
157                 for c in config.plugins.WeatherPlugin.Entry:
158                         res = [
159                                 c,
160                                 (eListboxPythonMultiContent.TYPE_TEXT, 5, 0, textWidth, textHeight, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, str(c.city.value)),
161                                 (eListboxPythonMultiContent.TYPE_TEXT, itemMargin+textWidth, 0, text2Width, textHeight, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, str(c.degreetype .value)),
162                         ]
163                         list.append(res)
164                 self.list = list
165                 self.l.setList(list)
166                 self.moveToIndex(0)
167
168 class MSNWeatherPluginEntryConfigScreen(ConfigListScreen, Screen):
169         skin = """
170                 <screen name="MSNWeatherPluginEntryConfigScreen" position="center,120" size="820,520">
171                         <ePixmap pixmap="skin_default/buttons/red.png" position="10,5" size="200,40" alphatest="on" />
172                 <ePixmap pixmap="skin_default/buttons/green.png" position="210,5" size="200,40" alphatest="on" />
173                 <ePixmap pixmap="skin_default/buttons/yellow.png" position="410,5" size="200,40" alphatest="on" />
174                 <ePixmap pixmap="skin_default/buttons/blue.png" position="610,5" size="200,40" alphatest="on" />
175                 <widget source="key_red" render="Label" position="10,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" shadowColor="black" shadowOffset="-2,-2" />
176                 <widget source="key_green" render="Label" position="210,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" shadowColor="black" shadowOffset="-2,-2" />
177                 <widget source="key_yellow" render="Label" position="410,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" transparent="1" shadowColor="black" shadowOffset="-2,-2" />
178                 <widget source="key_blue" render="Label" position="610,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" transparent="1" shadowColor="black" shadowOffset="-2,-2" />
179                 <eLabel position="10,50" size="800,1" backgroundColor="grey" />
180                 <widget name="config" position="10,60" size="800,450" enableWrapAround="1" scrollbarMode="showOnDemand" />
181                 </screen>"""
182
183         def __init__(self, session, entry):
184                 Screen.__init__(self, session)
185                 self.title = _("WeatherPlugin: Edit Entry")
186                 self["actions"] = ActionMap(["SetupActions", "ColorActions"],
187                 {
188                         "green": self.keySave,
189                         "red": self.keyCancel,
190                         "blue": self.keyDelete,
191                         "yellow": self.searchLocation,
192                         "cancel": self.keyCancel
193                 }, -2)
194
195                 self["key_red"] = StaticText(_("Cancel"))
196                 self["key_green"] = StaticText(_("OK"))
197                 self["key_blue"] = StaticText(_("Delete"))
198                 self["key_yellow"] = StaticText(_("Search Code"))
199
200                 if entry is None:
201                         self.newmode = 1
202                         self.current = initWeatherPluginEntryConfig()
203                 else:
204                         self.newmode = 0
205                         self.current = entry
206
207                 cfglist = [
208                         getConfigListEntry(_("City"), self.current.city),
209                         getConfigListEntry(_("Location code"), self.current.weatherlocationcode),
210                         getConfigListEntry(_("System"), self.current.degreetype)
211                 ]
212
213                 ConfigListScreen.__init__(self, cfglist, session)
214                 
215         def searchLocation(self):
216                 if self.current.city.value != "":
217                         language = config.osd.language.value.replace("_","-")
218                         url = "http://weather.service.msn.com/find.aspx?src=outlook&outputview=search&weasearchstr=%s&culture=%s" % (urllib_quote(self.current.city.value), language)
219                         getPage(url).addCallback(self.xmlCallback).addErrback(self.error)
220                 else:
221                         self.session.open(MessageBox, _("You need to enter a valid city name before you can search for the location code."), MessageBox.TYPE_ERROR)
222
223         def keySave(self):
224                 if self.current.city.value != "" and self.current.weatherlocationcode.value != "":
225                         if self.newmode == 1:
226                                 config.plugins.WeatherPlugin.entrycount.value = config.plugins.WeatherPlugin.entrycount.value + 1
227                                 config.plugins.WeatherPlugin.entrycount.save()
228                         ConfigListScreen.keySave(self)
229                         config.plugins.WeatherPlugin.save()
230                         configfile.save()
231                         self.close()
232                 else:
233                         if self.current.city.value == "":
234                                 self.session.open(MessageBox, _("Please enter a valid city name."), MessageBox.TYPE_ERROR)
235                         else:
236                                 self.session.open(MessageBox, _("Please enter a valid location code for the city."), MessageBox.TYPE_ERROR)
237
238         def keyCancel(self):
239                 if self.newmode == 1:
240                         config.plugins.WeatherPlugin.Entry.remove(self.current)
241                 ConfigListScreen.cancelConfirm(self, True)
242
243         def keyDelete(self):
244                 if self.newmode == 1:
245                         self.keyCancel()
246                 else:           
247                         self.session.openWithCallback(self.deleteConfirm, MessageBox, _("Really delete this WeatherPlugin Entry?"))
248
249         def deleteConfirm(self, result):
250                 if not result:
251                         return
252                 config.plugins.WeatherPlugin.entrycount.value = config.plugins.WeatherPlugin.entrycount.value - 1
253                 config.plugins.WeatherPlugin.entrycount.save()
254                 config.plugins.WeatherPlugin.Entry.remove(self.current)
255                 config.plugins.WeatherPlugin.Entry.save()
256                 config.plugins.WeatherPlugin.save()
257                 configfile.save()
258                 self.close()
259                 
260                 
261         def xmlCallback(self, xmlstring):
262                 if xmlstring:
263                         errormessage = ""
264                         root = cet_fromstring(xmlstring)
265                         for childs in root:
266                                 if childs.tag == "weather" and childs.attrib.has_key("errormessage"):
267                                         errormessage = childs.attrib.get("errormessage").encode("utf-8", 'ignore')
268                                         break
269                         if len(errormessage) !=0:
270                                 self.session.open(MessageBox, errormessage, MessageBox.TYPE_ERROR)                                      
271                         else:
272                                 self.session.openWithCallback(self.searchCallback, MSNWeatherPluginSearch, xmlstring)
273                         
274         def error(self, error = None):
275                 if error is not None:
276                         print error
277                 
278         def searchCallback(self, result):
279                 if result:
280                         self.current.weatherlocationcode.value = result[0]
281                         self.current.city.value = result[1]
282         
283                 
284                 
285 class MSNWeatherPluginSearch(Screen):
286         skin = """
287                 <screen name="MSNWeatherPluginSearch" position="center,120" size="820,520">
288                         <ePixmap pixmap="skin_default/buttons/red.png" position="10,5" size="200,40" alphatest="on" />
289                 <ePixmap pixmap="skin_default/buttons/green.png" position="210,5" size="200,40" alphatest="on" />
290                 <widget source="key_red" render="Label" position="10,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" shadowColor="black" shadowOffset="-2,-2" />
291                 <widget source="key_green" render="Label" position="210,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" shadowColor="black" shadowOffset="-2,-2" />
292                 <eLabel position="10,50" size="800,1" backgroundColor="grey" />
293                 <widget name="entrylist" position="10,60" size="800,450" enableWrapAround="1" scrollbarMode="showOnDemand" />
294                 </screen>""" 
295
296         def __init__(self, session, xmlstring):
297                 Screen.__init__(self, session)
298                 self.title = _("MSN location search result")
299                 self["key_red"] = StaticText(_("Back"))
300                 self["key_green"] = StaticText(_("OK"))         
301                 self["entrylist"] = MSNWeatherPluginSearchResultList([])
302                 self["actions"] = ActionMap(["WizardActions","MenuActions","ShortcutActions"],
303                         {
304                          "ok"   :       self.keyOK,
305                          "green": self.keyOK,
306                          "back" :       self.keyClose,
307                          "red": self.keyClose,
308                          }, -1)
309                 self.updateList(xmlstring)
310
311         def updateList(self, xmlstring):
312                 self["entrylist"].buildList(xmlstring)
313
314         def keyClose(self):
315                 self.close(None)
316
317         def keyOK(self):
318                 pass
319                 try:sel = self["entrylist"].l.getCurrentSelection()[0]
320                 except: sel = None
321                 self.close(sel)
322                 
323
324 class MSNWeatherPluginSearchResultList(MenuList):
325         SKIN_COMPONENT_KEY = "WeatherPluginList"
326         SKIN_COMPONENT_TEXT_HEIGHT = "textHeight"
327         SKIN_COMPONENT_TEXT_WIDTH = "textWidth"
328         SKIN_COMPONENT_LINE_SPACING = "lineSpacing"
329
330         def __init__(self, list, enableWrapAround = True):
331                 MenuList.__init__(self, list, enableWrapAround, eListboxPythonMultiContent)
332                 tlf = TemplatedListFonts()
333                 self.l.setFont(0, gFont(tlf.face(tlf.SMALL), tlf.size(tlf.SMALL)))
334
335         def postWidgetCreate(self, instance):
336                 MenuList.postWidgetCreate(self, instance)
337                 instance.setItemHeight(componentSizes.itemHeight(self.SKIN_COMPONENT_KEY, 50))
338
339         def getCurrentIndex(self):
340                 return self.instance.getCurrentIndex()
341
342         def buildList(self, xml):
343                 sizes = componentSizes[MSNWeatherPluginSearchResultList.SKIN_COMPONENT_KEY]
344                 textHeight = sizes.get(MSNWeatherPluginSearchResultList.SKIN_COMPONENT_TEXT_HEIGHT, 23)
345                 textWidth = sizes.get(MSNWeatherPluginSearchResultList.SKIN_COMPONENT_TEXT_WIDTH, 500)
346                 lineSpacing = sizes.get(MSNWeatherPluginSearchResultList.SKIN_COMPONENT_LINE_SPACING, 2)
347                 root = cet_fromstring(xml)
348                 searchlocation = ""
349                 searchresult = ""
350                 weatherlocationcode = ""
351                 list = []
352                 for childs in root:
353                         if childs.tag == "weather":
354                                 searchlocation = childs.attrib.get("weatherlocationname").encode("utf-8", 'ignore')
355                                 searchresult = childs.attrib.get("weatherfullname").encode("utf-8", 'ignore')
356                                 weatherlocationcode = childs.attrib.get("weatherlocationcode").encode("utf-8", 'ignore')
357                                 res = [
358                                         (weatherlocationcode, searchlocation),
359                                         (eListboxPythonMultiContent.TYPE_TEXT, 5, 0, textWidth, textHeight, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, searchlocation),
360                                         (eListboxPythonMultiContent.TYPE_TEXT, 5, textHeight+lineSpacing, textWidth, textHeight, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, searchresult),
361                                 ]
362                                 list.append(res)
363                 self.list = list
364                 self.l.setList(list)
365                 self.moveToIndex(0)