deskbar-applet r2252 - in trunk: . deskbar/core deskbar/ui deskbar/ui/cuemiac



Author: sebp
Date: Mon Jul 21 14:43:38 2008
New Revision: 2252
URL: http://svn.gnome.org/viewvc/deskbar-applet?rev=2252&view=rev

Log:
Access history like in 2.18.
Added arrow beside the Deskbar icon. Clicking on it will show the a list of previously activated actions.
History is still missing in tray mode.

Modified:
   trunk/ChangeLog
   trunk/deskbar/core/DeskbarHistory.py
   trunk/deskbar/ui/AbstractCuemiacView.py
   trunk/deskbar/ui/CuemiacAlignedView.py
   trunk/deskbar/ui/CuemiacWindowView.py
   trunk/deskbar/ui/DeskbarApplet.py
   trunk/deskbar/ui/cuemiac/CuemiacHistory.py

Modified: trunk/deskbar/core/DeskbarHistory.py
==============================================================================
--- trunk/deskbar/core/DeskbarHistory.py	(original)
+++ trunk/deskbar/core/DeskbarHistory.py	Mon Jul 21 14:43:38 2008
@@ -10,17 +10,16 @@
 
 LOGGER = logging.getLogger(__name__)
 
-class ChooseFromHistoryAction (deskbar.interfaces.Action):
+class EmptyHistoryAction (deskbar.interfaces.Action):
     """
-    This will be displayed always at the top of the history
-    and is just there to display "Choose action"
+    This will be displayed if history is empty
     """
     
     def __init__(self):
         deskbar.interfaces.Action.__init__(self, "")
         
     def get_verb(self):
-        return _("<i>Choose action</i>")
+        return _("<i>Empty history</i>")
     
     def activate(self, text=None):
         pass
@@ -57,10 +56,8 @@
         self.set_sort_order (gtk.SORT_DESCENDING)
         self.set_sort_func (self.COL_TIME, self.__sort_actions)
         
-        self._index = 0 # We don't want to show ChooseFromHistoryAction
+        self._index = -1
         self.set_max_history_items(max_history_items)
-        
-        self.append(0, "", ChooseFromHistoryAction())
     
     def set_sort_order(self, order):
         """
@@ -98,23 +95,18 @@
         """
         action1 = model[iter1][self.COL_ACTION]
         action2 = model[iter2][self.COL_ACTION]
-        
-        if isinstance(action1, ChooseFromHistoryAction):
+                
+        if self[iter1][self.COL_TIME] > self[iter2][self.COL_TIME] :
             return 1
-        elif isinstance(action2, ChooseFromHistoryAction):
+        else:
             return -1
-        else:        
-            if self[iter1][self.COL_TIME] > self[iter2][self.COL_TIME] :
-                return 1
-            else:
-                return -1
     
     def clear (self):
         """
         Clear the history
         """
         gtk.ListStore.clear(self)
-        self.append("", "", ChooseFromHistoryAction())
+        self.append("", "", EmptyHistoryAction())
         self._index = -1
         self.emit("cleared")
     
@@ -144,6 +136,9 @@
             LOGGER.error("Could not restore history")
             LOGGER.exception(e)
             pass
+        
+        if len(self) == 0:
+            self.append(0, "", EmptyHistoryAction())
 
     def save (self):
         """
@@ -151,7 +146,7 @@
         """
         save = []
         for timestamp, text, action in self:
-            if not isinstance(action, ChooseFromHistoryAction):
+            if not isinstance(action, EmptyHistoryAction):
                 save.append((timestamp, text, action))
         
         try:
@@ -181,7 +176,10 @@
         """
         assert text != None and action != None
         
-        if isinstance(action, ChooseFromHistoryAction):
+        if not isinstance(action, deskbar.interfaces.Action):
+            raise TypeError("Action must be a deskbar.interfaces.Action instance")
+        
+        if isinstance(action, EmptyHistoryAction):
             return
         if action.skip_history():
             self.reset()
@@ -189,6 +187,10 @@
         
         for idx, val in enumerate(self):
             htime, htext, haction = val
+            if isinstance(haction, EmptyHistoryAction):
+                self.remove (self.get_iter_from_string (str(idx)))
+                continue
+                
             if (action.get_hash() == haction.get_hash() and action.__class__.__name__ == haction.__class__.__name__):
                 self.remove (self.get_iter_from_string (str(idx)))
                 break
@@ -225,8 +227,8 @@
         """
         Reset index
         """
-        if self._index != 0:
-            self._index = 0
+        if self._index != -1:
+            self._index = -1
             return self.get_current()
     
     def last(self):
@@ -248,7 +250,7 @@
         """
         Get action where the current index points to
         """
-        if self._index == 0:
+        if self._index == -1:
             return None
         col_id, direction = self.get_sort_column_id()
         index = self._index

Modified: trunk/deskbar/ui/AbstractCuemiacView.py
==============================================================================
--- trunk/deskbar/ui/AbstractCuemiacView.py	(original)
+++ trunk/deskbar/ui/AbstractCuemiacView.py	Mon Jul 21 14:43:38 2008
@@ -9,7 +9,6 @@
 from deskbar.ui.cuemiac.CuemiacModel import CuemiacModel
 from deskbar.ui.cuemiac.CuemiacTreeView import CuemiacTreeView
 from deskbar.ui.cuemiac.CuemiacItems import CuemiacCategory
-from deskbar.ui.cuemiac.CuemiacHistory import CuemiacHistoryView
 from deskbar.ui.cuemiac.CuemiacActionsTreeView import CuemiacActionsTreeView, CuemiacActionsModel
 from deskbar.ui.cuemiac.LingeringSelectionWindow import LingeringSelectionWindow
 
@@ -42,10 +41,6 @@
         self._create_header()
         self.header.show()
         
-        # History TreeView
-        self._create_history_box()
-        self.history_box.show()
-        
         # Results TreeView
         self._create_results_treeview()
         self.cview.show()
@@ -92,34 +87,7 @@
         self.entry.show()
         
         self.header = CuemiacHeader ( self.entry )
-        
-    def _create_history_box(self):
-        """
-        Sets:
-            * self.history_box
-            * self.hview
-            * self.empty_button
-        """
-        self.history_box = gtk.HBox(spacing=6)
-        
-        hlabel = gtk.Label()
-        # translators: _H is a mnemonic, i.e. pressing Alt+h will focus the widget
-        hlabel.set_markup_with_mnemonic("<b>%s:</b>" % _("_History"))
-        hlabel.show()
-        self.history_box.pack_start(hlabel, False)
-        
-        self.hview = CuemiacHistoryView(self._model.get_history())
-        self.hview.connect("match-selected", self._controller.on_history_match_selected)
-        self.hview.show()
-        self.history_box.pack_start(self.hview)
-        hlabel.set_mnemonic_widget(self.hview)
-        
-        self.empty_button = gtk.Button()
-        self.empty_button.set_image( gtk.image_new_from_stock(gtk.STOCK_CLEAR, gtk.ICON_SIZE_MENU) )
-        self.empty_button.connect("clicked", self._controller.on_clear_history)
-        self.empty_button.show()
-        self.history_box.pack_start(self.empty_button, False)
-        
+    
     def _create_results_treeview(self):
         """
         Sets:
@@ -215,7 +183,6 @@
     def clear_query(self):
         self.entry.set_text("")
         self.entry.set_icon( self.default_entry_pixbuf )
-        
     
     def get_entry(self):
         return self.entry
@@ -228,8 +195,7 @@
         self._do_clear = True
         
     def mark_history_empty(self, val):
-        self.hview.set_sensitive (not val)
-        self.empty_button.set_sensitive (not val)
+        pass
     
     def show_results(self):
         self.results_box.show()
@@ -278,5 +244,4 @@
             # Display default icon in entry
             self.update_entry_icon()
         self.treeview_model.append (matches, self.entry.get_text())
-    
     
\ No newline at end of file

Modified: trunk/deskbar/ui/CuemiacAlignedView.py
==============================================================================
--- trunk/deskbar/ui/CuemiacAlignedView.py	(original)
+++ trunk/deskbar/ui/CuemiacAlignedView.py	Mon Jul 21 14:43:38 2008
@@ -39,7 +39,7 @@
         self.set_default_size( self._model.get_window_width(), -1 )
 
         self.set_role("deskbar-search-window")
-
+        
         # VBox
         self.add(self.vbox_main)
         
@@ -85,9 +85,9 @@
         # FIXME: Should we handle width intelligently also?
         w, h = self.cview.size_request ()
         # To ensure we don't always show scrollbars
-        h += self.header.allocation.height + self.history_box.allocation.height
-        # Spacing between header and history_box and between history_box and results_box
-        h += 2*self.VBOX_MAIN_SPACING
+        h += self.header.allocation.height
+        # Spacing between header and results_box
+        h += self.VBOX_MAIN_SPACING
         # Border at the top and the bottom
         h += 2*self.VBOX_MAIN_BORDER_WIDTH
         # Some additional space
@@ -109,12 +109,10 @@
         """
         if orient in [gnomeapplet.ORIENT_LEFT, gnomeapplet.ORIENT_RIGHT, gnomeapplet.ORIENT_DOWN]:
             self.vbox_main.pack_start(self.header, False)
-            self.vbox_main.pack_start(self.history_box, False)
             self.vbox_main.pack_start(self.results_box)
         else:
             # We are at a bottom panel. Put entry on bottom, and prepend matches (instead of append).
             self.vbox_main.pack_start(self.results_box)
-            self.vbox_main.pack_start(self.history_box, False)
             self.vbox_main.pack_start(self.header, False)
         
     def __set_sort_order_by_orientation(self, orient):

Modified: trunk/deskbar/ui/CuemiacWindowView.py
==============================================================================
--- trunk/deskbar/ui/CuemiacWindowView.py	(original)
+++ trunk/deskbar/ui/CuemiacWindowView.py	Mon Jul 21 14:43:38 2008
@@ -30,9 +30,6 @@
         # Search entry
         self.vbox_main.pack_start(self.header, False)
         
-        # History TreeView
-        self.vbox_main.pack_start(self.history_box, False)
-        
         # Results
         self.results_box = gtk.HBox()
         self.results_box.connect("unmap", self.__save_window_height)

Modified: trunk/deskbar/ui/DeskbarApplet.py
==============================================================================
--- trunk/deskbar/ui/DeskbarApplet.py	(original)
+++ trunk/deskbar/ui/DeskbarApplet.py	Mon Jul 21 14:43:38 2008
@@ -4,8 +4,136 @@
 import os.path
 import gobject
 from deskbar.ui.AbstractCuemiacDeskbarIcon import AbstractCuemiacDeskbarIcon
+from deskbar.ui.cuemiac.CuemiacHistory import CuemiacHistoryView, CuemiacHistoryPopup
 from gettext import gettext as _
 
+class ToggleEventBox(gtk.EventBox):
+    __gsignals__ = {
+        "toggled" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []),
+    }
+    
+    def __init__(self):
+        gtk.EventBox.__init__(self)
+        self.active = False
+        self.set_visible_window(False)
+        self.connect('button-press-event', self.on_button_press)
+    
+    def on_button_press(self, widget, event):
+        if event.button == 1:
+            self.set_active(not self.active)
+            return True
+                
+    def get_active(self):
+        return self.active
+    
+    def set_active(self, active):
+        changed = (self.active != active)
+        self.active = active
+        
+        if changed:
+            self.emit("toggled")
+    
+class CuemiacAppletButton (gtk.HBox):
+    """
+    Button consisting of two toggle buttons. A "main" with and image, and an "arrow"
+    with a gtk.Arrow.
+    
+    It automatically arranges itself according to one of 
+    gnomeapplet.ORIENT_UP,gnomeapplet.ORIENT_{UP,DOWN,LEFT,RIGHT}.
+    
+    Signals:
+        toggled-main: The main button has been toggled
+        toggle-arrow: the arrow button has been toggled
+        
+    The widget implements an interface like the gtk.ToggleButton, with _main or _arrow
+    appended to method names for each button.
+    """
+    __gsignals__ = {
+        "toggled-main" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []),
+        "toggled-arrow" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [])
+    }
+
+    def __init__ (self, applet):
+        gtk.HBox.__init__ (self)
+        self.applet = applet
+        self.applet.connect("change-orient", lambda applet, orient: self.set_layout_by_orientation(orient))
+        self.arrow = None
+        self.box = None
+        popup_dir = applet.get_orient()
+            
+        self.button_main = ToggleEventBox()
+        self.button_main.connect ("toggled", lambda widget: self.emit ("toggled-main"))
+        
+        self.image = gtk.Image ()
+        self.button_main.add (self.image)
+        
+        self.button_arrow = ToggleEventBox()
+        self.button_arrow.connect ("toggled", lambda widget: self.emit ("toggled-arrow"))
+                
+        self.button_main.set_tooltip_markup(_("Show search entry"))
+        self.button_arrow.set_tooltip_markup(_("Show previously used actions"))
+        
+        self.set_layout_by_orientation(popup_dir)
+        
+    def get_active_main (self):
+        return self.button_main.get_active ()
+    
+    def set_active_main (self, is_active):
+        self.button_main.set_active (is_active)
+    
+    def get_active_arrow (self):
+        return self.button_arrow.get_active ()
+
+    def set_active_arrow (self, is_active):
+        self.button_arrow.set_active (is_active)
+            
+    def set_button_image_from_pixbuf (self, pixbuf):
+        self.image.set_from_pixbuf (pixbuf)
+        
+    def gnomeapplet_dir_to_arrow_dir (self, gnomeapplet_dir):
+        """
+        Returns the appropriate gtk.ARROW_{UP,DOWN,LEFT,RIGHT} corresponding
+        to gnomeapplet_dir; which can be one of
+        gnomeapplet.ORIENT_{UP,DOWN,LEFT,RIGHT}
+        """
+        if gnomeapplet_dir == gnomeapplet.ORIENT_DOWN:
+            return gtk.ARROW_DOWN
+        elif gnomeapplet_dir == gnomeapplet.ORIENT_UP:
+            return gtk.ARROW_UP
+        elif gnomeapplet_dir == gnomeapplet.ORIENT_LEFT:
+            return gtk.ARROW_LEFT
+        else:
+            return gtk.ARROW_RIGHT
+    
+    def set_layout_by_orientation (self, orientation):
+        """
+        @param orientation: should be a gnomeapplet.ORIENT_{UP,DOWN,LEFT,RIGHT}.
+        
+        This method calls self.show_all()
+        """
+        if self.box != None:
+            self.box.remove (self.button_arrow)
+            self.box.remove (self.button_main)
+            self.remove (self.box)
+        if self.arrow != None:
+            self.button_arrow.remove (self.arrow)
+        
+        if orientation in [gnomeapplet.ORIENT_UP,gnomeapplet.ORIENT_DOWN]:
+            self.box = gtk.HBox ()
+        else:
+            self.box = gtk.VBox ()
+                
+        self.arrow = gtk.Arrow (self.gnomeapplet_dir_to_arrow_dir(orientation), gtk.SHADOW_IN)
+        
+        self.add (self.box)
+        self.button_arrow.add (self.arrow)
+        
+        self.box.pack_start (self.button_main)
+        self.box.pack_end (self.button_arrow, False, False)
+                
+        self.show_all ()
+    
+    
 class DeskbarApplet (gnomeapplet.Applet, AbstractCuemiacDeskbarIcon):
     
     def __init__(self, applet):
@@ -18,26 +146,30 @@
         self.applet.set_applet_flags (gnomeapplet.EXPAND_MINOR)
         self.applet.set_background_widget(self.applet)
         
-        self.tray = gtk.EventBox()
-        self.tray.set_visible_window(False)
-        self.tray.set_sensitive(False)
-        self.tray.connect('button-press-event', self.on_button_press)
+        self.tray = CuemiacAppletButton(applet)
+        self.tray.connect('toggled-main', self.on_toggled_main)
+        self.tray.connect('toggled-arrow', self.on_toggled_arrow)
         self.applet.add(self.tray)
         self.tray.show()
         
-        self.tray.set_tooltip_markup(_("Show search entry"))
-        
-        self.image = gtk.Image ()
-        self.tray.add(self.image)
-        self.image.show()
-        
         self.setup_menu()
         self._setup_mvc()
         
         self._set_image(self.applet.get_size())
         
+        self._setup_history()
+        
         self.applet.show_all()
 
+    def _setup_history(self):
+        self.hview = CuemiacHistoryView(self._core.get_history())
+        self.hview.connect("match-selected", self._controller.on_history_match_selected)
+        self.hview.show()
+        
+        self.history_popup = CuemiacHistoryPopup (self.tray.button_arrow,
+                            self.applet,
+                            self.hview)
+
     def on_allocate(self, applet, alloc):
         if self.applet.get_orient () in [gnomeapplet.ORIENT_UP, gnomeapplet.ORIENT_DOWN]:
             size_alloc = alloc.height
@@ -53,8 +185,7 @@
         pixbuf = self.get_deskbar_icon(size_alloc)
         
         self.applet.handler_block(self.handler_size_allocate_id)
-        self.image.set_from_pixbuf (pixbuf)
-        self.tray.set_size_request (size_alloc, size_alloc)
+        self.tray.set_button_image_from_pixbuf(pixbuf)
         # If we unblock immediately we get an infinite loop
         gobject.timeout_add(100, self.unblock_allocate)
         
@@ -62,13 +193,16 @@
         self.applet.handler_unblock (self.handler_size_allocate_id)
         return False
     
-    def on_button_press(self, widget, event):
-        if event.button == 1: # left mouse button
-            self.set_active (not self.get_active(), event.time)
-            return True
+    def on_toggled_main(self, widget):
+         self.set_active (not self.get_active(),
+                          gtk.get_current_event_time())
+    
+    def on_toggled_arrow(self, widget):
+        self._controller.on_quit()
+        self.history_popup.popup ()
     
     def get_reference_widget(self):
-        return self.image
+        return self.tray
     
     def get_applet(self):
         return self.applet

Modified: trunk/deskbar/ui/cuemiac/CuemiacHistory.py
==============================================================================
--- trunk/deskbar/ui/cuemiac/CuemiacHistory.py	(original)
+++ trunk/deskbar/ui/cuemiac/CuemiacHistory.py	Mon Jul 21 14:43:38 2008
@@ -2,18 +2,23 @@
 import pango
 import gobject
 import logging
+from deskbar.ui.cuemiac.CuemiacAlignedWindow import CuemiacAlignedWindow
 
 LOGGER = logging.getLogger(__name__)
 
-class CuemiacHistoryView (gtk.ComboBox):
+class CuemiacHistoryView (gtk.TreeView):
 
     __gsignals__ = {
         "match-selected" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [gobject.TYPE_STRING, gobject.TYPE_PYOBJECT]),
     }
     
     def __init__ (self, historystore):
-        gtk.ComboBox.__init__ (self, historystore)
-        historystore.connect("cleared", self.__select_default_item)
+        gtk.TreeView.__init__ (self, historystore)
+        
+        self.connect ("row-activated", lambda w,p,c: self.__on_activated())
+        self.connect ("button-press-event", lambda w,e: self.__on_activated())
+        self.set_property ("headers-visible", False)
+        self.set_property ("hover-selection", True)
         
         icon = gtk.CellRendererPixbuf ()
         icon.set_property("xpad", 4)
@@ -23,14 +28,12 @@
         title.set_property ("ellipsize", pango.ELLIPSIZE_END)
         title.set_property ("width-chars", 25) #FIXME: Pick width according to screen size
         
-        self.pack_start (icon, expand=False)
-        self.pack_start (title)
-        self.set_cell_data_func(title, self.__get_action_title_for_cell)            
-        self.set_cell_data_func(icon, self.__get_action_icon_for_cell)
-        
-        self.set_active(0)
-        
-        self.__changed_id = self.connect ("changed", lambda w: self.__on_activated())             
+        hits = gtk.TreeViewColumn ("Hits")
+        hits.pack_start (icon)
+        hits.pack_start (title)            
+        hits.set_cell_data_func(icon, self.__get_action_icon_for_cell)
+        hits.set_cell_data_func(title, self.__get_action_title_for_cell)
+        self.append_column (hits)
         
     def __get_action_icon_for_cell (self, celllayout, cell, model, iter, user_data=None):
         
@@ -53,7 +56,7 @@
         cell.set_property ("markup", text)
 
     def __on_activated (self):
-        iter = self.get_active_iter()
+        model, iter = self.get_selection().get_selected()
         if iter != None:
             timestamp, text, action = self.get_model()[iter]
             if not action.is_valid():
@@ -62,14 +65,102 @@
                 self.__select_default_item()
                 return False
             self.emit ("match-selected", text, action)
-            self.__select_default_item()
             
         return False
 
-    def __select_default_item(self, model=None):
-        self.handler_block(self.__changed_id)
-        self.set_active ( 0 )
-        self.handler_unblock(self.__changed_id)
+class CuemiacHistoryPopup (CuemiacAlignedWindow) :
+    
+    def __init__ (self, widget_to_align_with, applet, history_view):
+        """
+        @param widget_to_align_with: A widget the popup should align itself to.
+        @param applet: A gnomeapplet.Applet instance. However - all that is needed is a .window attribute and a get_orient() method.
+        @param history_view: A L{CuemiacHistoryView} instance.
+        """
+        CuemiacAlignedWindow.__init__ (self, widget_to_align_with, applet, window_type=gtk.WINDOW_POPUP)
+        self.applet = applet
+        self.window_group = None
+        
+        self.view = history_view
+            
+        self.add (self.view)
+        self.view.connect('enter-notify-event', self.on_view_enter)
+        self.view.connect('motion-notify-event', self.on_view_motion)
+        self.view.connect('button-press-event', self.on_view_button_press)
+        
+    def on_view_button_press (self, widget, event):
+        self.popdown()
+        return False
+    
+    def on_view_enter (self, widget, event):
+        return self.ignore_enter
+            
+    def on_view_motion (self, widget, event):
+        self.ignore_enter = False
+        return False
+    
+    def popup (self, time=None):
+        if not (self.widgetToAlignWith.flags() & gtk.REALIZED):
+            return
+        if (self.flags()&gtk.MAPPED):
+            return
+        if not (self.widgetToAlignWith.flags()&gtk.MAPPED):
+            return
+        if len(self.view.get_model()) <= 0:
+            return
+        
+        self.ignore_enter = True
+        
+        if not self.window_group :
+            target_toplevel = self.widgetToAlignWith.get_toplevel()
+            if target_toplevel != None and target_toplevel.group != None:
+                target_toplevel.group.add_window (self)
+                self.target_group = target_toplevel.group
+            elif target_toplevel is not None:
+                self.window_group = gtk.WindowGroup ()
+                self.window_group.add_window (target_toplevel)
+                self.window_group.add_window (self)
+            else:
+                print "WARNING in CuemiacEntryPopup : No toplevel window for widgetToAlignWith!"
+                return
+                    
+        self.update_position()
+        gtk.Window.show_all (self) # We issue warnings on the native methods, so bypass that
+
+        # For grabbing to work we need the view realized
+        if not (self.view.flags() & gtk.REALIZED):
+            self.view.realize ()
+
+        # Grab pointer
+        self.view.grab_add()
+        gtk.gdk.pointer_grab(
+            self.view.window, True,
+            gtk.gdk.BUTTON_PRESS_MASK|
+                gtk.gdk.BUTTON_RELEASE_MASK|
+                gtk.gdk.POINTER_MOTION_MASK,
+            None, None, gtk.get_current_event_time())
+            
+    def popdown (self):
+        if not (self.flags()&gtk.MAPPED):
+            return
+        
+        self.ignore_enter = False
+
+        gtk.Window.hide (self) # Bypass the warning we issue on hide()
 
+        # Ungrab pointer
+        gtk.gdk.pointer_ungrab(gtk.get_current_event_time())
+        self.view.grab_remove()
+    
+    def show (self):
+        LOGGER.warning("CuemiacHistoryPopup : Use of show() detected. Please use popup() instead.")
+    
+    def show_all (self):
+        LOGGER.warning("WARNING, CuemiacHistoryPopup : Use of show_all() detected. Please use popup() instead.")
+    
+    def hide (self):
+        LOGGER.warning("WARNING, CuemiacHistoryPopup : Use of hide() detected. Please use popdown() instead.")
+    
 if gtk.pygtk_version < (2,8,0):    
     gobject.type_register (CuemiacHistoryView)
+    gobject.type_register (CuemiacHistoryPopup)
+    
\ No newline at end of file



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]