drop plugin-local translations (in favor of the global ones in /po)
[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 Multimedia 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 Multimedia 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 Multimedia 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                         if language == "en-EN": # hack
219                                 language = "en-US"
220                         elif language == "no-NO": # hack
221                                 language = "nn-NO"
222                         url = "http://weather.service.msn.com/find.aspx?src=outlook&outputview=search&weasearchstr=%s&culture=%s" % (urllib_quote(self.current.city.value), language)
223                         getPage(url).addCallback(self.xmlCallback).addErrback(self.error)
224                 else:
225                         self.session.open(MessageBox, _("You need to enter a valid city name before you can search for the location code."), MessageBox.TYPE_ERROR)
226
227         def keySave(self):
228                 if self.current.city.value != "" and self.current.weatherlocationcode.value != "":
229                         if self.newmode == 1:
230                                 config.plugins.WeatherPlugin.entrycount.value = config.plugins.WeatherPlugin.entrycount.value + 1
231                                 config.plugins.WeatherPlugin.entrycount.save()
232                         ConfigListScreen.keySave(self)
233                         config.plugins.WeatherPlugin.save()
234                         configfile.save()
235                         self.close()
236                 else:
237                         if self.current.city.value == "":
238                                 self.session.open(MessageBox, _("Please enter a valid city name."), MessageBox.TYPE_ERROR)
239                         else:
240                                 self.session.open(MessageBox, _("Please enter a valid location code for the city."), MessageBox.TYPE_ERROR)
241
242         def keyCancel(self):
243                 if self.newmode == 1:
244                         config.plugins.WeatherPlugin.Entry.remove(self.current)
245                 ConfigListScreen.cancelConfirm(self, True)
246
247         def keyDelete(self):
248                 if self.newmode == 1:
249                         self.keyCancel()
250                 else:           
251                         self.session.openWithCallback(self.deleteConfirm, MessageBox, _("Really delete this WeatherPlugin Entry?"))
252
253         def deleteConfirm(self, result):
254                 if not result:
255                         return
256                 config.plugins.WeatherPlugin.entrycount.value = config.plugins.WeatherPlugin.entrycount.value - 1
257                 config.plugins.WeatherPlugin.entrycount.save()
258                 config.plugins.WeatherPlugin.Entry.remove(self.current)
259                 config.plugins.WeatherPlugin.Entry.save()
260                 config.plugins.WeatherPlugin.save()
261                 configfile.save()
262                 self.close()
263                 
264                 
265         def xmlCallback(self, xmlstring):
266                 if xmlstring:
267                         errormessage = ""
268                         root = cet_fromstring(xmlstring)
269                         for childs in root:
270                                 if childs.tag == "weather" and childs.attrib.has_key("errormessage"):
271                                         errormessage = childs.attrib.get("errormessage").encode("utf-8", 'ignore')
272                                         break
273                         if len(errormessage) !=0:
274                                 self.session.open(MessageBox, errormessage, MessageBox.TYPE_ERROR)                                      
275                         else:
276                                 self.session.openWithCallback(self.searchCallback, MSNWeatherPluginSearch, xmlstring)
277                         
278         def error(self, error = None):
279                 if error is not None:
280                         print error
281                 
282         def searchCallback(self, result):
283                 if result:
284                         self.current.weatherlocationcode.value = result[0]
285                         self.current.city.value = result[1]
286         
287                 
288                 
289 class MSNWeatherPluginSearch(Screen):
290         skin = """
291                 <screen name="MSNWeatherPluginSearch" position="center,120" size="820,520">
292                         <ePixmap pixmap="skin_default/buttons/red.png" position="10,5" size="200,40" alphatest="on" />
293                 <ePixmap pixmap="skin_default/buttons/green.png" position="210,5" size="200,40" alphatest="on" />
294                 <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" />
295                 <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" />
296                 <eLabel position="10,50" size="800,1" backgroundColor="grey" />
297                 <widget name="entrylist" position="10,60" size="800,450" enableWrapAround="1" scrollbarMode="showOnDemand" />
298                 </screen>""" 
299
300         def __init__(self, session, xmlstring):
301                 Screen.__init__(self, session)
302                 self.title = _("MSN location search result")
303                 self["key_red"] = StaticText(_("Back"))
304                 self["key_green"] = StaticText(_("OK"))         
305                 self["entrylist"] = MSNWeatherPluginSearchResultList([])
306                 self["actions"] = ActionMap(["WizardActions","MenuActions","ShortcutActions"],
307                         {
308                          "ok"   :       self.keyOK,
309                          "green": self.keyOK,
310                          "back" :       self.keyClose,
311                          "red": self.keyClose,
312                          }, -1)
313                 self.updateList(xmlstring)
314
315         def updateList(self, xmlstring):
316                 self["entrylist"].buildList(xmlstring)
317
318         def keyClose(self):
319                 self.close(None)
320
321         def keyOK(self):
322                 pass
323                 try:sel = self["entrylist"].l.getCurrentSelection()[0]
324                 except: sel = None
325                 self.close(sel)
326                 
327
328 class MSNWeatherPluginSearchResultList(MenuList):
329         SKIN_COMPONENT_KEY = "WeatherPluginList"
330         SKIN_COMPONENT_TEXT_HEIGHT = "textHeight"
331         SKIN_COMPONENT_TEXT_WIDTH = "textWidth"
332         SKIN_COMPONENT_LINE_SPACING = "lineSpacing"
333
334         def __init__(self, list, enableWrapAround = True):
335                 MenuList.__init__(self, list, enableWrapAround, eListboxPythonMultiContent)
336                 tlf = TemplatedListFonts()
337                 self.l.setFont(0, gFont(tlf.face(tlf.SMALL), tlf.size(tlf.SMALL)))
338
339         def postWidgetCreate(self, instance):
340                 MenuList.postWidgetCreate(self, instance)
341                 instance.setItemHeight(componentSizes.itemHeight(self.SKIN_COMPONENT_KEY, 50))
342
343         def getCurrentIndex(self):
344                 return self.instance.getCurrentIndex()
345
346         def buildList(self, xml):
347                 sizes = componentSizes[MSNWeatherPluginSearchResultList.SKIN_COMPONENT_KEY]
348                 textHeight = sizes.get(MSNWeatherPluginSearchResultList.SKIN_COMPONENT_TEXT_HEIGHT, 23)
349                 textWidth = sizes.get(MSNWeatherPluginSearchResultList.SKIN_COMPONENT_TEXT_WIDTH, 500)
350                 lineSpacing = sizes.get(MSNWeatherPluginSearchResultList.SKIN_COMPONENT_LINE_SPACING, 2)
351                 root = cet_fromstring(xml)
352                 searchlocation = ""
353                 searchresult = ""
354                 weatherlocationcode = ""
355                 list = []
356                 for childs in root:
357                         if childs.tag == "weather":
358                                 searchlocation = childs.attrib.get("weatherlocationname").encode("utf-8", 'ignore')
359                                 searchresult = childs.attrib.get("weatherfullname").encode("utf-8", 'ignore')
360                                 weatherlocationcode = childs.attrib.get("weatherlocationcode").encode("utf-8", 'ignore')
361                                 res = [
362                                         (weatherlocationcode, searchlocation),
363                                         (eListboxPythonMultiContent.TYPE_TEXT, 5, 0, textWidth, textHeight, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, searchlocation),
364                                         (eListboxPythonMultiContent.TYPE_TEXT, 5, textHeight+lineSpacing, textWidth, textHeight, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, searchresult),
365                                 ]
366                                 list.append(res)
367                 self.list = list
368                 self.l.setList(list)
369                 self.moveToIndex(0)