~ubuntu-branches/ubuntu/trusty/indicator-weather/trusty

« back to all changes in this revision

Viewing changes to bin/indicator-weather

  • Committer: Andrew Starr-Bochicchio
  • Date: 2011-04-11 19:27:49 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: a.starr.b@gmail.com-20110411192749-vkvmvwfxa4u5ok10
* New upstream bug fix release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
### END LICENSE
19
19
 
20
20
import sys, os, shutil, tempfile
 
21
from gi.repository import Gio
21
22
import gtk, pygtk, gobject, pynotify
22
23
pygtk.require('2.0')
23
24
import appindicator
28
29
from xml.dom.minidom import parseString
29
30
import datetime
30
31
import dbus
 
32
import time
31
33
# Will be used for humidex
32
34
#import math
33
35
import commands, threading
51
53
    sys.path.insert(0, PROJECT_ROOT_DIRECTORY)
52
54
    os.putenv('PYTHONPATH', PROJECT_ROOT_DIRECTORY) # for subprocesses
53
55
 
54
 
from indicator_weather.helpers import get_builder
 
56
from indicator_weather.helpers import *
55
57
 
56
58
class Settings:
57
59
    """ Class to read/write settings """
60
62
    # Open the DB and prepare views
61
63
    #TODO: Create view when package is installed?
62
64
    def prepare_settings_store(self):
63
 
        try:
64
 
            log.debug("Settings: preparing settings store")
65
 
            self.db = CouchDatabase("weatherindicator", create = True)
66
 
 
67
 
            # Settings view
68
 
            self.settings_design_doc = "settings"
69
 
            self.settings_view = "function(doc) {if (doc.record_type == '%s') {emit(doc.name, doc);}}" % self.settings_design_doc
70
 
            self.db.add_view("get_setting", self.settings_view, None, self.settings_design_doc)
71
 
 
72
 
            # Cached weather view
73
 
            self.weather_design_doc = "weather"
74
 
            self.weather_view = "function(doc) {if (doc.record_type == '%s') {emit(doc.location, doc)} ;}" % self.weather_design_doc
75
 
            self.db.add_view("get_weather", self.weather_view, None, self.weather_design_doc)
76
 
 
77
 
            # Location info view
78
 
            self.location_design_doc = "location"
79
 
            self.location_view = "function(doc) {if (doc.record_type == '%s') {emit(doc.location, doc)} ;}" % self.location_design_doc
80
 
            self.db.add_view("get_location", self.location_view, None, self.location_design_doc)
81
 
 
82
 
        except dbus.exceptions.DBusException as e:
83
 
            log.debug("Settings: DBus exception occurred, retrying")
84
 
            self.db = CouchDatabase("weatherindicator", create = True)
 
65
        log.debug("Settings: preparing settings store")
 
66
        while True:
 
67
            try:
 
68
                self.db = CouchDatabase("weatherindicator", create = True)
 
69
                break
 
70
            except dbus.exceptions.DBusException as e:
 
71
                log.debug("Settings: DBus exception occurred, retrying")
 
72
                time.sleep(3)
 
73
 
 
74
        # Settings view
 
75
        self.settings_design_doc = "settings"
 
76
        self.settings_view = "function(doc) {if (doc.record_type == '%s') {emit(doc.name, doc);}}" % self.settings_design_doc
 
77
        self.db.add_view("get_setting", self.settings_view, None, self.settings_design_doc)
 
78
 
 
79
        # Cached weather view
 
80
        self.weather_design_doc = "weather"
 
81
        self.weather_view = "function(doc) {if (doc.record_type == '%s') {emit(doc.location, doc)} ;}" % self.weather_design_doc
 
82
        self.db.add_view("get_weather", self.weather_view, None, self.weather_design_doc)
 
83
 
 
84
        # Location info view
 
85
        self.location_design_doc = "location"
 
86
        self.location_view = "function(doc) {if (doc.record_type == '%s') {emit(doc.location, doc)} ;}" % self.location_design_doc
 
87
        self.db.add_view("get_location", self.location_view, None, self.location_design_doc)
85
88
 
86
89
    # Get a value of the setting
87
90
    def get_value(self, setting, return_id = False):
110
113
            self.db.update_fields(old_doc_id, self.record)
111
114
        else:
112
115
            log.debug("Setting: setting '%s' was created" % setting)
113
 
            self.db.put_record(CouchRecord(self.record, self.settings_design_doc))
 
116
            while True:
 
117
                try:
 
118
                    self.db.put_record(CouchRecord(self.record, self.settings_design_doc))
 
119
                    break;
 
120
                except:
 
121
                    log.debug("Settings: exception occurred, retrying")
 
122
                    time.sleep(3)
114
123
 
115
124
    # Get cached weather by location code.
116
125
    # If return_id is True, only document id is returned, otherwise - full weather data
132
141
        self.record = {
133
142
          "location" : location_code,
134
143
          "data"      : {
135
 
            "label"    : weather.get_temperature(),
 
144
            "label"    : weather.get_temperature(needs_rounding=True),
136
145
            "condition": weather.get_condition_label(),
137
146
            "icon"     : weather.get_icon_name(),
138
147
            "temper"   : weather.get_temperature_label(),
148
157
        if old_doc_id != None:
149
158
            self.db.update_fields(old_doc_id, self.record)
150
159
        else:    
151
 
            self.db.put_record(CouchRecord(self.record, self.weather_design_doc))
 
160
            while True:
 
161
                try:
 
162
                    self.db.put_record(CouchRecord(self.record, self.weather_design_doc))
 
163
                    break;
 
164
                except:
 
165
                    log.debug("Settings: exception occurred, retrying")
 
166
                    time.sleep(3)
152
167
 
153
168
    # Get location details by location code
154
169
    # If return_id is True, only document id is returned, otherwise - full location data
183
198
        old_doc_id = self.get_location_details(location_code, return_id=True)
184
199
        if old_doc_id != None:
185
200
            self.db.update_fields(old_doc_id, self.record)
186
 
        else:    
187
 
            self.db.put_record(CouchRecord(self.record, self.location_design_doc))
 
201
        else:
 
202
            while True:
 
203
                try:
 
204
                    self.db.put_record(CouchRecord(self.record, self.location_design_doc))
 
205
                    break;
 
206
                except:
 
207
                    log.debug("Settings: exception occurred, retrying")
 
208
                    time.sleep(3)
188
209
 
189
210
class MetricSystem:
190
211
    """ Class with available metric systems units """
215
236
 
216
237
    # Convert coordinate for google
217
238
    def convert_coordinate_for_google(self, value):
218
 
        value = value.replace(".","")
219
 
        while len(value) < 9:
220
 
            value = "".join((value, "0"))
221
 
        value = value[0:9] if "-" in value else value[0:8]
222
 
        return value
 
239
       value = float(value) * 1e6
 
240
       return int(round(value))
223
241
 
224
242
    # Get necessary location details by its GeoNames details
225
243
    def prepare_location(self, geonames_details):
325
343
        self.daysofweek = []
326
344
        self.icons = []
327
345
        self.conditions = []
 
346
        self.error_message = None
328
347
        try:
329
348
            # Generate a fake location by current coordinates
330
349
            location_name = ",,,%s,%s" % (self.lat, self.lon)
335
354
                self.daysofweek.append(forecast["day_of_week"])
336
355
                self.icons.append(forecast["icon"].split("/ig/images/weather/")[-1].split(".gif")[0])
337
356
                self.conditions.append(forecast["condition"])
 
357
            self.error_message = None
 
358
 
338
359
        except urllib2.URLError:
339
360
            log.error("Forecast: error reading forecast for %s" % location_name)
 
361
        except KeyError:
 
362
            log.error("Forecast: returned empty forecast %s" % location_name)
 
363
            self.error_message = _('Unknown error occurred while picking up weather data')
340
364
 
341
365
    # Parse high values for forecast data
342
366
    def get_forecast_data(self):
385
409
 
386
410
    #Available conditions by google icon
387
411
    #Format: Google icon name: (day icon, night icon, is a severe weather condition)
 
412
    #Reference: http://www.blindmotion.com/2009/03/google-weather-api-images/
388
413
    _GoogleConditions = {
389
414
        "sunny"            : ( "weather-clear",      "weather-clear-night",      False),
390
415
        "mostly_sunny"     : ( "weather-clear",      "weather-clear-night",      False),
406
431
        "haze"             : ( "weather-fog",        "weather-fog",              False),
407
432
        "chance_of_storm"  : ( "weather-storm",      "weather-storm",            True),
408
433
        "storm"            : ( "weather-storm",      "weather-storm",            True),
409
 
        "thunderstorm"     : ( "weather-stoom",      "weather-storm",            True),
 
434
        "thunderstorm"     : ( "weather-storm",      "weather-storm",            True),
410
435
        "chance_of_tstorm" : ( "weather-storm",      "weather-storm",            True),
411
436
    }
412
437
 
419
444
        '3' : ("weather-storm",             "weather-storm",            True,  _("Severe thunderstorms")),
420
445
        '4' : ("weather-storm",             "weather-storm",            True,  _("Thunderstorms")),
421
446
        '5' : ("weather-snow",              "weather-snow",             False, _("Mixed rain and snow")),
422
 
        # Use Americal meaning of sleet - see http://en.wikipedia.org/wiki/Sleet
 
447
        # Use American meaning of sleet - see http://en.wikipedia.org/wiki/Sleet
423
448
        '6' : ("weather-showers",           "weather-showers",          False, _("Mixed rain and sleet")),
424
449
        '7' : ("weather-snow",              "weather-snow",             False, _("Mixed snow and sleet")),
425
450
        '8' : ("weather-showers",           "weather-showers",          False, _("Freezing drizzle")),
482
507
            # Get data in original locale for condition name
483
508
            self.__localized_report = pywapi.get_weather_from_google (location_id, hl = locale_name)
484
509
            icon_name = self.__report['current_conditions']['icon'].replace('/ig/images/weather/', '').replace('.gif', '')
 
510
 
485
511
            self.__current_condition = self._GoogleConditions.get(icon_name)
 
512
            if self.__current_condition == None:
 
513
                log.error("ExtendedForecast: unknown Google weather condition '%s'" % icon_name)
 
514
                self.__current_condition = (False, False, False, _(self.__report['current_conditions']['condition']))
486
515
 
487
516
        # Get data from Yahoo
488
517
        if self.__weather_datasource == WeatherDataSource.YAHOO:
593
622
        return "%s: %s %s" % (_("Pressure"), value, units)
594
623
 
595
624
    # Get temperature with units value - doesn't include 'Temperature' label
596
 
    def get_temperature(self):
 
625
    def get_temperature(self, needs_rounding = False):
597
626
        if self.__weather_datasource == WeatherDataSource.GOOGLE:
598
627
            if (self.__metric_system == MetricSystem.SI):
599
628
                _value = self.__report['current_conditions']['temp_c']
600
 
                _unit  = "C"
 
629
                _unit  = "˚C"
601
630
            else:
602
631
                _value = self.__report['current_conditions']['temp_f']
603
 
                _unit  = "F"
 
632
                _unit  = "˚F"
604
633
        if self.__weather_datasource == WeatherDataSource.YAHOO:
605
634
            if (self.__metric_system == MetricSystem.SI):
606
635
                _value = "%.1f" % ((float(self.__report['condition']['temp']) - 32) * 5/9)
607
 
                _unit  = "C"
 
636
                _unit  = "˚C"
608
637
            else:
609
638
                _value = self.__report['condition']['temp']
610
 
                _unit  = "F"
 
639
                _unit  = "˚F"
 
640
        # round the value if required
 
641
        if needs_rounding:
 
642
            _value = round(float(_value))
611
643
        # Removing unnecessary '.0' in the end, if exists
612
644
        return ("%s %s" % (_value, _unit)).replace(".0", "")
613
645
 
667
699
 
668
700
    # Get sunrise label
669
701
    def get_sunrise_label(self):
670
 
        return "%s: %s" % (_("Sunrise"), self.__sunrise_t.strftime('%X').replace(":00", ""))
 
702
        return "%s: %s" % (_("Sunrise"), TimeFormatter.format_time(self.__sunrise_t))
671
703
 
672
704
    # Get sunset label
673
705
    def get_sunset_label(self):
674
 
        return "%s: %s" % (_("Sunset"), self.__sunset_t.strftime('%X').replace(":00", ""))
 
706
        return "%s: %s" % (_("Sunset"), TimeFormatter.format_time(self.__sunset_t))
 
707
 
675
708
 
676
709
    # Additional functions
677
710
    # Convert wind direction from degrees to localized direction
759
792
        self.winder.set_status (appindicator.STATUS_ACTIVE)
760
793
        self.winder.set_attention_icon ("weather-indicator-error")
761
794
 
 
795
        self.refreshed_minutes_ago = 0
 
796
        monitor_upower(self.on_system_sleep, self.on_system_resume, log)
 
797
 
762
798
        log.debug("Indicator: reading settings")
763
799
        self.settings = Settings()
764
800
        self.settings.prepare_settings_store()      
853
889
        if (hasattr(self.winder, 'set_label')):
854
890
            log.debug("Indicator: update_label: setting label to '%s'" % label)
855
891
            self.previous_label_value = label
856
 
            self.winder.set_label(label) if self.show_label else self.winder.set_label("")
 
892
            self.winder.set_label(label) if self.show_label else self.winder.set_label(" ")
857
893
            self.winder.set_status(appindicator.STATUS_ATTENTION)
858
894
            self.winder.set_status(appindicator.STATUS_ACTIVE)
859
895
 
958
994
        breaker.show()
959
995
        self.menu.append(breaker)
960
996
 
961
 
        self.refresh_show = gtk.MenuItem("%s (%s)" % (_("Refresh"), _("refreshed just now")))
 
997
        self.refresh_show = gtk.MenuItem()
 
998
        self.set_refresh_label()
962
999
        self.refresh_show.connect("activate", self.update_weather)
963
1000
        self.refresh_show.show()
964
1001
        self.menu.append(self.refresh_show)
987
1024
        self.menu.append(quit)
988
1025
 
989
1026
        self.winder.set_menu(self.menu)
990
 
        self.update_label("")
 
1027
        self.update_label(" ")
991
1028
 
992
1029
    # Another city has been selected from radiobutton
993
1030
    def on_city_changed(self,widget):
1008
1045
            self.settings.set_value("placechosen", self.placechosen)
1009
1046
            self.update_weather(False)
1010
1047
 
 
1048
    def on_system_sleep(self):
 
1049
        """
 
1050
        Callback from UPower that system suspends/hibernates
 
1051
        """
 
1052
        # store time
 
1053
        self.sleep_time = datetime.datetime.now()
 
1054
        log.debug("Indicator: system goes to sleep at %s" % self.sleep_time)
 
1055
        # remove gobject timeouts
 
1056
        if hasattr(self, "refresh_id"):
 
1057
            gobject.source_remove(self.refresh_id)
 
1058
        if hasattr(self, "rate_id"):
 
1059
            gobject.source_remove(self.rate_id)
 
1060
 
 
1061
    def on_system_resume(self):
 
1062
        """
 
1063
        Callback from UPower that system resumes
 
1064
        """
 
1065
        now = datetime.datetime.now()
 
1066
        log.debug("Indicator: system resumes at %s" % now)
 
1067
        # update refresh label
 
1068
        td = now - self.sleep_time
 
1069
        mins_elapsed = td.days/24*60 + td.seconds/60 + self.refreshed_minutes_ago
 
1070
        self.update_refresh_label(mins_elapsed)
 
1071
        # check if we need to update the weather now or to reschedule the update
 
1072
        if mins_elapsed > int(self.rate):
 
1073
            self.update_weather()
 
1074
        else:
 
1075
            self.schedule_weather_update(int(self.rate) - mins_elapsed)
 
1076
 
 
1077
    # Schedule weather update
 
1078
    def schedule_weather_update(self, rate_override = None):
 
1079
        if hasattr(self, "rate_id"):
 
1080
            gobject.source_remove(self.rate_id)
 
1081
        if rate_override:
 
1082
            log.debug("Indicator: scheduling update in %s mins" % rate_override)
 
1083
            self.rate_id = gobject.timeout_add(
 
1084
                int(rate_override) * 60000, self.update_weather)
 
1085
        else:
 
1086
            log.debug("Indicator: scheduling update in %s mins" % self.rate)
 
1087
            self.rate_id = gobject.timeout_add(
 
1088
                int(self.rate) * 60000, self.update_weather)
 
1089
 
 
1090
    # Schedule weather update
 
1091
    def schedule_refresh_label_update(self):
 
1092
        if hasattr(self, "refresh_id"):
 
1093
            gobject.source_remove(self.refresh_id)
 
1094
        log.debug("Indicator: scheduling refresh label update in 1 min")
 
1095
        self.refresh_id = gobject.timeout_add(60000, self.update_refresh_label)
 
1096
 
1011
1097
    # Update 'Refresh' label with time since last successful data refresh
1012
 
    def update_refresh_label(self):
1013
 
        self.refreshed_minutes_ago += 1
1014
 
        log.debug("Indicator: updating refresh label, %s min. ago" % self.refreshed_minutes_ago)
1015
 
        refresh_label = "%s (%s)" % (_("Refresh"), _("%d min. ago") % self.refreshed_minutes_ago)
 
1098
    def update_refresh_label(self, reset_minutes = None):
 
1099
        if reset_minutes is not None:
 
1100
            self.refreshed_minutes_ago = reset_minutes
 
1101
        else:
 
1102
            self.refreshed_minutes_ago += 1
 
1103
        self.set_refresh_label()
 
1104
        self.schedule_refresh_label_update()
 
1105
        return False
 
1106
 
 
1107
    def set_refresh_label(self, refreshing=False):
 
1108
        if refreshing:
 
1109
            refresh_label=_("Refreshing, please wait")
 
1110
        elif self.refreshed_minutes_ago == 0:
 
1111
            refresh_label="%s (%s)" % (_("Refresh"), _("just now"))
 
1112
        else:
 
1113
            log.debug("Indicator: updating refresh label, %d min. ago" % self.refreshed_minutes_ago)
 
1114
            refresh_label = "%s (%s)" % (_("Refresh"), _("%d min. ago") % self.refreshed_minutes_ago)
1016
1115
        self.refresh_show.set_label(refresh_label)
1017
 
        self.refresh_id = gobject.timeout_add(60000, self.update_refresh_label)
1018
1116
 
1019
1117
    # Load weather data from cache and display its values
1020
1118
    def show_cached_weather(self):
1023
1121
            cached_weather = eval(cached_weather)
1024
1122
            log.debug("Indicator: loading weather from cache for %s" % self.places[self.placechosen])
1025
1123
            self.menu_normal()
 
1124
            self.set_refresh_label(True)
1026
1125
            self.icon = cached_weather['icon']
1027
1126
            if (self.icon == False):
1028
1127
                self.winder.set_icon(os.path.join(PROJECT_ROOT_DIRECTORY, "share/indicator-weather/media/icon_unknown_condition.png"))
1041
1140
            self.sunrise_show.set_label(cached_weather['sunrise'])
1042
1141
            self.sunset_show.set_label(cached_weather['sunset'])
1043
1142
            self.update_label(cached_weather['label'])
1044
 
            self.refresh_show.set_label("%s" % (_("Refreshing, please wait")))
1045
1143
            self.winder.set_status(appindicator.STATUS_ATTENTION)
1046
1144
            self.winder.set_status(appindicator.STATUS_ACTIVE)           
1047
1145
 
1052
1150
            # No data returned - leave cached data to be displayed
1053
1151
            log.error("Indicator: updateWeather: could not get weather, leaving cached data")
1054
1152
            # Repeat an attempt in one minute
1055
 
            log.debug("Indicator: updateWeather: setting rate to one minute")
1056
 
            self.rateid = gobject.timeout_add(60000, self.update_weather)
 
1153
            self.schedule_weather_update(1)
1057
1154
            return
1058
1155
 
1059
 
        # Set a 'Refresh' label update interval to 1 min
1060
 
        if hasattr(self, 'refresh_id'):
1061
 
          gobject.source_remove(self.refresh_id)
1062
 
        self.refreshed_minutes_ago = 0
1063
 
        self.refresh_id = gobject.timeout_add(60000, self.update_refresh_label)
1064
 
 
1065
1156
        # Fill in menu with data
1066
1157
        log.debug("Indicator: updateWeather: got condition '%s', icon '%s'" % (self.condition, self.icon))
1067
1158
        self.condition = weather.get_condition_label()
1069
1160
        log.debug("Indicator: fill in menu with params: city='%s', temp='%s', humid='%s', wind='%s', sunrise='%s', sunset='%s', puretemp=%s" % (self.places[self.placechosen][1], weather.get_temperature_label(), weather.get_humidity_label(), weather.get_wind_label(), weather.get_sunrise_label(), weather.get_sunset_label(), weather.get_temperature()))
1070
1161
 
1071
1162
        self.menu_normal()
 
1163
        self.update_refresh_label(0)
1072
1164
        self.city_show.set_label(self.places[self.placechosen][1])
1073
1165
        self.cond_show.set_label(self.condition)
1074
1166
        self.temp_show.set_label(weather.get_temperature_label())
1080
1172
        self.wind_show.set_label(weather.get_wind_label())
1081
1173
        self.sunrise_show.set_label(weather.get_sunrise_label())
1082
1174
        self.sunset_show.set_label(weather.get_sunset_label())
1083
 
        self.refresh_show.set_label("%s (%s)" % (_("Refresh"), _("just now")))
1084
1175
 
1085
1176
        # Saving cached data, unless correct icon is supplied
1086
1177
        if (self.icon == False):
1088
1179
        else:
1089
1180
            self.winder.set_icon(self.icon)
1090
1181
            self.settings.save_weather(weather, self.places[self.placechosen][0])
1091
 
        self.update_label(weather.get_temperature())
 
1182
        self.update_label(weather.get_temperature(needs_rounding=True))
1092
1183
 
1093
1184
        # Notify user, if notifications are enabled
1094
1185
        if self.condition != self.settings.get_value("current") and self.notif == 'U':
1101
1192
            self.notify(self.condition, self.icon, severe=True)
1102
1193
 
1103
1194
        self.settings.set_value("current", self.condition)
1104
 
        log.debug("Indicator: updateWeather: setting rate to %s" % self.rate)
1105
 
        self.rateid = gobject.timeout_add(int(self.rate) * 60000, self.update_weather)
 
1195
        self.schedule_weather_update()
1106
1196
 
1107
1197
    # Update weather
1108
1198
    def update_weather(self, notif=True, widget=None):
1143
1233
        log.debug("Indicator: open About dialog")  
1144
1234
        self.aboutdialog = gtk.AboutDialog()
1145
1235
        self.aboutdialog.set_name(_("Weather Indicator"))
1146
 
        self.aboutdialog.set_version("11.03.20 'Cloudy' RC3")
 
1236
        self.aboutdialog.set_version("11.04.10 'Cloudy'")
1147
1237
 
1148
1238
        ifile = open(os.path.join(PROJECT_ROOT_DIRECTORY, "share/doc/indicator-weather/AUTHORS"), "r")
1149
1239
        self.aboutdialog.set_copyright(ifile.read().replace('\x0c', ''))
1175
1265
 
1176
1266
    # Quit the applet
1177
1267
    def quit(self, widget, data=None):
1178
 
        # Compact the settings DB
1179
 
        self.settings.db.db.compact()
1180
 
        log.debug("Indicator: Quitting")  
 
1268
        log.debug("Indicator: Quitting")
 
1269
        try:
 
1270
            # Compact the settings DB
 
1271
            #self.settings.db.db.compact()
 
1272
            #
 
1273
            # There is a bug in python client v0.6, db.compact raises error
 
1274
            # http://code.google.com/p/couchdb-python/issues/detail?id=141
 
1275
            #
 
1276
            # It seems that the client should always set the
 
1277
            # 'Content-Type': 'application/json' header
 
1278
            # So we bypass that compact command and execute a post directly
 
1279
            # until the python client gets fixed
 
1280
            headers = {
 
1281
                'Content-Type': 'application/json'
 
1282
            }
 
1283
            self.settings.db.db.resource.post('_compact', headers=headers)
 
1284
        except Exception, e:
 
1285
            log.debug(e)
1181
1286
        gtk.main_quit()
1182
1287
 
1183
1288
class PreferencesDialog(gtk.Dialog):
1310
1415
        if int(self.builder.get_object('rate').get_value()) != wi.rate:
1311
1416
            wi.settings.set_value("refresh_rate", int(self.builder.get_object('rate').get_value()))
1312
1417
            wi.rate = int(self.builder.get_object('rate').get_value())
1313
 
            if hasattr(wi, "rateid"):
1314
 
                gobject.source_remove(wi.rateid)
1315
 
            wi.rateid = gobject.timeout_add(int(wi.rate) * 60000, wi.update_weather)
1316
1418
            log.debug("Preferences: Rate changed to '%s'" % wi.rate)
 
1419
            wi.schedule_weather_update()
1317
1420
            
1318
1421
        # Get places from location list
1319
1422
        newplaces = list()
1378
1481
        log.debug("ExtendedForecast: getting forecast data")
1379
1482
        forecast = Forecast(wi.metric_system, wi.current_location.location_details['latitude'], wi.current_location.location_details['longitude'], locale_name)
1380
1483
        forecast.prepare_forecast_data()
1381
 
        daysofweek = forecast.get_forecast_daysofweek()
1382
 
        forecast_data = forecast.get_forecast_data()
1383
 
        if forecast_data == None:
1384
 
            # Forecast data unavailable - hide elements and show 'connection_error' label
1385
 
            self.builder.get_object('connection_error').set_visible(True);
1386
 
            self.builder.get_object('hbox1').set_visible(False);
1387
 
            self.builder.get_object('hseparator1').set_visible(False);
1388
 
            return
1389
 
        (highdata, lowdata) = forecast_data
1390
 
        icons      = forecast.get_forecast_icons()
1391
 
        conditions = forecast.get_forecast_conditions()
1392
 
 
1393
 
        log.debug("ExtendedForecast: parsing forecast data")
1394
 
        # Create labels for each weekday
1395
 
        self.builder.get_object('day1lbl').set_label('<big>%s</big>' % daysofweek[0].capitalize())
1396
 
        self.builder.get_object('day2lbl').set_label('<big>%s</big>' % daysofweek[1].capitalize())
1397
 
        self.builder.get_object('day3lbl').set_label('<big>%s</big>' % daysofweek[2].capitalize())
1398
 
        self.builder.get_object('day4lbl').set_label('<big>%s</big>' % daysofweek[3].capitalize())
1399
 
 
1400
 
        # Fill in icons
1401
 
        for i in xrange(1,5):
1402
 
            # Get icon name from dictionary in Weather object for Google icons
1403
 
            google_icon = Weather._GoogleConditions[icons[i-1]][0]
1404
 
            self.builder.get_object('day%simage' % str(i)).set_from_icon_name(google_icon,gtk.ICON_SIZE_BUTTON)
1405
 
 
1406
 
        # Fill in condition labels
1407
 
        for i in xrange(1,5):
1408
 
            self.builder.get_object('day%scond' % str(i)).set_label(conditions[i-1])
1409
 
            
1410
 
        # Fill in High and Low temperatures
1411
 
        if wi.metric_system == MetricSystem.SI:
1412
 
            tempunit = '°C'
 
1484
        if forecast.error_message != None:
 
1485
            #Error occurred while getting forecast data
 
1486
            self.builder.get_object('connection_error').set_text("%s" % forecast.error_message)
 
1487
            self.builder.get_object('connection_error').set_visible(True)
 
1488
            self.builder.get_object('hbox1').set_visible(False)
1413
1489
        else:
1414
 
            tempunit = '°F'
1415
 
        for i in xrange(1,5):
1416
 
            label = "%s: %s%s" % (_('High'), highdata[i-1],tempunit)
1417
 
            self.builder.get_object('day%stemphigh' % str(i)).set_label(label)
1418
 
            label = "%s: %s%s" % (_('Low'), lowdata[i-1],tempunit)
1419
 
            self.builder.get_object('day%stemplow' % str(i)).set_label(label)
 
1490
            daysofweek = forecast.get_forecast_daysofweek()
 
1491
            forecast_data = forecast.get_forecast_data()
 
1492
            if forecast_data == None:
 
1493
                # Forecast data unavailable - hide elements and show 'connection_error' label
 
1494
                self.builder.get_object('connection_error').set_visible(True);
 
1495
                self.builder.get_object('hbox1').set_visible(False);
 
1496
                self.builder.get_object('hseparator1').set_visible(False);
 
1497
                return
 
1498
            (highdata, lowdata) = forecast_data
 
1499
            icons      = forecast.get_forecast_icons()
 
1500
            conditions = forecast.get_forecast_conditions()
 
1501
 
 
1502
            log.debug("ExtendedForecast: parsing forecast data")
 
1503
            # Create labels for each weekday
 
1504
            self.builder.get_object('day1lbl').set_label('<big>%s</big>' % daysofweek[0].capitalize())
 
1505
            self.builder.get_object('day2lbl').set_label('<big>%s</big>' % daysofweek[1].capitalize())
 
1506
            self.builder.get_object('day3lbl').set_label('<big>%s</big>' % daysofweek[2].capitalize())
 
1507
            self.builder.get_object('day4lbl').set_label('<big>%s</big>' % daysofweek[3].capitalize())
 
1508
 
 
1509
            # Fill in icons
 
1510
            for i in xrange(1,5):
 
1511
                # Get icon name from dictionary in Weather object for Google icons
 
1512
                conds = Weather._GoogleConditions.get(icons[i-1])
 
1513
                if conds != None:
 
1514
                    google_icon = conds[0]
 
1515
                else:
 
1516
                    log.error("ExtendedForecast: unknown Google weather condition '%s'" % icons[i-1])
 
1517
                    log.error(forecast.forecast)
 
1518
                    google_icon = 'weather-unknown-condition'
 
1519
                self.builder.get_object('day%simage' % str(i)).set_from_icon_name(google_icon,gtk.ICON_SIZE_BUTTON)
 
1520
 
 
1521
            # Fill in condition labels
 
1522
            for i in xrange(1,5):
 
1523
                self.builder.get_object('day%scond' % str(i)).set_label(conditions[i-1])
 
1524
                
 
1525
            # Fill in High and Low temperatures
 
1526
            if wi.metric_system == MetricSystem.SI:
 
1527
                tempunit = '°C'
 
1528
            else:
 
1529
                tempunit = '°F'
 
1530
            for i in xrange(1,5):
 
1531
                label = "%s: %s%s" % (_('High'), highdata[i-1],tempunit)
 
1532
                self.builder.get_object('day%stemphigh' % str(i)).set_label(label)
 
1533
                label = "%s: %s%s" % (_('Low'), lowdata[i-1],tempunit)
 
1534
                self.builder.get_object('day%stemplow' % str(i)).set_label(label)
1420
1535
 
1421
1536
    # Closing forecast window
1422
1537
    def close(self, widget, data=None):
1477
1592
                else:
1478
1593
                    displayed_city_name = "%s, %s" % (city['name'], city['countryName'])
1479
1594
                self.store.append([displayed_city_name, str(city['geonameId']), str(city['lat']), str(city['lng']), str(city['name'])])
 
1595
                self.location_input_combo.popup()
1480
1596
        except urllib2.URLError:
1481
1597
            log.error("Assistant: error reaching url '%s'" % url)
1482
1598
 
1577
1693
 
1578
1694
if __name__ == "__main__":
1579
1695
    #Enable and configure logs
 
1696
    global log
1580
1697
    log_filename = os.path.join(os.path.expanduser("~/.cache"), "indicator-weather.log")
1581
1698
    log = logging.getLogger('IndicatorWeather')
1582
1699
    log.setLevel(logging.DEBUG)
1594
1711
    if myapp.is_already_running():
1595
1712
        log.info("Another instance of this program is already running")
1596
1713
        sys.exit(_("Another instance of this program is already running"))
 
1714
 
 
1715
    # Set http proxy support
 
1716
    ProxyMonitor.monitor_proxy(log)
 
1717
    # Use date-time format as in indicator-datetime
 
1718
    TimeFormatter.monitor_indicator_datetime(log)
1597
1719
        
1598
1720
    # not running, safe to continue...
1599
1721
    gtk.gdk.threads_init()