From dc4e13796dc1242b8bef1f9f9b98e302f3209151 Mon Sep 17 00:00:00 2001 From: Julio Biason Date: Fri, 16 Apr 2010 18:19:20 -0300 Subject: [PATCH] trying to make a smarter statusbar --- mitterlib/ui/helpers/gtk_smartbar.py | 92 ++++++++++++++++++++++++++++ mitterlib/ui/ui_pygtk.py | 26 +++----- 2 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 mitterlib/ui/helpers/gtk_smartbar.py diff --git a/mitterlib/ui/helpers/gtk_smartbar.py b/mitterlib/ui/helpers/gtk_smartbar.py new file mode 100644 index 0000000..102b0d8 --- /dev/null +++ b/mitterlib/ui/helpers/gtk_smartbar.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Mitter, a micro-blogging client with multiple interfaces. +# Copyright (C) 2007-2010 Mitter Contributors +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gobject +import gtk + +import logging + +# ---------------------------------------------------------------------- +# Constants +# ---------------------------------------------------------------------- + +_log = logging.getLogger('ui.pygtk') + +# ---------------------------------------------------------------------- +# Smart statusbar message queueing object +# ---------------------------------------------------------------------- +class SmartStatusbar(gtk.Statusbar): + """A custom status bar with smart placement of messages.""" + + def __init__(self): + super(SmartStatusbar, self).__init__() + + self.static = None + self.pairs = {} + + self._context = self.get_context_id('Mitter') + return + + def static(self, message): + """Place a new static message in the statusbar. Only one static + message can be in the message stack at a time; if there is any static + messages in the stack, it will be removed before the new one is + added.""" + if self.static: + # remove any previous static messages + self.remove_message(self._context, self.static) + + self.static = self.push(self._context, message) + return + + def volatile(self, message, seconds=10, pair=None): + """Place a new volatile message in the statusbar. Volatile messages + are removed from the statusbar in two possiblities: + * The first way is after the number of seconds has passed. + * The second way by pairing; The first time a message appears with a + pair name, it is not queued for removal after some time like normal + messages; the message will stay in the message stack till its pair + appear, when it will be finally removed; the second message, in this + case, will be removed after the number of seconds, like any + non-paired message.""" + message_id = self.push(self._context, message)) + + # pair checking + if pair: + if pair in self.pairs: + # this is the second message. We remove the first one and + # this one will be removed like any other message. + first = self.pairs[pair] + self.remove_message(self._context, first) + del self.pairs[pair] + else: + # this is the first message of the pair. It will not be + # removed but the timeout. + self.pairs[pairs] = message_id + return + + self.timeout = gobject.timeout_add( + seconds * 1000, # removal after 20 seconds + self.remove_volatile, message_id) + return + + def kill_volatiles(self, message_id): + """Kill all messages that are marked as volatiles.""" + self.remove_message(self._context, message_id) + return diff --git a/mitterlib/ui/ui_pygtk.py b/mitterlib/ui/ui_pygtk.py index 94fb5e6..b103ea4 100644 --- a/mitterlib/ui/ui_pygtk.py +++ b/mitterlib/ui/ui_pygtk.py @@ -33,6 +33,7 @@ from mitterlib.ui.helpers.gtk_threading import ThreadManager from mitterlib.ui.helpers.gtk_updatebox import UpdateBox from mitterlib.ui.helpers.gtk_messagegrid import MessageGrid from mitterlib.ui.helpers.gdk_avatarcache import AvatarCache +from mitterlib.ui.helpers.gtk_smartbar import SmartStatusbar from mitterlib.constants import gpl_3, version from mitterlib.network import NetworksNoNetworkSetupError @@ -88,7 +89,7 @@ class Interface(object): self._update_field = UpdateBox( self._images['avatar'], self._options[self.NAMESPACE]['spell_check']) - self._statusbar = self._create_statusbar() + self._statusbar = SmartStatusbar() # the messages grid messages = MessageGrid(self._avatars) @@ -325,12 +326,6 @@ class Interface(object): return (main_menu, main_toolbar, uimanager.get_accel_group()) - def _create_statusbar(self): - """Create the statusbar.""" - statusbar = gtk.Statusbar() - self._statusbar_context = statusbar.get_context_id('Mitter') - return statusbar - def _show_about(self, widget): """Show the about dialog.""" about_window = gtk.AboutDialog() @@ -363,12 +358,6 @@ class Interface(object): # ------------------------------------------------------------ # Helper functions # ------------------------------------------------------------ - def _update_statusbar(self, message): - """Update the statusbar with the message.""" - self._statusbar.pop(self._statusbar_context) - self._statusbar.push(self._statusbar_context, message) - return - def _refresh(self, widget=None): """Request a refresh. *widget* is the widget that called this function (we basically ignore it.)""" @@ -385,7 +374,7 @@ class Interface(object): self._refresh_id = None # do the refresh - self._update_statusbar(_('Retrieving messages...')) + self._statusbar.volatile(_('Retrieving messages...'), pair='refresh') self._threads.add_work(self._post_get_messages, self._exception_get_messages, self._connection.messages) @@ -520,7 +509,7 @@ class Interface(object): _log.debug('Status: %s', status) - self._update_statusbar(_('Sending update...')) + self._statusbar.volatile(_('Sending update...'), pair='update') self._action_group.get_action('Update').set_sensitive(False) self._threads.add_work(self._post_update_status, self._exception_update_status, @@ -590,7 +579,7 @@ class Interface(object): _log.debug("Delete cancelled") return False - self._update_statusbar(_('Deleting message...')) + self._statusbar.volatile(_('Deleting message...'), pair='delete') _log.debug('Deleting messing %d', message.id) self._threads.add_work(self._post_delete_message, self._exception_delete_message, @@ -804,7 +793,6 @@ class Interface(object): grid.update(results) # now get replies - self._update_statusbar(_('Retrieving replies...')) self._threads.add_work(self._post_get_replies, self._exception_get_messages, self._connection.replies) @@ -847,6 +835,8 @@ class Interface(object): grid = self._main_tabs.get_nth_page(1) grid.update(results) + self._statusbar.volatile(_('Messages retrieved'), pair='refresh') + interval = self._options[self.NAMESPACE]['refresh_interval'] # once our update went fine, we can queue the next one. This avoids @@ -863,7 +853,7 @@ class Interface(object): # TODO: Check if the time format string should go in the config file. message = '%s %s (at %s).' % (prefix, suffix, next_update) - self._update_statusbar(message % (interval)) + self._statusbar.static(message % (interval)) self._refresh_id = gobject.timeout_add( interval * 60 * 1000, self._refresh, None)