def show_preferences(self, *args): """ Show the preferences window. """ if not self.preferences_initialized or self.preferences.get_state( ) == True: self.pref = Preferences(self.specto, self) else: self.pref.show()
def show_preferences(self, *args): """ Show the preferences window. """ if not self.preferences_initialized or self.preferences.get_state( ) == True: self.logger.log(_("preferences: create"), "debug", self.__class__) self.pref = Preferences(self) else: self.logger.log(_("preferences: reappear"), "debug", self.__class__) self.pref.show()
def show_preferences(self, *args): """ Show the preferences window. """ if not self.preferences_initialized or self.preferences.get_state() == True: self.logger.log(_("preferences: create"), "debug", self.__class__) self.pref=Preferences(self) else: self.logger.log(_("preferences: reappear"), "debug", self.__class__) self.pref.show()
class Specto: """ The main Specto class. """ add_w = "" edit_w = "" error_l = "" about = "" export = "" def __init__(self): self.DEBUG = DEBUG import gettext #this is for the glade files self.glade_gettext = gettext.textdomain("specto") self.logger = Logger(self) self.check_instance() #see if specto is already running self.util = util self.PATH = self.util.get_path() self.specto_gconf = specto_gconf self.check_default_settings( ) #if this is the first run of specto, set the default values for gconf. Whenever you add some gconf preference for specto, this function will also need to be updated. self.GTK = GTK if GTK: self.tray = Tray(self) self.icon_theme = gtk.icon_theme_get_default() self.watch_db = {} self.watch_io = Watch_io() watch_value_db = self.watch_io.read_options() self.preferences_initialized = False self.notifier_initialized = False #listen for gconf keys self.specto_gconf.notify_entry("debug_mode", self.key_changed, "debug") self.connection_manager = conmgr.get_net_listener() if GTK: if self.specto_gconf.get_entry("always_show_icon") == False: #if the user has not requested the tray icon to be shown at all times, it's impossible that the notifier is hidden on startup, so we must show it. self.notifier_keep_hidden = False self.toggle_notifier() elif self.specto_gconf.get_entry("show_notifier") == True: self.notifier_keep_hidden = False self.toggle_notifier() elif self.specto_gconf.get_entry("show_notifier") == False: self.notifier_keep_hidden = True self.toggle_notifier() self.notifier_keep_hidden = False else: #just in case the entry was never created in gconf self.notifier_keep_hidden = False self.toggle_notifier() self.create_all_watches(watch_value_db) if GTK: gtk.main() else: self.go = gobject.MainLoop() self.go.run() def key_changed(self, *args): """ Listen for gconf keys. """ label = args[3] if label == "debug": self.DEBUG = self.specto_gconf.get_entry("debug_mode") def check_default_settings(self): """ This is used to set the default settings properly the first time Specto is run, without using gconf schemas """ self.default_settings = ( ["always_show_icon", False], #having it True would be against the HIG! ["debug_mode", False], ["follow_website_redirects", True], ["pop_toast_duration", 5], ["pop_toast", True], ["show_deactivated_watches", True], ["show_in_windowlist", True], ["show_notifier", True], ["show_toolbar", True], ["sort_function", "name"], ["sort_order", "asc"], ["update_sound", "/usr/share/sounds/ekiga/voicemail.wav"], ["use_update_sound", False], ["window_notifier_height", 500], ["window_notifier_width", 500]) for default_setting in self.default_settings: if self.specto_gconf.get_entry( default_setting[0] ) == None: #the key has no user-defined value or does not exist self.specto_gconf.set_entry(default_setting[0], default_setting[1]) def check_instance(self): """ Check if specto is already running. """ pidfile = os.environ['HOME'] + "/.specto/" + "specto.pid" if not os.path.exists(pidfile): f = open(pidfile, "w") f.close() os.chmod(pidfile, 0600) #see if specto is already running f = open(pidfile, "r") pid = f.readline() f.close() if pid: p = os.system("ps --no-heading --pid " + pid) p_name = os.popen("ps -f --pid " + pid).read() if p == 0 and "specto" in p_name: self.logger.log(_("Specto is already running!"), "critical", self.__class__) sys.exit(0) #write the pid file f = open(pidfile, "w") f.write(str(os.getpid())) f.close() def recreate_tray(self, *args): """ Recreate a tray icon if the notification area unexpectedly quits. """ try: self.tray.destroy() except: pass self.tray = "" self.tray = Tray(self) self.count_updated_watches() def create_all_watches(self, value_db): """ Create the watches at startup. """ for i in value_db: self.create_watch(value_db[i]) if GTK: while gtk.events_pending(): gtk.main_iteration_do(False) if self.specto_gconf.get_entry("show_deactivated_watches") == True: self.notifier.wTree.get_widget("display_all_watches").set_active( True) self.notifier.toggle_show_deactivated_watches( startup=True ) #True makes startup=True, only used on the first startup to avoid duplicate watches. #start the active watches if self.notifier_initialized: self.notifier.refresh() def create_watch(self, values): """ Add a watch to the watches repository. """ id = len(self.watch_db) if values['type'] == 0: #add a website from spectlib.watch_web_static import Web_watch self.watch_db[id] = Web_watch( self, values['name'], values['refresh'], values['uri'], id, values['error_margin']) #TODO: Authentication elif values['type'] == 1: #add an email if int(values['prot']) == 0: #check if pop3, imap or gmail is used import spectlib.watch_mail_pop3 self.watch_db[id] = spectlib.watch_mail_pop3.Mail_watch( values['refresh'], values['host'], values['username'], values['password'], values['ssl'], self, id, values['name']) elif int(values['prot']) == 1: import spectlib.watch_mail_imap self.watch_db[id] = spectlib.watch_mail_imap.Mail_watch( values['refresh'], values['host'], values['username'], values['password'], values['ssl'], self, id, values['name']) else: import spectlib.watch_mail_gmail self.watch_db[id] = spectlib.watch_mail_gmail.Mail_watch( values['refresh'], values['username'], values['password'], self, id, values['name']) elif values['type'] == 2: #add a file from spectlib.watch_file import File_watch self.watch_db[id] = File_watch(values['refresh'], values['file'], values['mode'], self, id, values['name']) elif values['type'] == 3: #add a process watch from spectlib.watch_process import Process_watch self.watch_db[id] = Process_watch(values['refresh'], values['process'], self, id, values['name']) elif values['type'] == 4: #add a port watch from spectlib.watch_port import Port_watch self.watch_db[id] = Port_watch(values['refresh'], values['port'], self, id, values['name']) elif values['type'] == 5: #add a google reader account from spectlib.watch_web_greader import Google_reader self.watch_db[id] = Google_reader(values['refresh'], values['username'], values['password'], self, id, values['name']) try: self.watch_db[id].updated = values['updated'] except: self.watch_db[id].updated = False try: self.watch_db[id].active = values['active'] except: self.watch_db[id].active = True try: self.watch_db[id].last_updated = values['last_updated'] except: self.watch_db[id].last_updated = _("No updates yet.") if GTK: if not self.notifier_initialized: self.notifier = Notifier(self) #self.notifier.restore_size_and_position()#fixme: is this necessary? this makes specto output stuff for nothing. self.notifier.add_notifier_entry(values['name'], values['type'], id) try: if values['updated']: self.toggle_updated(id) except: pass try: if values['active'] == False: self.notifier.deactivate(id) except: pass return id def clear_watch(self, id): """ Mark a watch as not updated. """ new_values = {} self.watch_db[id].updated = False new_values['name'] = self.watch_db[id].name new_values['updated'] = False self.watch_io.write_options(new_values) self.count_updated_watches() def mark_watch_busy(self, progress, id): """ Display a refresh icon when updating watches. """ self.notifier.toggle_updating(progress, id) def set_status(self, id, status): """ Set the status from a watch (active/not active). """ new_values = {} new_values['name'] = self.watch_db[id].name new_values['active'] = status if status == False: new_values['updated'] = False self.watch_db[id].updated = False self.notifier.clear_watch('', id) self.watch_db[id].active = status self.watch_io.write_options(new_values) def replace_name(self, orig, new): """ Replace the name from a watch in watches.list. """ self.watch_io.replace_name(orig, new) def start_watch(self, id): """ Start a watch. """ self.notifier.toggle_updating(True, id) self.watch_db[id].start_watch() self.logger.log( _("watch \"%s\" started") % self.watch_db[id].name, "info", self.__class__) def stop_watch(self, id): """ Stop a watch. """ self.watch_db[id].stop_watch() self.logger.log( _("watch \"%s\" stopped") % self.watch_db[id].name, "info", self.__class__) def add_watch(self, values): """ Add a new watch. """ new_values = {} new_values['name'] = values['name'] new_values['type'] = values['type'] new_values['refresh'] = self.set_interval(values['refresh_value'], values['refresh_unit']) if int(values['type']) == 0: #web new_values['uri'] = values['url'] new_values['error_margin'] = values['error_margin'] elif int(values['type']) == 1: #mail if int(values['prot']) == 0 or int(values['prot']) == 1: new_values['host'] = values['host'] new_values['ssl'] = values['ssl'] new_values['username'] = values['username'] new_values['password'] = values['password'] new_values['prot'] = values['prot'] elif int(values['type']) == 2: #file new_values['file'] = values['file'] new_values['mode'] = values['mode'] elif int(values['type']) == 3: #process new_values['process'] = values['process'] elif int(values['type']) == 4: #port new_values['port'] = values['port'] elif int(values['type']) == 5: #google reader new_values['username'] = values['username'] new_values['password'] = values['password'] id = self.create_watch(new_values) self.start_watch(id) self.watch_io.write_options(new_values) def edit_watch(self, values): """ Edit a watch. """ new_values = {} new_values['name'] = values['name'] new_values['type'] = values['type'] new_values['refresh'] = self.set_interval(values['refresh_value'], values['refresh_unit']) if int(values['type']) == 0: #web new_values['uri'] = values['url'] new_values['error_margin'] = values['error_margin'] elif int(values['type']) == 1: #mail if int( values['prot'] ) != 2: #gmail doesn't need a host and SSL it seems, so this is updated only of it's another kind of mail watch new_values['host'] = values['host'] new_values['ssl'] = values['ssl'] new_values['username'] = values['username'] new_values['password'] = values['password'] new_values['prot'] = values['prot'] elif int(values['type']) == 2: #file new_values['file'] = values['file'] elif int(values['type']) == 3: #process new_values['process'] = values['process'] elif int(values['type']) == 4: #port new_values['port'] = values['port'] elif int(values['type']) == 5: #google reader new_values['username'] = values['username'] new_values['password'] = values['password'] self.watch_io.write_options(new_values) self.notifier.show_watch_info() def remove_watch(self, name, id): """ Remove a watch. """ try: self.stop_watch(id) except: pass del self.watch_db[id] self.count_updated_watches() self.watch_io.remove_watch( name ) #do not clear the watch after removing it or it will mess up the watches.list self.notifier.model.remove(self.notifier.iter[id]) def find_watch(self, name): """ Returns the key of a watch or None if it doesn't exists. """ k = -1 for key in self.watch_db.iterkeys(): if self.watch_db[key].name == name: k = key break return k def check_unique_watch(self, name): """ Check if the watch name is unique. """ if self.watch_io.search_watch(name) and GTK: return False else: return True def count_updated_watches(self): """ Count the number of updated watches for the tooltip. """ tooltip_updated_watches = { 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 } #don't forget to update this if you are implementing a new type of watch for i in self.watch_db: if self.watch_db[i].updated == True: self.tray.set_icon_state_excited( ) #change the tray icon color to orange tooltip_updated_watches[self.watch_db[i].type] += 1 if tooltip_updated_watches.values() == [ 0, 0, 0, 0, 0, 0 ]: #there are no more watches to clear, reset the tray icon self.tray.set_icon_state_normal() self.notifier.wTree.get_widget("button_clear_all").set_sensitive( False) self.tray.show_tooltip(tooltip_updated_watches) def toggle_updated(self, id): """ When a watch is updated: change name in notifier window, change the tray icon state, play a sound, ... """ new_values = {} now = datetime.today() #TODO:XXX:GETTEXT new_values['last_updated'] = now.strftime("%A %d %b %Y %H:%M") self.watch_db[id].last_updated = now.strftime("%A %d %b %Y %H:%M") self.watch_db[id].updated = True if self.notifier_initialized: self.notifier.toggle_updated(id) new_values['name'] = self.watch_db[id].name new_values['updated'] = True self.watch_io.write_options( new_values) #write the watches state in watches.list self.count_updated_watches() #show the tooltip def toggle_all_cleared(self): """ Set the state from all the watches back to 'not updated'. """ for i in self.watch_db: new_values = {} self.watch_db[i].updated = False new_values['name'] = self.watch_db[i].name new_values['updated'] = False self.watch_io.write_options(new_values) self.count_updated_watches() def set_interval(self, refresh, refresh_unit): """ Set the interval between the update checks. refresh = number refresh_unit = days, hours, minutes,... in values of 0, 1, 2, 3. """ new_refresh = 0 if refresh_unit == 0: #seconds new_refresh = refresh * 1000 elif refresh_unit == 1: #minutes new_refresh = refresh * 60 * 1000 elif refresh_unit == 2: #hours new_refresh = (refresh * 60) * 60 * 1000 elif refresh_unit == 3: #days new_refresh = ((refresh * 60) * 60) * 24 * 1000 return new_refresh def get_interval(self, value): """ Get the interval between 2 updates. """ if ((value / 60) / 60) / 24 / 1000 > 0: refresh_value = ((value / 60) / 60) / 24 / 1000 type = 3 elif (value / 60) / 60 / 1000 > 0: refresh_value = (value / 60) / 60 / 1000 type = 2 elif value / 60 / 1000 > 0: refresh_value = value / 60 / 1000 type = 1 else: refresh_value = value / 1000 type = 0 return refresh_value, type def toggle_notifier(self, *args): """ Toggle the state of the notifier, hidden or shown. It will save the size, position, and the last state when you closed Specto. """ #Creating the notifier window, but keeping it hidden if not self.notifier_initialized and self.notifier_keep_hidden: self.notifier = Notifier(self) #self.notifier.restore_size_and_position()#this is NOT needed here because it already does that on instanciation on the line above -kiddo self.notifier.notifier.hide() #Creating the notifier window and displaying it elif not self.notifier_initialized and not self.notifier_keep_hidden: self.notifier = Notifier(self) #self.notifier.restore_size_and_position()#this is NOT needed here because it already does that on instanciation on the line above -kiddo self.notifier.notifier.show() elif self.notifier_initialized: if self.notifier.get_state() == True and self.notifier_keep_hidden: self.logger.log(_("notifier: reappear"), "debug", self.__class__) self.specto_gconf.set_entry("show_notifier", True) self.notifier.restore_size_and_position( ) #to make sure that the x and y positions don't jump around self.notifier.notifier.show() elif self.notifier.get_state( ) == True and not self.notifier_keep_hidden: self.logger.log(_("notifier: hide"), "debug", self.__class__) self.specto_gconf.set_entry("show_notifier", False) self.notifier.notifier.hide() else: self.logger.log(_("notifier: reappear"), "debug", self.__class__) self.specto_gconf.set_entry("show_notifier", True) self.notifier.restore_size_and_position( ) #to make sure that the x and y positions don't jump around self.notifier.notifier.show() self.notifier_initialized = True def show_preferences(self, *args): """ Show the preferences window. """ if not self.preferences_initialized or self.preferences.get_state( ) == True: self.logger.log(_("preferences: create"), "debug", self.__class__) self.pref = Preferences(self) else: self.logger.log(_("preferences: reappear"), "debug", self.__class__) self.pref.show() def show_error_log(self, *args): """ Show the error log. """ if self.error_l == "": self.error_l = Log_dialog(self) self.logger.log(_("error log: create"), "debug", self.__class__) elif self.error_l.log_dialog.flags() & gtk.MAPPED: self.logger.log(_("error log: already visible"), "debug", self.__class__) else: self.error_l = Log_dialog(self) self.logger.log(_("error log: recreate"), "debug", self.__class__) def show_add_watch(self, *args): """ Show the add watch window. """ if self.add_w == "": self.add_w = Add_watch(self) self.logger.log(_("add watch: create"), "debug", self.__class__) elif self.add_w.add_watch.flags() & gtk.MAPPED: self.logger.log(_("add watch: already visible"), "debug", self.__class__) else: self.add_w = Add_watch(self) self.logger.log(_("add watch: recreate"), "debug", self.__class__) def show_edit_watch(self, id, *args): """ Show the edit watch window. """ selected = "" if not id == -1: selected = self.watch_db[id] else: for i in self.watch_db: if self.watch_db[i].name == args[0]: selected = self.watch_db[i] if self.edit_w == "": self.edit_w = Edit_watch(self, selected) self.logger.log(_("edit watch: create"), "debug", self.__class__) elif self.edit_w.edit_watch.flags() & gtk.MAPPED: self.logger.log(_("edit watch: already visible"), "debug", self.__class__) else: self.edit_w = Edit_watch(self, selected) self.logger.log(_("edit watch: recreate"), "debug", self.__class__) def show_about(self, *args): """ Show the about window. """ if self.about == "": self.about = About(self) elif self.about.about.flags() & gtk.MAPPED: pass else: self.about = About(self) def show_help(self, *args): """ Show the help web page. """ self.util.show_webpage("http://code.google.com/p/specto/w/list") def import_export_watches(self, action): """ Show the import/export window. """ if self.export == "": self.export = Import_watch(self, action) elif self.export.import_watch.flags() & gtk.MAPPED: pass else: self.export = Import_watch(self, action) def quit(self, *args): """ Save the save and position from the notifier and quit Specto. """ if self.notifier.get_state() == True and not self.notifier_keep_hidden: self.notifier.save_size_and_position( ) #when quitting specto abruptly, remember the notifier window properties try: gtk.main_quit() except: #create a close dialog dialog = gtk.Dialog( _("Cannot quit yet"), None, gtk.DIALOG_MODAL | gtk.DIALOG_NO_SEPARATOR | gtk.DIALOG_DESTROY_WITH_PARENT, None) #HIG tricks dialog.set_has_separator(False) dialog.add_button(_("Murder!"), 3) dialog.add_button(gtk.STOCK_CANCEL, -1) dialog.label_hbox = gtk.HBox(spacing=6) icon = gtk.Image() icon.set_from_icon_name("dialog-warning", 64) dialog.label_hbox.pack_start(icon, True, True, 6) icon.show() label = gtk.Label( _('<b><big>Specto is currently busy and cannot quit yet.</big></b>\n\nThis may be because it is checking for watch updates.\nHowever, you can try forcing it to quit by clicking the murder button.' )) label.set_use_markup(True) dialog.label_hbox.pack_start( label, True, True, 6 ) #here, pack means "cram the label right at the start of the vbox before the buttons" label.show() dialog.vbox.pack_start(dialog.label_hbox, True, True, 12) dialog.label_hbox.show() icon = gtk.gdk.pixbuf_new_from_file(self.PATH + 'icons/specto_window_icon.svg') dialog.set_icon(icon) answer = dialog.run() if answer == 3: try: #go figure, it never works! self.notifier.stop_refresh = True sys.exit(0) except: #kill the specto process with killall os.system('killall specto') else: dialog.destroy()
class Specto: """ The main Specto class. """ add_w = "" edit_w = "" error_l = "" about = "" export = "" def __init__(self): self.DEBUG = DEBUG import gettext #this is for the glade files self.glade_gettext = gettext.textdomain("specto") self.logger = Logger(self) self.check_instance() #see if specto is already running self.util = util self.PATH = self.util.get_path() self.specto_gconf = specto_gconf self.check_default_settings()#if this is the first run of specto, set the default values for gconf. Whenever you add some gconf preference for specto, this function will also need to be updated. self.GTK = GTK if GTK: self.tray = Tray(self) self.icon_theme = gtk.icon_theme_get_default() self.watch_db = {} self.watch_io = Watch_io() watch_value_db = self.watch_io.read_options() self.preferences_initialized = False self.notifier_initialized = False #listen for gconf keys self.specto_gconf.notify_entry("debug_mode", self.key_changed, "debug") self.connection_manager = conmgr.get_net_listener() if GTK: if self.specto_gconf.get_entry("always_show_icon") == False: #if the user has not requested the tray icon to be shown at all times, it's impossible that the notifier is hidden on startup, so we must show it. self.notifier_keep_hidden = False self.toggle_notifier() elif self.specto_gconf.get_entry("show_notifier")==True: self.notifier_keep_hidden = False self.toggle_notifier() elif self.specto_gconf.get_entry("show_notifier")==False: self.notifier_keep_hidden = True self.toggle_notifier() self.notifier_keep_hidden = False else:#just in case the entry was never created in gconf self.notifier_keep_hidden = False self.toggle_notifier() self.create_all_watches(watch_value_db) if GTK: gtk.main() else: self.go = gobject.MainLoop() self.go.run() def key_changed(self, *args): """ Listen for gconf keys. """ label = args[3] if label == "debug": self.DEBUG = self.specto_gconf.get_entry("debug_mode") def check_default_settings(self): """ This is used to set the default settings properly the first time Specto is run, without using gconf schemas """ self.default_settings=( ["always_show_icon", False], #having it True would be against the HIG! ["debug_mode", False], ["follow_website_redirects", True], ["pop_toast_duration", 5], ["pop_toast", True], ["show_deactivated_watches", True], ["show_in_windowlist", True], ["show_notifier", True], ["show_toolbar", True], ["sort_function", "name"], ["sort_order", "asc"], ["update_sound", "/usr/share/sounds/ekiga/voicemail.wav"], ["use_update_sound", False], ["window_notifier_height", 500], ["window_notifier_width", 500] ) for default_setting in self.default_settings: if self.specto_gconf.get_entry(default_setting[0]) == None: #the key has no user-defined value or does not exist self.specto_gconf.set_entry(default_setting[0], default_setting[1]) def check_instance(self): """ Check if specto is already running. """ pidfile = os.environ['HOME'] + "/.specto/" + "specto.pid" if not os.path.exists(pidfile): f = open(pidfile, "w") f.close() os.chmod(pidfile, 0600) #see if specto is already running f=open(pidfile, "r") pid = f.readline() f.close() if pid: p=os.system("ps --no-heading --pid " + pid) p_name=os.popen("ps -f --pid " + pid).read() if p == 0 and "specto" in p_name: self.logger.log(_("Specto is already running!"), "critical", self.__class__) sys.exit(0) #write the pid file f=open(pidfile, "w") f.write(str(os.getpid())) f.close() def recreate_tray(self, *args): """ Recreate a tray icon if the notification area unexpectedly quits. """ try:self.tray.destroy() except:pass self.tray = "" self.tray = Tray(self) self.count_updated_watches() def create_all_watches(self, value_db): """ Create the watches at startup. """ for i in value_db: self.create_watch(value_db[i]) if GTK: while gtk.events_pending(): gtk.main_iteration_do(False) if self.specto_gconf.get_entry("show_deactivated_watches")== True: self.notifier.wTree.get_widget("display_all_watches").set_active(True) self.notifier.toggle_show_deactivated_watches(startup=True)#True makes startup=True, only used on the first startup to avoid duplicate watches. #start the active watches if self.notifier_initialized: self.notifier.refresh() def create_watch(self, values): """ Add a watch to the watches repository. """ id = len(self.watch_db) if values['type'] == 0: #add a website from spectlib.watch_web_static import Web_watch self.watch_db[id] = Web_watch(self, values['name'], values['refresh'], values['uri'], id, values['error_margin']) #TODO: Authentication elif values['type'] == 1: #add an email if int(values['prot']) == 0: #check if pop3, imap or gmail is used import spectlib.watch_mail_pop3 self.watch_db[id] = spectlib.watch_mail_pop3.Mail_watch(values['refresh'], values['host'], values['username'], values['password'], values['ssl'], self, id, values['name']) elif int(values['prot']) == 1: import spectlib.watch_mail_imap self.watch_db[id] = spectlib.watch_mail_imap.Mail_watch(values['refresh'], values['host'], values['username'], values['password'], values['ssl'], self, id, values['name']) else: import spectlib.watch_mail_gmail self.watch_db[id] = spectlib.watch_mail_gmail.Mail_watch(values['refresh'], values['username'], values['password'], self, id, values['name']) elif values['type'] == 2: #add a file from spectlib.watch_file import File_watch self.watch_db[id] = File_watch(values['refresh'], values['file'], values['mode'], self, id, values['name']) elif values['type'] == 3: #add a process watch from spectlib.watch_process import Process_watch self.watch_db[id] = Process_watch(values['refresh'], values['process'], self, id, values['name']) elif values['type'] == 4: #add a port watch from spectlib.watch_port import Port_watch self.watch_db[id] = Port_watch(values['refresh'], values['port'], self, id, values['name']) elif values['type'] == 5: #add a google reader account from spectlib.watch_web_greader import Google_reader self.watch_db[id] = Google_reader(values['refresh'], values['username'], values['password'], self, id, values['name']) try: self.watch_db[id].updated = values['updated'] except: self.watch_db[id].updated = False try: self.watch_db[id].active = values['active'] except: self.watch_db[id].active = True try: self.watch_db[id].last_updated = values['last_updated'] except: self.watch_db[id].last_updated = _("No updates yet.") if GTK: if not self.notifier_initialized: self.notifier = Notifier(self) #self.notifier.restore_size_and_position()#fixme: is this necessary? this makes specto output stuff for nothing. self.notifier.add_notifier_entry(values['name'], values['type'], id) try: if values['updated']: self.toggle_updated(id) except: pass try: if values['active'] == False: self.notifier.deactivate(id) except: pass return id def clear_watch(self, id): """ Mark a watch as not updated. """ new_values = {} self.watch_db[id].updated = False new_values['name'] = self.watch_db[id].name new_values['updated'] = False self.watch_io.write_options(new_values) self.count_updated_watches() def mark_watch_busy(self, progress, id): """ Display a refresh icon when updating watches. """ self.notifier.toggle_updating(progress, id) def set_status(self, id, status): """ Set the status from a watch (active/not active). """ new_values = {} new_values['name'] = self.watch_db[id].name new_values['active'] = status if status == False: new_values['updated'] = False self.watch_db[id].updated = False self.notifier.clear_watch('',id) self.watch_db[id].active = status self.watch_io.write_options(new_values) def replace_name(self, orig, new): """ Replace the name from a watch in watches.list. """ self.watch_io.replace_name(orig, new) def start_watch(self, id): """ Start a watch. """ self.notifier.toggle_updating(True, id) self.watch_db[id].start_watch() self.logger.log(_("watch \"%s\" started") % self.watch_db[id].name, "info", self.__class__) def stop_watch(self, id): """ Stop a watch. """ self.watch_db[id].stop_watch() self.logger.log(_("watch \"%s\" stopped") % self.watch_db[id].name, "info", self.__class__) def add_watch(self, values): """ Add a new watch. """ new_values = {} new_values['name'] = values['name'] new_values['type'] = values['type'] new_values['refresh'] = self.set_interval(values['refresh_value'], values['refresh_unit']) if int(values['type']) == 0: #web new_values['uri'] = values['url'] new_values['error_margin'] = values['error_margin'] elif int(values['type']) == 1: #mail if int(values['prot']) == 0 or int(values['prot']) == 1: new_values['host'] = values['host'] new_values['ssl'] = values['ssl'] new_values['username'] = values['username'] new_values['password'] = values['password'] new_values['prot'] = values['prot'] elif int(values['type']) == 2: #file new_values['file'] = values['file'] new_values['mode'] = values['mode'] elif int(values['type']) == 3: #process new_values['process'] = values['process'] elif int(values['type']) == 4: #port new_values['port'] = values['port'] elif int(values['type']) == 5: #google reader new_values['username'] = values['username'] new_values['password'] = values['password'] id = self.create_watch(new_values) self.start_watch(id) self.watch_io.write_options(new_values) def edit_watch(self, values): """ Edit a watch. """ new_values = {} new_values['name'] = values['name'] new_values['type'] = values['type'] new_values['refresh'] = self.set_interval(values['refresh_value'], values['refresh_unit']) if int(values['type']) == 0: #web new_values['uri'] = values['url'] new_values['error_margin'] = values['error_margin'] elif int(values['type']) == 1: #mail if int(values['prot']) != 2: #gmail doesn't need a host and SSL it seems, so this is updated only of it's another kind of mail watch new_values['host'] = values['host'] new_values['ssl'] = values['ssl'] new_values['username'] = values['username'] new_values['password'] = values['password'] new_values['prot'] = values['prot'] elif int(values['type']) == 2: #file new_values['file'] = values['file'] elif int(values['type']) == 3: #process new_values['process'] = values['process'] elif int(values['type']) == 4: #port new_values['port'] = values['port'] elif int(values['type']) == 5: #google reader new_values['username'] = values['username'] new_values['password'] = values['password'] self.watch_io.write_options(new_values) self.notifier.show_watch_info() def remove_watch(self, name, id): """ Remove a watch. """ try: self.stop_watch(id) except: pass del self.watch_db[id] self.count_updated_watches() self.watch_io.remove_watch(name)#do not clear the watch after removing it or it will mess up the watches.list self.notifier.model.remove(self.notifier.iter[id]) def find_watch(self, name): """ Returns the key of a watch or None if it doesn't exists. """ k = -1 for key in self.watch_db.iterkeys(): if self.watch_db[key].name == name: k = key break return k def check_unique_watch(self, name): """ Check if the watch name is unique. """ if self.watch_io.search_watch(name) and GTK: return False else: return True def count_updated_watches(self): """ Count the number of updated watches for the tooltip. """ tooltip_updated_watches = { 0:0,1:0,2:0,3:0,4:0,5:0 }#don't forget to update this if you are implementing a new type of watch for i in self.watch_db: if self.watch_db[i].updated == True: self.tray.set_icon_state_excited()#change the tray icon color to orange tooltip_updated_watches[self.watch_db[i].type] += 1 if tooltip_updated_watches.values() == [0,0,0,0,0,0]:#there are no more watches to clear, reset the tray icon self.tray.set_icon_state_normal() self.notifier.wTree.get_widget("button_clear_all").set_sensitive(False) self.tray.show_tooltip(tooltip_updated_watches) def toggle_updated(self, id): """ When a watch is updated: change name in notifier window, change the tray icon state, play a sound, ... """ new_values = {} now = datetime.today() #TODO:XXX:GETTEXT new_values['last_updated'] = now.strftime("%A %d %b %Y %H:%M") self.watch_db[id].last_updated = now.strftime("%A %d %b %Y %H:%M") self.watch_db[id].updated = True if self.notifier_initialized: self.notifier.toggle_updated(id) new_values['name'] = self.watch_db[id].name new_values['updated'] = True self.watch_io.write_options(new_values) #write the watches state in watches.list self.count_updated_watches() #show the tooltip def toggle_all_cleared(self): """ Set the state from all the watches back to 'not updated'. """ for i in self.watch_db: new_values = {} self.watch_db[i].updated = False new_values['name'] = self.watch_db[i].name new_values['updated'] = False self.watch_io.write_options(new_values) self.count_updated_watches() def set_interval(self, refresh, refresh_unit): """ Set the interval between the update checks. refresh = number refresh_unit = days, hours, minutes,... in values of 0, 1, 2, 3. """ new_refresh = 0 if refresh_unit == 0:#seconds new_refresh = refresh * 1000 elif refresh_unit == 1:#minutes new_refresh = refresh * 60 * 1000 elif refresh_unit == 2:#hours new_refresh = (refresh * 60) * 60 * 1000 elif refresh_unit == 3:#days new_refresh = ((refresh * 60) * 60) * 24 *1000 return new_refresh def get_interval(self, value): """ Get the interval between 2 updates. """ if ((value / 60) / 60) / 24 / 1000 > 0: refresh_value = ((value / 60) / 60) / 24 / 1000 type = 3 elif (value / 60) / 60 / 1000 > 0: refresh_value = (value / 60) / 60 / 1000 type = 2 elif value / 60 / 1000 > 0: refresh_value = value / 60 / 1000 type = 1 else: refresh_value = value / 1000 type = 0 return refresh_value, type def toggle_notifier(self, *args): """ Toggle the state of the notifier, hidden or shown. It will save the size, position, and the last state when you closed Specto. """ #Creating the notifier window, but keeping it hidden if not self.notifier_initialized and self.notifier_keep_hidden: self.notifier = Notifier(self) #self.notifier.restore_size_and_position()#this is NOT needed here because it already does that on instanciation on the line above -kiddo self.notifier.notifier.hide() #Creating the notifier window and displaying it elif not self.notifier_initialized and not self.notifier_keep_hidden: self.notifier = Notifier(self) #self.notifier.restore_size_and_position()#this is NOT needed here because it already does that on instanciation on the line above -kiddo self.notifier.notifier.show() elif self.notifier_initialized: if self.notifier.get_state()==True and self.notifier_keep_hidden: self.logger.log(_("notifier: reappear"), "debug", self.__class__) self.specto_gconf.set_entry("show_notifier", True) self.notifier.restore_size_and_position()#to make sure that the x and y positions don't jump around self.notifier.notifier.show() elif self.notifier.get_state()==True and not self.notifier_keep_hidden: self.logger.log(_("notifier: hide"), "debug", self.__class__) self.specto_gconf.set_entry("show_notifier", False) self.notifier.notifier.hide() else: self.logger.log(_("notifier: reappear"), "debug", self.__class__) self.specto_gconf.set_entry("show_notifier", True) self.notifier.restore_size_and_position()#to make sure that the x and y positions don't jump around self.notifier.notifier.show() self.notifier_initialized = True def show_preferences(self, *args): """ Show the preferences window. """ if not self.preferences_initialized or self.preferences.get_state() == True: self.logger.log(_("preferences: create"), "debug", self.__class__) self.pref=Preferences(self) else: self.logger.log(_("preferences: reappear"), "debug", self.__class__) self.pref.show() def show_error_log(self, *args): """ Show the error log. """ if self.error_l == "": self.error_l= Log_dialog(self) self.logger.log(_("error log: create"), "debug", self.__class__) elif self.error_l.log_dialog.flags() & gtk.MAPPED: self.logger.log(_("error log: already visible"), "debug", self.__class__) else: self.error_l= Log_dialog(self) self.logger.log(_("error log: recreate"), "debug", self.__class__) def show_add_watch(self, *args): """ Show the add watch window. """ if self.add_w == "": self.add_w= Add_watch(self) self.logger.log(_("add watch: create"), "debug", self.__class__) elif self.add_w.add_watch.flags() & gtk.MAPPED: self.logger.log(_("add watch: already visible"), "debug", self.__class__) else: self.add_w= Add_watch(self) self.logger.log(_("add watch: recreate"), "debug", self.__class__) def show_edit_watch(self, id, *args): """ Show the edit watch window. """ selected = "" if not id == -1: selected = self.watch_db[id] else: for i in self.watch_db: if self.watch_db[i].name == args[0]: selected = self.watch_db[i] if self.edit_w == "": self.edit_w= Edit_watch(self, selected) self.logger.log(_("edit watch: create"), "debug", self.__class__) elif self.edit_w.edit_watch.flags() & gtk.MAPPED: self.logger.log(_("edit watch: already visible"), "debug", self.__class__) else: self.edit_w= Edit_watch(self, selected) self.logger.log(_("edit watch: recreate"), "debug", self.__class__) def show_about(self, *args): """ Show the about window. """ if self.about == "": self.about = About(self) elif self.about.about.flags() & gtk.MAPPED: pass else: self.about = About(self) def show_help(self, *args): """ Show the help web page. """ self.util.show_webpage("http://code.google.com/p/specto/w/list") def import_export_watches(self, action): """ Show the import/export window. """ if self.export == "": self.export = Import_watch(self, action) elif self.export.import_watch.flags() & gtk.MAPPED: pass else: self.export = Import_watch(self, action) def quit(self, *args): """ Save the save and position from the notifier and quit Specto. """ if self.notifier.get_state()==True and not self.notifier_keep_hidden: self.notifier.save_size_and_position()#when quitting specto abruptly, remember the notifier window properties try: gtk.main_quit() except: #create a close dialog dialog = gtk.Dialog(_("Cannot quit yet"), None, gtk.DIALOG_MODAL | gtk.DIALOG_NO_SEPARATOR | gtk.DIALOG_DESTROY_WITH_PARENT, None) #HIG tricks dialog.set_has_separator(False) dialog.add_button(_("Murder!"), 3) dialog.add_button(gtk.STOCK_CANCEL, -1) dialog.label_hbox = gtk.HBox(spacing=6) icon = gtk.Image() icon.set_from_icon_name("dialog-warning", 64) dialog.label_hbox.pack_start(icon, True, True, 6) icon.show() label = gtk.Label(_('<b><big>Specto is currently busy and cannot quit yet.</big></b>\n\nThis may be because it is checking for watch updates.\nHowever, you can try forcing it to quit by clicking the murder button.')) label.set_use_markup(True) dialog.label_hbox.pack_start(label, True, True, 6)#here, pack means "cram the label right at the start of the vbox before the buttons" label.show() dialog.vbox.pack_start(dialog.label_hbox, True, True, 12) dialog.label_hbox.show() icon = gtk.gdk.pixbuf_new_from_file(self.PATH + 'icons/specto_window_icon.svg' ) dialog.set_icon(icon) answer = dialog.run() if answer == 3: try:#go figure, it never works! self.notifier.stop_refresh = True sys.exit(0) except: #kill the specto process with killall os.system('killall specto') else: dialog.destroy()
class Notifier: """ Class to create the main specto window """ add_w = "" edit_w = "" error_l = "" about = "" export_watch = "" import_watch = "" def __init__(self, specto): """ In this init we are going to display the main notifier window. """ self.specto = specto uifile = os.path.join(self.specto.PATH, "uis/notifier.ui") windowname = "notifier" self.builder = gtk.Builder() self.builder.set_translation_domain("specto") self.builder.add_from_file(uifile) self.notifier = self.builder.get_object("notifier") if INDICATOR: self.indicator = Indicator(specto) self.tray = None else: self.tray = Tray(specto, self) self.indicator = None if SOUND: self.sound = Sound() else: self.sound = None self.balloon = NotificationToast(specto, self) self.preferences_initialized = False #create tree self.iter = {} self.model = gtk.ListStore(gobject.TYPE_BOOLEAN, gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING, pango.Weight) #catch some events dic = { "on_add_activate": self.show_add_watch_menu, "on_edit_activate": self.show_edit_watch, "on_clear_all_activate": self.mark_all_as_read, "on_preferences_activate": self.show_preferences, "on_refresh_activate": self.refresh_all_watches, "on_close_activate": self.close_event, "on_quit_activate": self.delete_event, "on_import_watches_activate": self.import_watches, "on_export_watches_activate": self.export_watches, "on_error_log_activate": self.show_error_log, "on_display_all_watches_activate": self.toggle_show_deactivated_watches, "on_display_toolbar_activate": self.toggle_display_toolbar, "on_help_activate": self.show_help, "on_about_activate": self.show_about, "on_treeview_row_activated": self.open_watch_callback, "on_btnOpen_clicked": self.open_watch_callback, "on_btnClear_clicked": self.mark_watch_as_read, "on_treeview_cursor_changed": self.show_watch_info, "on_btnEdit_clicked": self.show_edit_watch, "on_by_watch_type_activate": self.sort_type, "on_by_name_activate": self.sort_name, "on_by_watch_active_activate": self.sort_active, "on_remove_clicked": self.remove_watch, "on_clear_activate": self._mark_watch_as_read, "on_remove_activate": self.remove_watch } self.builder.connect_signals(dic) self.notifier.set_icon_from_file(self.specto.LOGO_PATH) self.specto.notifier_initialized = True self.create_notifier_gui() self.stop_refresh = False def mark_watch_as_read(self, widget, *id): """ Call the main function to mark the watch as read and reset the name in the notifier. If widget == '' then id will be used to mark the watch as read else the selected watch will be marked as read. """ try: id = id[0] except: model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) watch = self.specto.watch_db[id] watch.mark_as_read() self.model.set(self.iter[id], 2, watch.name, 5, pango.WEIGHT_NORMAL) if self.model.iter_is_valid(self.iter[id]) and not watch.error: self.model.set_value(self.iter[id], 1, self.get_icon(watch.icon, 50, False)) if watch.changed == False: self.builder.get_object("btnClear").set_sensitive(False) else: self.builder.get_object("btnClear").set_sensitive(True) #check if all watches has been marked as read changed_watches = False changes = self.specto.watch_db.count_changed_watches() for changed in changes.values(): if changed > 0: changed_watches = True if changed_watches == False: self.builder.get_object("button_clear_all").set_sensitive(False) def mark_all_as_read(self, widget): """ Call the main function to mark all watches as read and reset the name in the notifier. """ self.builder.get_object("btnClear").set_sensitive(False) self.builder.get_object("button_clear_all").set_sensitive(False) self.builder.get_object("clear_all1").set_sensitive(False) for watch in self.specto.watch_db: if self.model.iter_is_valid(self.iter[watch.id]): self.mark_watch_as_read("", watch.id) def refresh_all_watches(self, *widget): """ Call the main funcion to refresh all active watches and change refresh icon to stop. """ if self.builder.get_object( "button_refresh").get_stock_id() == "gtk-refresh": self.builder.get_object("button_refresh").set_stock_id( "gtk-stop") #menu item, does not allow changing label self.builder.get_object("button_refresh").set_label(_("Stop")) self.builder.get_object("button_add").set_sensitive(False) self.builder.get_object("btnEdit").set_sensitive(False) for i in self.iter: if self.stop_refresh == True: self.stop_refresh = False break try: iter = self.model.get_iter(i) if self.model.iter_is_valid(iter): model = self.model id = int(model.get_value(iter, 3)) except: break if self.specto.watch_db[id].active == True: try: self.specto.watch_db[id].stop() except: pass self.specto.watch_db[id].start() self.builder.get_object("button_refresh").set_stock_id( "gtk-refresh") #menu item, does not allow changing label self.builder.get_object("button_refresh").set_label( _("Refresh All")) self.builder.get_object("button_add").set_sensitive(True) self.builder.get_object("btnEdit").set_sensitive(True) else: self.stop_refresh = True def mark_error(self, error_message): error_dialog = ErrorDialog(self.specto, error_message) def mark_watch_status(self, status, id): """ show the right icon for the status from the watch. """ watch = self.specto.watch_db[id] statusbar = self.builder.get_object("statusbar1") icon = self.get_icon("error", 50, False) try: if status == "checking": icon = self.get_icon("reload", 0, False) statusbar.push(0, (datetime.today().strftime("%H:%M") + " - " + _('The watch "%s" is checking.') % watch.name)) elif status == "idle": if self.tray: self.tray.show_tooltip() #check if all watches are cleared if watch.changed == True: self.model.set(self.iter[id], 2, "%s" % watch.name, 5, pango.WEIGHT_BOLD) self.builder.get_object("button_clear_all").set_sensitive( True) self.builder.get_object("clear_all1").set_sensitive(True) icon = self.get_icon(watch.icon, 0, False) else: self.model.set(self.iter[id], 2, "%s" % watch.name, 5, pango.WEIGHT_NORMAL) self.builder.get_object("clear_all1").set_sensitive(False) icon = self.get_icon(watch.icon, 50, False) statusbar.push( 0, "" ) # As per HIG, make the status bar empty when nothing is happening elif status == "no-network": statusbar.push(0, (datetime.today( ).strftime("%H:%M") + " - " + _( 'The network connection seems to be down, networked watches will not check until then.' ))) if self.tray: self.tray.show_tooltip() icon = self.get_icon(watch.icon, 50, False) elif status == "error": statusbar.push( 0, (datetime.today().strftime("%H:%M") + " - " + _('The watch "%s" has a problem.') % watch.name)) balloon_icon = self.get_icon("error", 0, True) icon = self.get_icon("error", 50, False) if self.specto.specto_gconf.get_entry("pop_toast") == True: body = watch.escape(watch.error_message) self.balloon.show_toast( body, balloon_icon, urgency="critical", summary=(_("%s encountered a problem") % watch.name)) if self.specto.specto_gconf.get_entry( "use_problem_sound") and self.sound: problem_sound = self.specto.specto_gconf.get_entry( "problem_sound") self.sound.play(problem_sound) elif status == "changed": if self.indicator: self.indicator.add_indicator(watch) statusbar.push(0, (datetime.today().strftime("%H:%M") + " - " + _('The watch "%s" has changed.') % watch.name)) self.model.set(self.iter[id], 2, "%s" % watch.name, 5, pango.WEIGHT_BOLD) self.builder.get_object("button_clear_all").set_sensitive(True) self.builder.get_object("clear_all1").set_sensitive(True) if self.model.iter_is_valid(self.iter[id]): icon = self.get_icon(watch.icon, 0, False) if self.tray: self.tray.show_tooltip() balloon_icon = self.get_icon(watch.icon, 0, True) if self.specto.specto_gconf.get_entry("pop_toast") == True: self.balloon.show_toast(watch.get_balloon_text(), balloon_icon, summary=(_("%s has changed") % watch.name), name=watch.name) icon = self.get_icon(watch.icon, 0, False) if self.specto.specto_gconf.get_entry( "use_changed_sound") and self.sound: changed_sound = self.specto.specto_gconf.get_entry( "changed_sound") self.sound.play(changed_sound) elif status == "read": if self.indicator: self.indicator.remove_indicator(id) self.model.set_value(self.iter[id], 1, icon) try: model, iter = self.treeview.get_selection().get_selected() id2 = int(model.get_value(iter, 3)) if id == id2: self.show_watch_info() except: pass except: self.specto.logger.log( _("There was an error marking the watch status"), "error", watch.name) def deactivate(self, id): """ Disable the checkbox from the watch. """ watch = self.specto.watch_db[id] self.model.set_value( self.iter[id], 0, 0 ) #TODO: make the text label in the "Name" column and the buttons insensitive def activate(self, id): """ enable the checkbox from the watch. """ watch = self.specto.watch_db[id] self.model.set_value( self.iter[id], 0, 1 ) #TODO: make the text label in the "Name" column and the buttons insensitive def get_icon(self, icon, percent, size): """ Calculate the alpha and return a transparent pixbuf. The input percentage is the 'transparency' percentage. 0 means no transparency. """ if icon == "": icon = "dialog-information" if size == True: size = 64 else: size = 22 try: icon = self.specto.icon_theme.load_icon(icon, size, 0) except gobject.GError: try: icon = gtk.gdk.pixbuf_new_from_file_at_size( os.path.join(self.specto.PATH, ("icons/" + icon + ".svg")), size, size) except: try: icon = gtk.gdk.pixbuf_new_from_file_at_size( os.path.join(self.specto.PATH, ("icons/" + icon + ".png")), size, size) except: return None icon = icon.add_alpha(False, '0', '0', '0') for row in icon.get_pixels_array(): for pix in row: pix[3] = min( int(pix[3]), 255 - (percent * 0.01 * 255) ) #note: we must *0.01, NOT /100, otherwise it won't work return icon def add_notifier_entry(self, id): """ Add an entry to the notifier list. """ watch = self.specto.watch_db[id] if watch.active == True: active = 1 else: active = 0 self.iter[id] = self.model.insert_before(None, None) self.model.set_value(self.iter[id], 0, active) if watch.changed == True: self.model.set_value(self.iter[id], 1, self.get_icon(watch.icon, 0, False)) self.model.set(self.iter[id], 5, pango.WEIGHT_BOLD) else: self.model.set_value(self.iter[id], 1, self.get_icon(watch.icon, 50, False)) self.model.set(self.iter[id], 5, pango.WEIGHT_NORMAL) self.model.set_value(self.iter[id], 2, watch.name) self.model.set_value(self.iter[id], 3, watch.id) self.model.set_value(self.iter[id], 4, watch.type) if not self.builder.get_object( "display_all_watches" ).active and active == 0: #dont creat the entry self.remove_notifier_entry(id) def remove_notifier_entry(self, id): path = self.model.get_path(self.iter[id]) iter = self.model.get_iter(path) id = int(self.model.get_value(iter, 3)) self.model.remove(iter) def check_clicked(self, object, path, model): """ Call the main function to start/stop the selected watch. """ sel = self.treeview.get_selection() sel.select_path(path) model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) watch = self.specto.watch_db[id] if model.get_value(iter, 0): model.set_value(iter, 0, 0) if watch.changed: self.mark_watch_as_read("", id) self.mark_watch_status("idle", id) watch.stop() if not self.builder.get_object("display_all_watches").active: self.remove_notifier_entry(id) else: model.set_value(iter, 0, 1) watch.start() def connected_message(self, connected): return if not connected: self.builder.get_object("statusbar1").push( 0, _("The network connection seems to be down, networked watches will not check until then." )) self.builder.get_object("statusbar1").show() else: self.builder.get_object("statusbar1").hide() def show_watch_info(self, *args): """ Show the watch information in the notifier window. """ model, iter = self.treeview.get_selection().get_selected() if iter != None and self.model.iter_is_valid(iter): self.builder.get_object("edit").set_sensitive(True) self.builder.get_object("remove").set_sensitive(True) if not self.info_table.flags() & gtk.VISIBLE: #hide the tip of the day and show the buttons self.quicktip.hide() self.quicktip_image.hide() self.builder.get_object("vbox_panel_buttons").show() self.builder.get_object("notebook1").show() self.info_table.show() id = int(model.get_value(iter, 3)) watch = self.specto.watch_db[id] watch_values = watch.get_gui_info() #set the error log field if not self.specto.DEBUG: self.builder.get_object("notebook1").remove_page(2) else: if self.builder.get_object("notebook1").get_n_pages() == 2: self.builder.get_object("notebook1").append_page( self.error_log_window, self.label_error_log) log_text = self.specto.logger.watch_log(watch.name) start = self.log_buffer.get_start_iter() end = self.log_buffer.get_end_iter() self.log_buffer.delete(start, end) iter = self.log_buffer.get_iter_at_offset(0) for line in log_text: self.log_buffer.insert_with_tags_by_name( iter, line[1], line[0]) if watch.changed == False: self.builder.get_object("clear").set_sensitive(False) self.builder.get_object("btnClear").set_sensitive(False) self.builder.get_object("lblExtraInfo").set_label( _("No extra information available.")) else: self.builder.get_object("clear").set_sensitive(True) self.builder.get_object("btnClear").set_sensitive(True) try: self.extra_info = watch.get_extra_information() if self.extra_info != "": try: self.builder.get_object("lblExtraInfo").set_label( self.extra_info) except: self.specto.logger.log( _("Extra information could not be set"), "error", self.specto.watch_db[id].name) except: self.specto.logger.log( _("Extra information could not be set"), "error", self.specto.watch_db[id].name) i = 0 while i < 4: if i >= len(watch_values): self.info_labels[i][0].set_label("") self.info_labels[i][1].set_label("") else: #create label self.info_labels[i][0].set_label("<b>" + str(watch_values[i][0]) + ":</b>") label = watch.escape(str(watch_values[i][1])) self.info_labels[i][1].set_label(label) i += 1 image = self.builder.get_object("watch_icon") image.set_from_pixbuf(self.get_icon(watch.icon, 0, True)) def open_watch(self, id): """ Open the selected watch. Returns False if the watch failed to open """ return self.specto.watch_db[id].open_watch() def open_watch_callback(self, *args): """ Opens the selected watch and mark it as unchanged """ model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) self.open_watch(id) if self.specto.watch_db[id].changed == True: self.mark_watch_as_read(None, id) def show_watch_popup(self, treeview, event, data=None): if event.button == 3: x = int(event.x) y = int(event.y) time = event.time pthinfo = treeview.get_path_at_pos(x, y) if pthinfo is not None: path, col, cellx, celly = pthinfo treeview.grab_focus() treeview.set_cursor(path, col, 0) menu = self.create_menu(self, self.notifier, None) menu.popup(None, None, None, 3, time) return 1 def _mark_watch_as_read(self, *widget): try: model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) self.mark_watch_as_read(id) except: pass def refresh_watch(self, widget): model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) watch = self.specto.watch_db[id] watch.restart() def edit_watch(self, widget): model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) self.show_edit_watch(self, widget, id) def create_menu(self, window, event, data=None): model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) watch = self.specto.watch_db[id] menu = gtk.Menu() menuItem = None menuItem = create_menu_item(_("Refresh"), self.refresh_watch, gtk.STOCK_REFRESH) if not watch.active: menuItem.set_sensitive(False) menu.append(menuItem) menuItem = create_menu_item(_("Mark as read"), self._mark_watch_as_read, gtk.STOCK_CLEAR) if not watch.changed: menuItem.set_sensitive(False) menu.append(menuItem) separator = gtk.SeparatorMenuItem() menu.append(separator) menuItem = create_menu_item(_("Edit"), self.edit_watch, gtk.STOCK_EDIT) menu.append(menuItem) menuItem = create_menu_item(_("Remove"), self.remove_watch, gtk.STOCK_REMOVE) menu.append(menuItem) menu.show_all() return menu def change_entry_name(self, *args): """ Edit the name from the watch in the notifier window. """ # Change the name in the treeview model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) self.change_name(args[2], id) def change_name(self, new_name, id): if self.specto.watch_db[id].changed == True: weight = pango.WEIGHT_BOLD else: weight = pango.WEIGHT_NORMAL self.model.set(self.iter[id], 2, new_name, 5, weight) # Write the new name in watches.list self.specto.watch_io.replace_name(self.specto.watch_db[id].name, new_name) # Change the name in the database self.specto.watch_db[id].name = new_name self.show_watch_info() ### GUI FUNCTIONS ### def get_quick_tip(self): """Return a random tip of the day to be shown on startup""" tips = [ _("You can add all kinds of websites as watches. Static pages, RSS or Atom feeds, etc. Specto will automatically handle them." ), _("Website watches can use an error margin that allows you to set a minimum difference percentage. This allows you to adapt to websites that change constantly or have lots of advertising." ), _("Single-click an existing watch to display information, and double-click it to open the content." ), _("Please set a reasonable refresh interval in order to save bandwidth and prevent you from being blocked from content providers." ) ] chosen_tip = tips[randrange(len(tips))] return chosen_tip def toggle_display_toolbar(self, *args): """ Show or hide the toolbar. """ if self.builder.get_object("display_toolbar").active: self.builder.get_object("toolbar").show() self.specto.specto_gconf.set_entry("hide_toolbar", False) else: self.builder.get_object("toolbar").hide() self.specto.specto_gconf.set_entry("hide_toolbar", True) def toggle_show_deactivated_watches(self, *widget): """ Display only active watches or all watches. """ if self.startup != True: self.startup = False # This is important to prevent *widget from messing with us. If you don't believe me, print startup ;) if self.startup == True: self.startup = False else: if self.builder.get_object("display_all_watches").active: for watch in self.specto.watch_db: if watch.active == False: # For each watch that is supposed to be inactive, show it in the notifier but don't activate it if self.startup == False: # Recreate the item because it was deleted self.add_notifier_entry(watch.id) self.specto.specto_gconf.set_entry("show_deactivated_watches", True) else: # Hide the deactivated watches for i in self.iter: if self.model.iter_is_valid(self.iter[i]): path = self.model.get_path(self.iter[i]) iter = self.model.get_iter(path) model = self.model id = int(model.get_value(iter, 3)) if self.specto.watch_db[id].active == False: model.remove(iter) self.specto.specto_gconf.set_entry("show_deactivated_watches", False) def remove_watch(self, *widget): try: model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) except: pass else: dialog = RemoveDialog(self.specto, _("Remove a watch"), (_( '<big>Remove the watch "%s"?</big>\nThis operation cannot be undone.' ) % self.specto.watch_db[id].name)) answer = dialog.show() if answer == True: self.remove_notifier_entry(id) self.specto.watch_db.remove(id) #remove the watch self.specto.watch_io.remove_watch( self.specto.watch_db[id].name) if self.tray: self.tray.show_tooltip() def delete_event(self, *args): """ quit specto """ self.save_size_and_position() self.specto.quit() return True def close_event(self, *args): """ if the trayicon and the indicator or not available then quit specto else hide the notifier window """ if self.specto.specto_gconf.get_entry( "always_show_icon") == True or self.indicator: self.notifier.hide() self.specto.specto_gconf.set_entry( "show_notifier", False) #save the window state for the next time specto starts return True else: self.specto.quit() return True def restore_size_and_position(self): """ Restore the size and the postition from the notifier window. """ saved_window_width = self.specto.specto_gconf.get_entry( "window_notifier_width") saved_window_height = self.specto.specto_gconf.get_entry( "window_notifier_height") saved_window_x = self.specto.specto_gconf.get_entry( "window_notifier_x") saved_window_y = self.specto.specto_gconf.get_entry( "window_notifier_y") if saved_window_width != None and saved_window_height != None: # Check if the size is not 0 self.builder.get_object("notifier").resize(saved_window_width, saved_window_height) if saved_window_x != None and saved_window_y != None: # Check if the position is not 0 self.builder.get_object("notifier").move(saved_window_x, saved_window_y) def save_size_and_position(self): """ Save the size and position from the notifier in gconf when the window is closed. """ # Save the size in gconf current_window_size = self.builder.get_object("notifier").get_size() current_window_width = current_window_size[0] current_window_height = current_window_size[1] self.specto.specto_gconf.set_entry("window_notifier_width", current_window_width) self.specto.specto_gconf.set_entry("window_notifier_height", current_window_height) # Save the window position in gconf when the window is closed current_window_xy = self.builder.get_object("notifier").get_position() current_window_x = current_window_xy[0] current_window_y = current_window_xy[1] self.specto.specto_gconf.set_entry("window_notifier_x", current_window_x) self.specto.specto_gconf.set_entry("window_notifier_y", current_window_y) def get_state(self): """ Return True if the notifier window is visible. """ return bool(self.notifier.flags() & gtk.VISIBLE) def create_notifier_gui(self): """ Create the gui from the notifier. """ self.treeview = self.builder.get_object("treeview") self.treeview.set_model(self.model) self.treeview.set_flags(gtk.TREE_MODEL_ITERS_PERSIST) self.treeview.connect("button_press_event", self.show_watch_popup, None) self.builder.get_object("button_clear_all").set_sensitive(False) self.builder.get_object("clear_all1").set_sensitive(False) if self.specto.specto_gconf.get_entry( "always_show_icon") == False and not self.indicator: self.builder.get_object("close").set_sensitive(False) ### Initiate the window self.restore_size_and_position() self.show_toolbar = self.specto.specto_gconf.get_entry("show_toolbar") if self.show_toolbar == False: self.builder.get_object("display_toolbar").set_active(False) self.toggle_display_toolbar() else: self.builder.get_object("display_toolbar").set_active(True) self.toggle_display_toolbar() self.startup = True if self.specto.specto_gconf.get_entry( "show_deactivated_watches") == True: self.builder.get_object("display_all_watches").set_active(True) else: self.builder.get_object("display_all_watches").set_active(False) self.startup = False if not self.specto.notifier_hide: self.notifier.show() ### Checkbox self.columnCheck_renderer = gtk.CellRendererToggle() self.columnCheck_renderer.set_property("activatable", True) self.columnCheck_renderer.connect("toggled", self.check_clicked, self.model) self.columnCheck = gtk.TreeViewColumn(_("Active"), self.columnCheck_renderer, active=0) self.columnCheck.connect("clicked", self.sort_active_from_treeview_headers) self.columnCheck.set_sort_column_id(0) self.treeview.append_column(self.columnCheck) ### Icon self.columnIcon_renderer = gtk.CellRendererPixbuf() self.columnIcon = gtk.TreeViewColumn(_("Type"), self.columnIcon_renderer, pixbuf=1) self.columnIcon.set_clickable(True) self.columnIcon.connect("clicked", self.sort_type_from_treeview_headers) self.treeview.append_column(self.columnIcon) ### Titre self.columnTitle_renderer = gtk.CellRendererText() #self.columnTitle_renderer.set_property("editable", True) #self.columnTitle_renderer.connect('edited', self.change_entry_name) self.columnTitle = gtk.TreeViewColumn(_("Name"), self.columnTitle_renderer, text=2, weight=5) self.columnTitle.connect("clicked", self.sort_name_from_treeview_headers) self.columnTitle.set_expand(True) self.columnTitle.set_resizable(True) self.columnTitle.set_sort_column_id(2) self.treeview.append_column(self.columnTitle) ### ID self.columnID_renderer = gtk.CellRendererText() self.columnID = gtk.TreeViewColumn(_("ID"), self.columnID_renderer, markup=3) self.columnID.set_visible(False) self.columnID.set_sort_column_id(3) self.treeview.append_column(self.columnID) ### type self.renderer = gtk.CellRendererText() self.columnType = gtk.TreeViewColumn(_("TYPE"), self.renderer, markup=4) self.columnType.set_visible(False) self.columnType.set_sort_column_id(4) self.treeview.append_column(self.columnType) self.get_startup_sort_order() ###Create info-panel vbox_info = self.builder.get_object("vbox_info") #show tip of the day self.quicktip = self.get_quick_tip() self.quicktip_image = gtk.Image() self.quicktip_image.set_from_pixbuf( self.get_icon("dialog-information", 0, True)) self.quicktip_image.show() vbox_info.pack_start(self.quicktip_image, False, False, 0) self.quicktip = gtk.Label( ("<big>" + _("Tip of the Day:") + "</big> " + self.quicktip)) self.quicktip.set_line_wrap(True) self.quicktip.set_use_markup(True) self.quicktip.set_alignment(xalign=0.0, yalign=0.5) self.quicktip.show() vbox_info.pack_start(self.quicktip, False, False, 0) #create the info table self.info_table = gtk.Table(rows=4, columns=2, homogeneous=True) self.info_table.set_row_spacings(6) self.info_table.set_col_spacings(6) vbox_watch_info = self.builder.get_object("vbox_watch_info") vbox_watch_info.pack_start(self.info_table, False, False, 0) #show the image i = 0 self.info_labels = [] while i < 4: gtk_label = gtk.Label() gtk_label.set_alignment(xalign=0.0, yalign=0.5) gtk_label.set_use_markup(True) gtk_label.set_ellipsize(pango.ELLIPSIZE_END) gtk_label.show() #create value gtk_label1 = gtk.Label() gtk_label1.set_alignment(xalign=0.0, yalign=0.5) gtk_label1.set_use_markup(True) gtk_label1.set_ellipsize(pango.ELLIPSIZE_END) gtk_label1.show() self.info_labels.extend([(gtk_label, gtk_label1)]) self.info_table.attach(self.info_labels[i][1], 1, 2, i, i + 1) self.info_table.attach(self.info_labels[i][0], 0, 1, i, i + 1) i += 1 #create the error log textview and notebook label self.error_log = gtk.TextView() self.log_buffer = self.error_log.get_buffer() self.log_buffer.create_tag("ERROR", foreground="#a40000") self.log_buffer.create_tag("INFO", foreground="#4e9a06") self.log_buffer.create_tag("WARNING", foreground="#c4a000") self.error_log_window = gtk.ScrolledWindow() self.error_log_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.error_log_window.add_with_viewport(self.error_log) self.error_log_window.show() self.label_error_log = gtk.Label(_("Error log")) self.error_log.show() self.label_error_log.show() #hide the buttons self.builder.get_object("vbox_panel_buttons").hide() self.builder.get_object("edit").set_sensitive(False) self.builder.get_object("clear").set_sensitive(False) self.builder.get_object("remove").set_sensitive(False) self.builder.get_object("statusbar1").show() self.builder.get_object("notebook1").hide() self.generate_add_menu() ### Sort functions ### def get_startup_sort_order(self): order = self.get_gconf_sort_order() sort_function = self.specto.specto_gconf.get_entry("sort_function") if sort_function == "name": self.builder.get_object("by_name").set_active(True) self.model.set_sort_column_id(2, order) elif sort_function == "type": self.builder.get_object("by_watch_type").set_active(True) self.model.set_sort_column_id(4, order) elif sort_function == "active": self.builder.get_object("by_watch_active").set_active(True) self.model.set_sort_column_id(0, order) def get_gconf_sort_order(self): """ Get the order (asc, desc) from a gconf key. """ order = self.specto.specto_gconf.get_entry("sort_order") if order == "asc": sort_order = gtk.SORT_ASCENDING else: sort_order = gtk.SORT_DESCENDING return sort_order def set_gconf_sort_order(self, order): """ Set the order (asc, desc) for a gconf keys. """ if order == gtk.SORT_ASCENDING: sort_order = "asc" else: sort_order = "desc" return sort_order def sort_name(self, *args): """ Sort by watch name. """ self.model.set_sort_column_id(2, not self.columnTitle.get_sort_order()) self.specto.specto_gconf.set_entry("sort_function", "name") def sort_type(self, *args): """ Sort by watch type. """ self.model.set_sort_column_id(4, not self.columnType.get_sort_order()) self.specto.specto_gconf.set_entry("sort_function", "type") self.specto.specto_gconf.set_entry( "sort_order", self.set_gconf_sort_order(self.columnType.get_sort_order())) def sort_active(self, *args): """ Sort by active watches. """ self.model.set_sort_column_id(0, not self.columnCheck.get_sort_order()) self.specto.specto_gconf.set_entry("sort_function", "active") def sort_name_from_treeview_headers(self, *widget): """When treeview headers are clicked, GTK already does the sorting. Just change the active sorting radio button to 'name' in the menus, save the sorting preference.""" self.builder.get_object("by_name").set_active(True) self.specto.specto_gconf.set_entry( "sort_order", self.set_gconf_sort_order(not self.columnTitle.get_sort_order())) def sort_type_from_treeview_headers(self, *widget): """When treeview headers are clicked, GTK already does the sorting. Just change the active sorting radio button to 'type' in the menus, save the sorting preference.""" self.builder.get_object("by_watch_type").set_active(True) self.sort_type() def sort_active_from_treeview_headers(self, *widget): """When treeview headers are clicked, GTK already does the sorting. Just change the active sorting radio button to 'active' in the menus, save the sorting preference.""" self.builder.get_object("by_watch_active").set_active(True) self.specto.specto_gconf.set_entry( "sort_order", self.set_gconf_sort_order(not self.columnCheck.get_sort_order())) def recreate_tray(self, *args): """ Recreate a tray icon if the notification area unexpectedly quits. """ try: self.tray.destroy() except: pass self.tray = "" self.tray = Tray(self.specto, self) self.specto.watch_db.count_changed_watches() def show_preferences(self, *args): """ Show the preferences window. """ if not self.preferences_initialized or self.preferences.get_state( ) == True: self.pref = Preferences(self.specto, self) else: self.pref.show() def generate_add_menu(self): """ Creates two "Add watch" submenus for the toplevel menu and the toolbar """ menu_dict = self.specto.watch_db.plugin_menu self.add_menu = gtk.Menu() self.add_menu_ = gtk.Menu() for parent in menu_dict.keys(): menuItem = gtk.MenuItem(parent) menuItem.show() menuItem_ = gtk.MenuItem(parent) menuItem_.show() self.add_menu.append(menuItem) self.add_menu_.append(menuItem_) childmenu = gtk.Menu() childmenu_ = gtk.Menu() for child in menu_dict[parent]: # Create an entry for the popup add menu childmenuItem = gtk.ImageMenuItem(child[0]) childmenu.append(childmenuItem) img = gtk.Image() image = self.get_icon(child[1], 0, False) img.set_from_pixbuf(image) childmenuItem.set_image(img) childmenuItem.connect( 'button-press-event', self.show_add_watch, child[2]) #FIXME: doesn't work with the keyboard childmenuItem.show() # Create an entry for the "edit -> add" submenu childmenuItem_ = gtk.ImageMenuItem(child[0]) childmenu_.append(childmenuItem_) img = gtk.Image() image = self.get_icon(child[1], 0, False) img.set_from_pixbuf(image) childmenuItem_.set_image(img) childmenuItem_.connect('button-press-event', self.show_add_watch, child[2]) childmenuItem_.show() menuItem.set_submenu(childmenu) menuItem_.set_submenu(childmenu_) self.builder.get_object("button_add").set_menu(self.add_menu) self.builder.get_object("add").set_submenu(self.add_menu_) def position_add_watch_menu_correctly(self, *args): """ This is a hack, so that the popup menu appears left-aligned, right below the Add button """ current_window_xy = self.builder.get_object( "notifier" ).window.get_origin( ) #here's the trick to not getting screwed by the window manager. get_origin from the window property returns the root x coordinates current_window_x = current_window_xy[0] current_window_y = current_window_xy[1] button_x = self.builder.get_object("button_add").get_allocation().x button_y = self.builder.get_object("button_add").get_allocation().y button_height = self.builder.get_object( "button_add").get_allocation().height coordinates = (current_window_x + button_x, current_window_y + button_y + button_height, False) return coordinates def show_add_watch_menu(self, *args): """ When the user clicks on the button part of the GTK Toolbar Menu Button, show the menu instead """ self.add_menu.popup(None, None, self.position_add_watch_menu_correctly, 3, 0) return 1 def show_add_watch(self, event, *args): """ Show the add watch window. """ watch_type = args[1] if self.add_w == "": self.add_w = Add_watch(self.specto, self, watch_type) elif self.add_w.add_watch.flags() & gtk.MAPPED: pass else: self.add_w = Add_watch(self.specto, self, watch_type) def show_edit_watch(self, widget, *args): """ Show the edit watch window. """ selected = "" try: model, iter = self.treeview.get_selection().get_selected() if model.iter_is_valid(iter): id = int(model.get_value(iter, 3)) except: for watch in self.specto.watch_db: try: if watch.name == args[0]: id = watch.id break except: return if self.edit_w == "": self.edit_w = Edit_watch(self.specto, self, id) elif self.edit_w.edit_watch.flags() & gtk.MAPPED: pass else: self.edit_w = Edit_watch(self.specto, self, id) def show_error_log(self, *widget): """ Call the main function to show the log window. """ if self.error_l == "": self.error_l = Log_dialog(self.specto, self) elif self.error_l.log_dialog.flags() & gtk.MAPPED: pass else: self.error_l = Log_dialog(self.specto, self) def show_help(self, *args): """ Call the main function to show the help. """ show_webpage("http://code.google.com/p/specto/w/list") def show_about(self, *args): """ Call the main function to show the about window. """ if self.about == "": self.about = About(self.specto) elif self.about.about.flags() & gtk.MAPPED: pass else: self.about = About(self.specto) def import_watches(self, *widget): if self.import_watch == "": self.import_watch = Import_watch(self.specto, self) elif self.import_watch.import_open_dialog.flags() & gtk.MAPPED: pass else: self.import_watch = Import_watch(self.specto, self) def export_watches(self, *widget): if self.export_watch == "": self.export_watch = Export_watch(self.specto, self) elif self.export_watch.export_watch.flags() & gtk.MAPPED: pass else: self.export_watch = Export_watch(self.specto, self)
def show_preferences(self, *args): """ Show the preferences window. """ if not self.preferences_initialized or self.preferences.get_state() == True: self.pref = Preferences(self.specto, self) else: self.pref.show()
class Notifier: """ Class to create the main specto window """ add_w = "" edit_w = "" error_l = "" about = "" export_watch = "" import_watch = "" def __init__(self, specto): """ In this init we are going to display the main notifier window. """ self.specto = specto uifile = os.path.join(self.specto.PATH, "uis/notifier.ui") windowname = "notifier" self.builder = gtk.Builder() self.builder.set_translation_domain("specto") self.builder.add_from_file(uifile) self.notifier = self.builder.get_object("notifier") if INDICATOR: self.indicator = Indicator(specto) self.tray = None else: self.tray = Tray(specto, self) self.indicator = None if SOUND: self.sound = Sound() else: self.sound = None self.balloon = NotificationToast(specto, self) self.preferences_initialized = False #create tree self.iter = {} self.model = gtk.ListStore(gobject.TYPE_BOOLEAN, gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING, pango.Weight) #catch some events dic = { "on_add_activate": self.show_add_watch_menu, "on_edit_activate": self.show_edit_watch, "on_clear_all_activate": self.mark_all_as_read, "on_preferences_activate": self.show_preferences, "on_refresh_activate": self.refresh_all_watches, "on_close_activate": self.close_event, "on_quit_activate": self.delete_event, "on_import_watches_activate": self.import_watches, "on_export_watches_activate": self.export_watches, "on_error_log_activate": self.show_error_log, "on_display_all_watches_activate": self.toggle_show_deactivated_watches, "on_display_toolbar_activate": self.toggle_display_toolbar, "on_help_activate": self.show_help, "on_about_activate": self.show_about, "on_treeview_row_activated": self.open_watch_callback, "on_btnOpen_clicked": self.open_watch_callback, "on_btnClear_clicked": self.mark_watch_as_read, "on_treeview_cursor_changed": self.show_watch_info, "on_btnEdit_clicked": self.show_edit_watch, "on_by_watch_type_activate": self.sort_type, "on_by_name_activate": self.sort_name, "on_by_watch_active_activate": self.sort_active, "on_remove_clicked": self.remove_watch, "on_clear_activate": self._mark_watch_as_read, "on_remove_activate": self.remove_watch} self.builder.connect_signals(dic) self.notifier.set_icon_from_file(self.specto.LOGO_PATH) self.specto.notifier_initialized = True self.create_notifier_gui() self.stop_refresh = False def mark_watch_as_read(self, widget, *id): """ Call the main function to mark the watch as read and reset the name in the notifier. If widget == '' then id will be used to mark the watch as read else the selected watch will be marked as read. """ try: id = id[0] except: model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) watch = self.specto.watch_db[id] watch.mark_as_read() self.model.set(self.iter[id], 2, watch.name, 5, pango.WEIGHT_NORMAL) if self.model.iter_is_valid(self.iter[id]) and not watch.error: self.model.set_value(self.iter[id], 1, self.get_icon(watch.icon, 50, False)) if watch.changed == False: self.builder.get_object("btnClear").set_sensitive(False) else: self.builder.get_object("btnClear").set_sensitive(True) #check if all watches has been marked as read changed_watches = False changes = self.specto.watch_db.count_changed_watches() for changed in changes.values(): if changed > 0: changed_watches = True if changed_watches == False: self.builder.get_object("button_clear_all").set_sensitive(False) def mark_all_as_read(self, widget): """ Call the main function to mark all watches as read and reset the name in the notifier. """ self.builder.get_object("btnClear").set_sensitive(False) self.builder.get_object("button_clear_all").set_sensitive(False) self.builder.get_object("clear_all1").set_sensitive(False) for watch in self.specto.watch_db: if self.model.iter_is_valid(self.iter[watch.id]): self.mark_watch_as_read("", watch.id) def refresh_all_watches(self, *widget): """ Call the main funcion to refresh all active watches and change refresh icon to stop. """ if self.builder.get_object("button_refresh").get_stock_id() == "gtk-refresh": self.builder.get_object("button_refresh").set_stock_id("gtk-stop") #menu item, does not allow changing label self.builder.get_object("button_refresh").set_label(_("Stop")) self.builder.get_object("button_add").set_sensitive(False) self.builder.get_object("btnEdit").set_sensitive(False) for i in self.iter: if self.stop_refresh == True: self.stop_refresh = False break try: iter = self.model.get_iter(i) if self.model.iter_is_valid(iter): model = self.model id = int(model.get_value(iter, 3)) except: break if self.specto.watch_db[id].active == True: try: self.specto.watch_db[id].stop() except: pass self.specto.watch_db[id].start() self.builder.get_object("button_refresh").set_stock_id("gtk-refresh") #menu item, does not allow changing label self.builder.get_object("button_refresh").set_label(_("Refresh All")) self.builder.get_object("button_add").set_sensitive(True) self.builder.get_object("btnEdit").set_sensitive(True) else: self.stop_refresh = True def mark_error(self, error_message): error_dialog = ErrorDialog(self.specto, error_message) def mark_watch_status(self, status, id): """ show the right icon for the status from the watch. """ watch = self.specto.watch_db[id] statusbar = self.builder.get_object("statusbar1") icon = self.get_icon("error", 50, False) try: if status == "checking": icon = self.get_icon("reload", 0, False) statusbar.push(0, (datetime.today().strftime("%H:%M") + " - " + _('The watch "%s" is checking.') % watch.name)) elif status == "idle": if self.tray: self.tray.show_tooltip() #check if all watches are cleared if watch.changed == True: self.model.set(self.iter[id], 2, "%s" % watch.name, 5, pango.WEIGHT_BOLD) self.builder.get_object("button_clear_all").set_sensitive(True) self.builder.get_object("clear_all1").set_sensitive(True) icon = self.get_icon(watch.icon, 0, False) else: self.model.set(self.iter[id], 2, "%s" % watch.name, 5, pango.WEIGHT_NORMAL) self.builder.get_object("clear_all1").set_sensitive(False) icon = self.get_icon(watch.icon, 50, False) statusbar.push(0, "") # As per HIG, make the status bar empty when nothing is happening elif status == "no-network": statusbar.push(0, (datetime.today().strftime("%H:%M") + " - " + _('The network connection seems to be down, networked watches will not check until then.'))) if self.tray: self.tray.show_tooltip() icon = self.get_icon(watch.icon, 50, False) elif status == "error": statusbar.push(0, (datetime.today().strftime("%H:%M") + " - " + _('The watch "%s" has a problem.') % watch.name)) balloon_icon = self.get_icon("error", 0, True) icon = self.get_icon("error", 50, False) if self.specto.specto_gconf.get_entry("pop_toast") == True: body = watch.escape(watch.error_message) self.balloon.show_toast(body, balloon_icon, urgency="critical", summary=(_("%s encountered a problem") % watch.name)) if self.specto.specto_gconf.get_entry("use_problem_sound") and self.sound: problem_sound = self.specto.specto_gconf.get_entry("problem_sound") self.sound.play(problem_sound) elif status == "changed": if self.indicator: self.indicator.add_indicator(watch) statusbar.push(0, (datetime.today().strftime("%H:%M") + " - " + _('The watch "%s" has changed.') % watch.name)) self.model.set(self.iter[id], 2, "%s" % watch.name, 5, pango.WEIGHT_BOLD) self.builder.get_object("button_clear_all").set_sensitive(True) self.builder.get_object("clear_all1").set_sensitive(True) if self.model.iter_is_valid(self.iter[id]): icon = self.get_icon(watch.icon, 0, False) if self.tray: self.tray.show_tooltip() balloon_icon = self.get_icon(watch.icon, 0, True) if self.specto.specto_gconf.get_entry("pop_toast") == True: self.balloon.show_toast(watch.get_balloon_text(), balloon_icon, summary=(_("%s has changed") % watch.name), name=watch.name) icon = self.get_icon(watch.icon, 0, False) if self.specto.specto_gconf.get_entry("use_changed_sound") and self.sound: changed_sound = self.specto.specto_gconf.get_entry("changed_sound") self.sound.play(changed_sound) elif status == "read": if self.indicator: self.indicator.remove_indicator(id) self.model.set_value(self.iter[id], 1, icon) try: model, iter = self.treeview.get_selection().get_selected() id2 = int(model.get_value(iter, 3)) if id == id2: self.show_watch_info() except: pass except: self.specto.logger.log(_("There was an error marking the watch status"), "error", watch.name) def deactivate(self, id): """ Disable the checkbox from the watch. """ watch = self.specto.watch_db[id] self.model.set_value(self.iter[id], 0, 0)#TODO: make the text label in the "Name" column and the buttons insensitive def activate(self, id): """ enable the checkbox from the watch. """ watch = self.specto.watch_db[id] self.model.set_value(self.iter[id], 0, 1)#TODO: make the text label in the "Name" column and the buttons insensitive def get_icon(self, icon, percent, size): """ Calculate the alpha and return a transparent pixbuf. The input percentage is the 'transparency' percentage. 0 means no transparency. """ if icon == "": icon = "dialog-information" if size == True: size = 64 else: size = 22 try: icon = self.specto.icon_theme.load_icon(icon, size, 0) except gobject.GError: try: icon = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(self.specto.PATH, ("icons/" + icon + ".svg")), size, size) except: try: icon = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(self.specto.PATH, ("icons/" + icon + ".png")), size, size) except: return None icon = icon.add_alpha(False, '0', '0', '0') for row in icon.get_pixels_array(): for pix in row: pix[3] = min(int(pix[3]), 255 - (percent * 0.01 * 255))#note: we must *0.01, NOT /100, otherwise it won't work return icon def add_notifier_entry(self, id): """ Add an entry to the notifier list. """ watch = self.specto.watch_db[id] if watch.active == True: active = 1 else: active = 0 self.iter[id] = self.model.insert_before(None, None) self.model.set_value(self.iter[id], 0, active) if watch.changed == True: self.model.set_value(self.iter[id], 1, self.get_icon(watch.icon, 0, False)) self.model.set(self.iter[id], 5, pango.WEIGHT_BOLD) else: self.model.set_value(self.iter[id], 1, self.get_icon(watch.icon, 50, False)) self.model.set(self.iter[id], 5, pango.WEIGHT_NORMAL) self.model.set_value(self.iter[id], 2, watch.name) self.model.set_value(self.iter[id], 3, watch.id) self.model.set_value(self.iter[id], 4, watch.type) if not self.builder.get_object("display_all_watches").active and active == 0: #dont creat the entry self.remove_notifier_entry(id) def remove_notifier_entry(self, id): path = self.model.get_path(self.iter[id]) iter = self.model.get_iter(path) id = int(self.model.get_value(iter, 3)) self.model.remove(iter) def check_clicked(self, object, path, model): """ Call the main function to start/stop the selected watch. """ sel = self.treeview.get_selection() sel.select_path(path) model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) watch = self.specto.watch_db[id] if model.get_value(iter, 0): model.set_value(iter, 0, 0) if watch.changed: self.mark_watch_as_read("", id) self.mark_watch_status("idle", id) watch.stop() if not self.builder.get_object("display_all_watches").active: self.remove_notifier_entry(id) else: model.set_value(iter, 0, 1) watch.start() def connected_message(self, connected): return if not connected: self.builder.get_object("statusbar1").push(0, _("The network connection seems to be down, networked watches will not check until then.")) self.builder.get_object("statusbar1").show() else: self.builder.get_object("statusbar1").hide() def show_watch_info(self, *args): """ Show the watch information in the notifier window. """ model, iter = self.treeview.get_selection().get_selected() if iter != None and self.model.iter_is_valid(iter): self.builder.get_object("edit").set_sensitive(True) self.builder.get_object("remove").set_sensitive(True) if not self.info_table.flags() & gtk.VISIBLE: #hide the tip of the day and show the buttons self.quicktip.hide() self.quicktip_image.hide() self.builder.get_object("vbox_panel_buttons").show() self.builder.get_object("notebook1").show() self.info_table.show() id = int(model.get_value(iter, 3)) watch = self.specto.watch_db[id] watch_values = watch.get_gui_info() #set the error log field if not self.specto.DEBUG: self.builder.get_object("notebook1").remove_page(2) else: if self.builder.get_object("notebook1").get_n_pages() == 2: self.builder.get_object("notebook1").append_page(self.error_log_window, self.label_error_log) log_text = self.specto.logger.watch_log(watch.name) start = self.log_buffer.get_start_iter() end = self.log_buffer.get_end_iter() self.log_buffer.delete(start, end) iter = self.log_buffer.get_iter_at_offset(0) for line in log_text: self.log_buffer.insert_with_tags_by_name(iter, line[1], line[0]) if watch.changed == False: self.builder.get_object("clear").set_sensitive(False) self.builder.get_object("btnClear").set_sensitive(False) self.builder.get_object("lblExtraInfo").set_label(_("No extra information available.")) else: self.builder.get_object("clear").set_sensitive(True) self.builder.get_object("btnClear").set_sensitive(True) try: self.extra_info = watch.get_extra_information() if self.extra_info != "": try: self.builder.get_object("lblExtraInfo").set_label(self.extra_info) except: self.specto.logger.log(_("Extra information could not be set"), "error", self.specto.watch_db[id].name) except: self.specto.logger.log(_("Extra information could not be set"), "error", self.specto.watch_db[id].name) i = 0 while i < 4: if i >= len(watch_values): self.info_labels[i][0].set_label("") self.info_labels[i][1].set_label("") else: #create label self.info_labels[i][0].set_label("<b>" + str(watch_values[i][0]) + ":</b>") label = watch.escape(str(watch_values[i][1])) self.info_labels[i][1].set_label(label) i += 1 image = self.builder.get_object("watch_icon") image.set_from_pixbuf(self.get_icon(watch.icon, 0, True)) def open_watch(self, id): """ Open the selected watch. Returns False if the watch failed to open """ return self.specto.watch_db[id].open_watch() def open_watch_callback(self, *args): """ Opens the selected watch and mark it as unchanged """ model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) self.open_watch(id) if self.specto.watch_db[id].changed == True: self.mark_watch_as_read(None, id) def show_watch_popup(self, treeview, event, data=None): if event.button == 3: x = int(event.x) y = int(event.y) time = event.time pthinfo = treeview.get_path_at_pos(x, y) if pthinfo is not None: path, col, cellx, celly = pthinfo treeview.grab_focus() treeview.set_cursor(path, col, 0) menu = self.create_menu(self, self.notifier, None) menu.popup(None, None, None, 3, time) return 1 def _mark_watch_as_read(self, *widget): try: model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) self.mark_watch_as_read(id) except: pass def refresh_watch(self, widget): model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) watch = self.specto.watch_db[id] watch.restart() def edit_watch(self, widget): model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) self.show_edit_watch(self, widget, id) def create_menu(self, window, event, data=None): model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) watch = self.specto.watch_db[id] menu = gtk.Menu() menuItem = None menuItem = create_menu_item(_("Refresh"), self.refresh_watch, gtk.STOCK_REFRESH) if not watch.active: menuItem.set_sensitive(False) menu.append(menuItem) menuItem = create_menu_item(_("Mark as read"), self._mark_watch_as_read, gtk.STOCK_CLEAR) if not watch.changed: menuItem.set_sensitive(False) menu.append(menuItem) separator = gtk.SeparatorMenuItem() menu.append(separator) menuItem = create_menu_item(_("Edit"), self.edit_watch, gtk.STOCK_EDIT) menu.append(menuItem) menuItem = create_menu_item(_("Remove"), self.remove_watch, gtk.STOCK_REMOVE) menu.append(menuItem) menu.show_all() return menu def change_entry_name(self, *args): """ Edit the name from the watch in the notifier window. """ # Change the name in the treeview model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) self.change_name(args[2], id) def change_name(self, new_name, id): if self.specto.watch_db[id].changed == True: weight = pango.WEIGHT_BOLD else: weight = pango.WEIGHT_NORMAL self.model.set(self.iter[id], 2, new_name, 5, weight) # Write the new name in watches.list self.specto.watch_io.replace_name(self.specto.watch_db[id].name, new_name) # Change the name in the database self.specto.watch_db[id].name = new_name self.show_watch_info() ### GUI FUNCTIONS ### def get_quick_tip(self): """Return a random tip of the day to be shown on startup""" tips = [_("You can add all kinds of websites as watches. Static pages, RSS or Atom feeds, etc. Specto will automatically handle them."), _("Website watches can use an error margin that allows you to set a minimum difference percentage. This allows you to adapt to websites that change constantly or have lots of advertising."), _("Single-click an existing watch to display information, and double-click it to open the content."), _("Please set a reasonable refresh interval in order to save bandwidth and prevent you from being blocked from content providers.")] chosen_tip = tips[randrange(len(tips))] return chosen_tip def toggle_display_toolbar(self, *args): """ Show or hide the toolbar. """ if self.builder.get_object("display_toolbar").active: self.builder.get_object("toolbar").show() self.specto.specto_gconf.set_entry("hide_toolbar", False) else: self.builder.get_object("toolbar").hide() self.specto.specto_gconf.set_entry("hide_toolbar", True) def toggle_show_deactivated_watches(self, *widget): """ Display only active watches or all watches. """ if self.startup != True: self.startup = False # This is important to prevent *widget from messing with us. If you don't believe me, print startup ;) if self.startup == True: self.startup = False else: if self.builder.get_object("display_all_watches").active: for watch in self.specto.watch_db: if watch.active == False: # For each watch that is supposed to be inactive, show it in the notifier but don't activate it if self.startup == False: # Recreate the item because it was deleted self.add_notifier_entry(watch.id) self.specto.specto_gconf.set_entry("show_deactivated_watches", True) else: # Hide the deactivated watches for i in self.iter: if self.model.iter_is_valid(self.iter[i]): path = self.model.get_path(self.iter[i]) iter = self.model.get_iter(path) model = self.model id = int(model.get_value(iter, 3)) if self.specto.watch_db[id].active == False: model.remove(iter) self.specto.specto_gconf.set_entry("show_deactivated_watches", False) def remove_watch(self, *widget): try: model, iter = self.treeview.get_selection().get_selected() id = int(model.get_value(iter, 3)) except: pass else: dialog = RemoveDialog(self.specto, _("Remove a watch"), (_('<big>Remove the watch "%s"?</big>\nThis operation cannot be undone.') % self.specto.watch_db[id].name)) answer = dialog.show() if answer == True: self.remove_notifier_entry(id) self.specto.watch_db.remove(id) #remove the watch self.specto.watch_io.remove_watch(self.specto.watch_db[id].name) if self.tray: self.tray.show_tooltip() def delete_event(self, *args): """ quit specto """ self.save_size_and_position() self.specto.quit() return True def close_event(self, *args): """ if the trayicon and the indicator or not available then quit specto else hide the notifier window """ if self.specto.specto_gconf.get_entry("always_show_icon") == True or self.indicator: self.notifier.hide() self.specto.specto_gconf.set_entry("show_notifier", False)#save the window state for the next time specto starts return True else: self.specto.quit() return True def restore_size_and_position(self): """ Restore the size and the postition from the notifier window. """ saved_window_width = self.specto.specto_gconf.get_entry("window_notifier_width") saved_window_height = self.specto.specto_gconf.get_entry("window_notifier_height") saved_window_x = self.specto.specto_gconf.get_entry("window_notifier_x") saved_window_y = self.specto.specto_gconf.get_entry("window_notifier_y") if saved_window_width != None and saved_window_height != None: # Check if the size is not 0 self.builder.get_object("notifier").resize(saved_window_width, saved_window_height) if saved_window_x != None and saved_window_y != None: # Check if the position is not 0 self.builder.get_object("notifier").move(saved_window_x, saved_window_y) def save_size_and_position(self): """ Save the size and position from the notifier in gconf when the window is closed. """ # Save the size in gconf current_window_size = self.builder.get_object("notifier").get_size() current_window_width = current_window_size[0] current_window_height = current_window_size[1] self.specto.specto_gconf.set_entry("window_notifier_width", current_window_width) self.specto.specto_gconf.set_entry("window_notifier_height", current_window_height) # Save the window position in gconf when the window is closed current_window_xy = self.builder.get_object("notifier").get_position() current_window_x = current_window_xy[0] current_window_y = current_window_xy[1] self.specto.specto_gconf.set_entry("window_notifier_x", current_window_x) self.specto.specto_gconf.set_entry("window_notifier_y", current_window_y) def get_state(self): """ Return True if the notifier window is visible. """ return bool(self.notifier.flags() & gtk.VISIBLE) def create_notifier_gui(self): """ Create the gui from the notifier. """ self.treeview = self.builder.get_object("treeview") self.treeview.set_model(self.model) self.treeview.set_flags(gtk.TREE_MODEL_ITERS_PERSIST) self.treeview.connect("button_press_event", self.show_watch_popup, None) self.builder.get_object("button_clear_all").set_sensitive(False) self.builder.get_object("clear_all1").set_sensitive(False) if self.specto.specto_gconf.get_entry("always_show_icon") == False and not self.indicator: self.builder.get_object("close").set_sensitive(False) ### Initiate the window self.restore_size_and_position() self.show_toolbar = self.specto.specto_gconf.get_entry("show_toolbar") if self.show_toolbar == False: self.builder.get_object("display_toolbar").set_active(False) self.toggle_display_toolbar() else: self.builder.get_object("display_toolbar").set_active(True) self.toggle_display_toolbar() self.startup = True if self.specto.specto_gconf.get_entry("show_deactivated_watches") == True: self.builder.get_object("display_all_watches").set_active(True) else: self.builder.get_object("display_all_watches").set_active(False) self.startup = False if not self.specto.notifier_hide: self.notifier.show() ### Checkbox self.columnCheck_renderer = gtk.CellRendererToggle() self.columnCheck_renderer.set_property("activatable", True) self.columnCheck_renderer.connect("toggled", self.check_clicked, self.model) self.columnCheck = gtk.TreeViewColumn(_("Active"), self.columnCheck_renderer, active=0) self.columnCheck.connect("clicked", self.sort_active_from_treeview_headers) self.columnCheck.set_sort_column_id(0) self.treeview.append_column(self.columnCheck) ### Icon self.columnIcon_renderer = gtk.CellRendererPixbuf() self.columnIcon = gtk.TreeViewColumn(_("Type"), self.columnIcon_renderer, pixbuf=1) self.columnIcon.set_clickable(True) self.columnIcon.connect("clicked", self.sort_type_from_treeview_headers) self.treeview.append_column(self.columnIcon) ### Titre self.columnTitle_renderer = gtk.CellRendererText() #self.columnTitle_renderer.set_property("editable", True) #self.columnTitle_renderer.connect('edited', self.change_entry_name) self.columnTitle = gtk.TreeViewColumn(_("Name"), self.columnTitle_renderer, text=2, weight=5) self.columnTitle.connect("clicked", self.sort_name_from_treeview_headers) self.columnTitle.set_expand(True) self.columnTitle.set_resizable(True) self.columnTitle.set_sort_column_id(2) self.treeview.append_column(self.columnTitle) ### ID self.columnID_renderer = gtk.CellRendererText() self.columnID = gtk.TreeViewColumn(_("ID"), self.columnID_renderer, markup=3) self.columnID.set_visible(False) self.columnID.set_sort_column_id(3) self.treeview.append_column(self.columnID) ### type self.renderer = gtk.CellRendererText() self.columnType = gtk.TreeViewColumn(_("TYPE"), self.renderer, markup=4) self.columnType.set_visible(False) self.columnType.set_sort_column_id(4) self.treeview.append_column(self.columnType) self.get_startup_sort_order() ###Create info-panel vbox_info = self.builder.get_object("vbox_info") #show tip of the day self.quicktip = self.get_quick_tip() self.quicktip_image = gtk.Image() self.quicktip_image.set_from_pixbuf(self.get_icon("dialog-information", 0, True)) self.quicktip_image.show() vbox_info.pack_start(self.quicktip_image, False, False, 0) self.quicktip = gtk.Label(("<big>" + _("Tip of the Day:") + "</big> "+ self.quicktip)) self.quicktip.set_line_wrap(True) self.quicktip.set_use_markup(True) self.quicktip.set_alignment(xalign=0.0, yalign=0.5) self.quicktip.show() vbox_info.pack_start(self.quicktip, False, False, 0) #create the info table self.info_table = gtk.Table(rows=4, columns=2, homogeneous=True) self.info_table.set_row_spacings(6) self.info_table.set_col_spacings(6) vbox_watch_info = self.builder.get_object("vbox_watch_info") vbox_watch_info.pack_start(self.info_table, False, False, 0) #show the image i = 0 self.info_labels = [] while i < 4: gtk_label = gtk.Label() gtk_label.set_alignment(xalign=0.0, yalign=0.5) gtk_label.set_use_markup(True) gtk_label.set_ellipsize(pango.ELLIPSIZE_END) gtk_label.show() #create value gtk_label1 = gtk.Label() gtk_label1.set_alignment(xalign=0.0, yalign=0.5) gtk_label1.set_use_markup(True) gtk_label1.set_ellipsize(pango.ELLIPSIZE_END) gtk_label1.show() self.info_labels.extend([(gtk_label, gtk_label1)]) self.info_table.attach(self.info_labels[i][1], 1, 2, i, i + 1) self.info_table.attach(self.info_labels[i][0], 0, 1, i, i + 1) i += 1 #create the error log textview and notebook label self.error_log = gtk.TextView() self.log_buffer = self.error_log.get_buffer() self.log_buffer.create_tag("ERROR", foreground="#a40000") self.log_buffer.create_tag("INFO", foreground="#4e9a06") self.log_buffer.create_tag("WARNING", foreground="#c4a000") self.error_log_window = gtk.ScrolledWindow() self.error_log_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.error_log_window.add_with_viewport(self.error_log) self.error_log_window.show() self.label_error_log = gtk.Label(_("Error log")) self.error_log.show() self.label_error_log.show() #hide the buttons self.builder.get_object("vbox_panel_buttons").hide() self.builder.get_object("edit").set_sensitive(False) self.builder.get_object("clear").set_sensitive(False) self.builder.get_object("remove").set_sensitive(False) self.builder.get_object("statusbar1").show() self.builder.get_object("notebook1").hide() self.generate_add_menu() ### Sort functions ### def get_startup_sort_order(self): order = self.get_gconf_sort_order() sort_function = self.specto.specto_gconf.get_entry("sort_function") if sort_function == "name": self.builder.get_object("by_name").set_active(True) self.model.set_sort_column_id(2, order) elif sort_function == "type": self.builder.get_object("by_watch_type").set_active(True) self.model.set_sort_column_id(4, order) elif sort_function == "active": self.builder.get_object("by_watch_active").set_active(True) self.model.set_sort_column_id(0, order) def get_gconf_sort_order(self): """ Get the order (asc, desc) from a gconf key. """ order = self.specto.specto_gconf.get_entry("sort_order") if order == "asc": sort_order = gtk.SORT_ASCENDING else: sort_order = gtk.SORT_DESCENDING return sort_order def set_gconf_sort_order(self, order): """ Set the order (asc, desc) for a gconf keys. """ if order == gtk.SORT_ASCENDING: sort_order = "asc" else: sort_order = "desc" return sort_order def sort_name(self, *args): """ Sort by watch name. """ self.model.set_sort_column_id(2, not self.columnTitle.get_sort_order()) self.specto.specto_gconf.set_entry("sort_function", "name") def sort_type(self, *args): """ Sort by watch type. """ self.model.set_sort_column_id(4, not self.columnType.get_sort_order()) self.specto.specto_gconf.set_entry("sort_function", "type") self.specto.specto_gconf.set_entry("sort_order", self.set_gconf_sort_order(self.columnType.get_sort_order())) def sort_active(self, *args): """ Sort by active watches. """ self.model.set_sort_column_id(0, not self.columnCheck.get_sort_order()) self.specto.specto_gconf.set_entry("sort_function", "active") def sort_name_from_treeview_headers(self, *widget): """When treeview headers are clicked, GTK already does the sorting. Just change the active sorting radio button to 'name' in the menus, save the sorting preference.""" self.builder.get_object("by_name").set_active(True) self.specto.specto_gconf.set_entry("sort_order", self.set_gconf_sort_order(not self.columnTitle.get_sort_order())) def sort_type_from_treeview_headers(self, *widget): """When treeview headers are clicked, GTK already does the sorting. Just change the active sorting radio button to 'type' in the menus, save the sorting preference.""" self.builder.get_object("by_watch_type").set_active(True) self.sort_type() def sort_active_from_treeview_headers(self, *widget): """When treeview headers are clicked, GTK already does the sorting. Just change the active sorting radio button to 'active' in the menus, save the sorting preference.""" self.builder.get_object("by_watch_active").set_active(True) self.specto.specto_gconf.set_entry("sort_order", self.set_gconf_sort_order(not self.columnCheck.get_sort_order())) def recreate_tray(self, *args): """ Recreate a tray icon if the notification area unexpectedly quits. """ try: self.tray.destroy() except: pass self.tray = "" self.tray = Tray(self.specto, self) self.specto.watch_db.count_changed_watches() def show_preferences(self, *args): """ Show the preferences window. """ if not self.preferences_initialized or self.preferences.get_state() == True: self.pref = Preferences(self.specto, self) else: self.pref.show() def generate_add_menu(self): """ Creates two "Add watch" submenus for the toplevel menu and the toolbar """ menu_dict = self.specto.watch_db.plugin_menu self.add_menu = gtk.Menu() self.add_menu_ = gtk.Menu() for parent in menu_dict.keys(): menuItem = gtk.MenuItem(parent) menuItem.show() menuItem_ = gtk.MenuItem(parent) menuItem_.show() self.add_menu.append(menuItem) self.add_menu_.append(menuItem_) childmenu = gtk.Menu() childmenu_ = gtk.Menu() for child in menu_dict[parent]: # Create an entry for the popup add menu childmenuItem = gtk.ImageMenuItem(child[0]) childmenu.append(childmenuItem) img = gtk.Image() image = self.get_icon(child[1], 0, False) img.set_from_pixbuf(image) childmenuItem.set_image(img) childmenuItem.connect('button-press-event', self.show_add_watch, child[2]) #FIXME: doesn't work with the keyboard childmenuItem.show() # Create an entry for the "edit -> add" submenu childmenuItem_ = gtk.ImageMenuItem(child[0]) childmenu_.append(childmenuItem_) img = gtk.Image() image = self.get_icon(child[1], 0, False) img.set_from_pixbuf(image) childmenuItem_.set_image(img) childmenuItem_.connect('button-press-event', self.show_add_watch, child[2]) childmenuItem_.show() menuItem.set_submenu(childmenu) menuItem_.set_submenu(childmenu_) self.builder.get_object("button_add").set_menu(self.add_menu) self.builder.get_object("add").set_submenu(self.add_menu_) def position_add_watch_menu_correctly(self, *args): """ This is a hack, so that the popup menu appears left-aligned, right below the Add button """ current_window_xy = self.builder.get_object("notifier").window.get_origin()#here's the trick to not getting screwed by the window manager. get_origin from the window property returns the root x coordinates current_window_x = current_window_xy[0] current_window_y = current_window_xy[1] button_x = self.builder.get_object("button_add").get_allocation().x button_y = self.builder.get_object("button_add").get_allocation().y button_height = self.builder.get_object("button_add").get_allocation().height coordinates = (current_window_x+button_x, current_window_y+button_y+button_height, False) return coordinates def show_add_watch_menu(self, *args): """ When the user clicks on the button part of the GTK Toolbar Menu Button, show the menu instead """ self.add_menu.popup(None, None, self.position_add_watch_menu_correctly, 3, 0) return 1 def show_add_watch(self, event, *args): """ Show the add watch window. """ watch_type = args[1] if self.add_w == "": self.add_w = Add_watch(self.specto, self, watch_type) elif self.add_w.add_watch.flags() & gtk.MAPPED: pass else: self.add_w = Add_watch(self.specto, self, watch_type) def show_edit_watch(self, widget, *args): """ Show the edit watch window. """ selected = "" try: model, iter = self.treeview.get_selection().get_selected() if model.iter_is_valid(iter): id = int(model.get_value(iter, 3)) except: for watch in self.specto.watch_db: try: if watch.name == args[0]: id = watch.id break except: return if self.edit_w == "": self.edit_w = Edit_watch(self.specto, self, id) elif self.edit_w.edit_watch.flags() & gtk.MAPPED: pass else: self.edit_w = Edit_watch(self.specto, self, id) def show_error_log(self, *widget): """ Call the main function to show the log window. """ if self.error_l == "": self.error_l = Log_dialog(self.specto, self) elif self.error_l.log_dialog.flags() & gtk.MAPPED: pass else: self.error_l = Log_dialog(self.specto, self) def show_help(self, *args): """ Call the main function to show the help. """ show_webpage("http://code.google.com/p/specto/w/list") def show_about(self, *args): """ Call the main function to show the about window. """ if self.about == "": self.about = About(self.specto) elif self.about.about.flags() & gtk.MAPPED: pass else: self.about = About(self.specto) def import_watches(self, *widget): if self.import_watch == "": self.import_watch = Import_watch(self.specto, self) elif self.import_watch.import_open_dialog.flags() & gtk.MAPPED: pass else: self.import_watch = Import_watch(self.specto, self) def export_watches(self, *widget): if self.export_watch == "": self.export_watch = Export_watch(self.specto, self) elif self.export_watch.export_watch.flags() & gtk.MAPPED: pass else: self.export_watch = Export_watch(self.specto, self)