Beispiel #1
0
 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()
Beispiel #2
0
 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()
Beispiel #3
0
 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()
Beispiel #4
0
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()
Beispiel #5
0
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()
Beispiel #6
0
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)
Beispiel #7
0
 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()
Beispiel #8
0
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)