Re: [Deskbar] first attempt at a cuemiac/pearl merge
- From: Raphael Slinckx <raphael slinckx net>
- To: deskbar-applet-list gnome org
- Subject: Re: [Deskbar] first attempt at a cuemiac/pearl merge
- Date: Sat, 07 Jan 2006 13:44:26 +0100
On Sat, 2006-01-07 at 12:53 +0100, Mikkel Kamstrup Erlandsen wrote:
>
> Just to follow up on self... Here's a revised version of the pearl.py
> headers so you won't have to to rumage around with diffs to get a clear
> view of how far we/I are/am.
Quick fix:
remove Makefile and Makefile.in from patch
remove _() around "Actions"
Note: you must remove the pearl.py and categories.py from the previous
tarball (if you have it)
patch will complain anyway if they are present.
apply with:
cd deskbar-applet
patch -p2 < pearl-0.1.patch
enjoy
The rest is coming later
Raf
diff -ruN ../deskbar-applet/deskbar/categories.py deskbar/categories.py
--- ../deskbar-applet/deskbar/categories.py 1970-01-01 01:00:00.000000000 +0100
+++ deskbar/categories.py 2006-01-07 03:46:06.000000000 +0100
@@ -0,0 +1,73 @@
+
+class UnknownCategory (Exception):
+ def __init__ (self, category_name, match):
+ print "** Unknown Category '%s' requested by %s" % (category_name, match.__class__)
+
+
+CATEGORIES = {
+ "Files" : {
+ "name": "Files",
+ "nest": "<b>%(count)s</b> <i>more files</i>",
+ "threshold": 3
+ },
+ "Actions" : {
+ "name": "Actions",
+ "nest": "<b>%(count)s</b> <i>more actions</i>",
+ "threshold": 1
+ },
+ "News" : {
+ "name": "News",
+ "nest": "<b>%(count)s</b> <i>more news items</i>",
+ "threshold": 3
+ },
+ "Contacts" : {
+ "name": "Contacts",
+ "nest": "<b>%(count)s</b> <i>more contacts</i>",
+ "threshold": 3
+ },
+ "Emails" : {
+ "name": "Emails",
+ "nest": "<b>%(count)s</b> <i>more emails</i>",
+ "threshold": 3
+ },
+ "Notes" : {
+ "name": "Notes",
+ "nest": "<b>%(count)s</b> <i>more notes</i>",
+ "threshold": 3
+ },
+ "Volumes" : {
+ "name": "Volumes",
+ "nest": "<b>%(count)s</b> <i>more volumes</i>",
+ "threshold": 3
+ },
+ "Google Search" : {
+ "name": "Google Search",
+ "nest": "<b>%(count)s</b> <i>more online hits</i>",
+ "threshold": 2
+ },
+ "Calendar" : {
+ "name": "Calendar",
+ "nest": "<b>%(count)s</b> <i>more calendar items</i>",
+ "threshold": 1
+ },
+ "Conversation" : {
+ "name": "Conversation",
+ "nest": "<b>%(count)s</b> <i>more conversations</i>",
+ "threshold": 1
+ },
+ "Web Browser" : {
+ "name":"Web Browser",
+ "nest":"<b>%(count)s</b> <i>more items</i>",
+ "threshold":5,
+ },
+ "Programs" : {
+ "name":"Programs",
+ "nest":"<b>%(count)s</b> <i>more programs</i>",
+ "threshold":3,
+ },
+ "Debug" : {
+ "name":"Debug",
+ "nest":"<b>%(count)s</b> <i>more debugging handlers</i>",
+ "threshold":2,
+ },
+}
diff -ruN ../deskbar-applet/deskbar/handlers/beagle-live.py deskbar/handlers/beagle-live.py
--- ../deskbar-applet/deskbar/handlers/beagle-live.py 2005-12-21 17:17:49.000000000 +0100
+++ deskbar/handlers/beagle-live.py 2006-01-07 03:44:12.000000000 +0100
@@ -122,6 +122,16 @@
self.__result = result
+ def get_category (self):
+ t = self.__result["type"]
+ if t == "MailMessage" : return "Emails"
+ elif t == "Contact": return "Contacts"
+ elif t == "File": return "Files"
+ elif t == "FeedItem": return "News"
+ elif t == "Note": return "Notes"
+ elif t == "IMLog": return "Conversation"
+ elif t == "Calendar": return "Calendar"
+
def get_name (self, text=None):
# We use the result dict itself to look up words
return self.__result
Binary files ../deskbar-applet/deskbar/handlers/beagle-live.pyc and deskbar/handlers/beagle-live.pyc differ
diff -ruN ../deskbar-applet/deskbar/handlers/beagle.py deskbar/handlers/beagle.py
--- ../deskbar-applet/deskbar/handlers/beagle.py 2005-12-26 18:37:06.000000000 +0100
+++ deskbar/handlers/beagle.py 2006-01-07 03:44:12.000000000 +0100
@@ -29,6 +29,9 @@
def action(self, text=None):
gobject.spawn_async(["best", '--no-tray', '--show-window', self._name], flags=gobject.SPAWN_SEARCH_PATH)
+ def get_category(self):
+ return "Actions"
+
def get_verb(self):
return _("Search for %s using Beagle") % "<b>%(name)s</b>"
Binary files ../deskbar-applet/deskbar/handlers/beagle.pyc and deskbar/handlers/beagle.pyc differ
diff -ruN ../deskbar-applet/deskbar/handlers/debug-async_handler.py deskbar/handlers/debug-async_handler.py
--- ../deskbar-applet/deskbar/handlers/debug-async_handler.py 2005-11-15 05:27:26.000000000 +0100
+++ deskbar/handlers/debug-async_handler.py 2006-01-07 03:44:12.000000000 +0100
@@ -22,6 +22,9 @@
def action(self, text=None):
print str(self.__class__) + " : action triggered"
+
+ def get_category (self):
+ return "Debug"
class AsyncDebugHandler (AsyncHandler):
Binary files ../deskbar-applet/deskbar/handlers/debug-async_handler.pyc and deskbar/handlers/debug-async_handler.pyc differ
diff -ruN ../deskbar-applet/deskbar/handlers/debug-requirements.py deskbar/handlers/debug-requirements.py
--- ../deskbar-applet/deskbar/handlers/debug-requirements.py 2005-11-28 21:16:27.000000000 +0100
+++ deskbar/handlers/debug-requirements.py 2006-01-07 03:44:12.000000000 +0100
@@ -33,6 +33,9 @@
def action(self, text=None):
pass
+
+ def get_category (self):
+ return "Debug"
class DebugRequirementsModule(deskbar.handler.Handler):
def __init__ (self):
Binary files ../deskbar-applet/deskbar/handlers/debug-requirements.pyc and deskbar/handlers/debug-requirements.pyc differ
diff -ruN ../deskbar-applet/deskbar/handlers/debug-signal_handler.py deskbar/handlers/debug-signal_handler.py
--- ../deskbar-applet/deskbar/handlers/debug-signal_handler.py 2005-11-15 05:27:26.000000000 +0100
+++ deskbar/handlers/debug-signal_handler.py 2006-01-07 03:44:12.000000000 +0100
@@ -19,6 +19,9 @@
def action(self, text=None):
print str(self.__class__) + " : action triggered"
+
+ def get_category (self):
+ return "Debug"
class SignallingDebugHandler(SignallingHandler):
Binary files ../deskbar-applet/deskbar/handlers/debug-signal_handler.pyc and deskbar/handlers/debug-signal_handler.pyc differ
diff -ruN ../deskbar-applet/deskbar/handlers/email_address.py deskbar/handlers/email_address.py
--- ../deskbar-applet/deskbar/handlers/email_address.py 2005-11-15 05:27:27.000000000 +0100
+++ deskbar/handlers/email_address.py 2006-01-07 03:44:12.000000000 +0100
@@ -21,6 +21,9 @@
def action(self, text=None):
gnomevfs.url_show("mailto:"+self._email)
+
+ def get_category(self):
+ return "Emails"
def get_verb(self):
return _("Send Email to %s") % "<b>%(name)s</b>"
Binary files ../deskbar-applet/deskbar/handlers/email_address.pyc and deskbar/handlers/email_address.pyc differ
Binary files ../deskbar-applet/deskbar/handlers/epiphany.pyc and deskbar/handlers/epiphany.pyc differ
diff -ruN ../deskbar-applet/deskbar/handlers/evolution.py deskbar/handlers/evolution.py
--- ../deskbar-applet/deskbar/handlers/evolution.py 2006-01-02 01:57:54.000000000 +0100
+++ deskbar/handlers/evolution.py 2006-01-07 03:44:12.000000000 +0100
@@ -29,6 +29,9 @@
def action(self, text=None):
gnomevfs.url_show("mailto:"+self._email)
+
+ def get_category(self):
+ return "Contacts"
def get_name(self, text=None):
return {
Binary files ../deskbar-applet/deskbar/handlers/evolution.pyc and deskbar/handlers/evolution.pyc differ
diff -ruN ../deskbar-applet/deskbar/handlers/files.py deskbar/handlers/files.py
--- ../deskbar-applet/deskbar/handlers/files.py 2005-11-18 15:14:25.000000000 +0100
+++ deskbar/handlers/files.py 2006-01-07 03:44:12.000000000 +0100
@@ -27,6 +27,9 @@
def action(self, text=None):
gobject.spawn_async(["gnome-open", self._filename], flags=gobject.SPAWN_SEARCH_PATH)
+ def get_category(self):
+ return "Files"
+
def get_verb(self):
return _("Open %s") % "<b>%(name)s</b>"
Binary files ../deskbar-applet/deskbar/handlers/files.pyc and deskbar/handlers/files.pyc differ
diff -ruN ../deskbar-applet/deskbar/handlers/galago.py deskbar/handlers/galago.py
--- ../deskbar-applet/deskbar/handlers/galago.py 2006-01-02 01:57:54.000000000 +0100
+++ deskbar/handlers/galago.py 2006-01-07 03:44:12.000000000 +0100
@@ -21,6 +21,9 @@
def action(self, text=None):
gnomevfs.url_show("mailto:"+self._email)
+
+ def get_category(self):
+ return "Contacts"
def get_verb(self):
return _("Send Email to %s") % "<b>%(name)s</b>"
Binary files ../deskbar-applet/deskbar/handlers/galago.pyc and deskbar/handlers/galago.pyc differ
Binary files ../deskbar-applet/deskbar/handlers/galeon.pyc and deskbar/handlers/galeon.pyc differ
diff -ruN ../deskbar-applet/deskbar/handlers/google-live.py deskbar/handlers/google-live.py
--- ../deskbar-applet/deskbar/handlers/google-live.py 2005-11-28 21:16:27.000000000 +0100
+++ deskbar/handlers/google-live.py 2006-01-07 03:44:12.000000000 +0100
@@ -62,6 +62,9 @@
def action(self, text=None):
gnomevfs.url_show(self.__url)
+
+ def get_category(self):
+ return "Google Search"
def get_hash(self, text=None):
return self.__url
Binary files ../deskbar-applet/deskbar/handlers/google-live.pyc and deskbar/handlers/google-live.pyc differ
diff -ruN ../deskbar-applet/deskbar/handlers/gtkbookmarks.py deskbar/handlers/gtkbookmarks.py
--- ../deskbar-applet/deskbar/handlers/gtkbookmarks.py 2006-01-02 01:57:54.000000000 +0100
+++ deskbar/handlers/gtkbookmarks.py 2006-01-07 03:44:12.000000000 +0100
@@ -23,6 +23,9 @@
def action(self, text=None):
gobject.spawn_async(["nautilus", self._path], flags=gobject.SPAWN_SEARCH_PATH)
+
+ def get_category(self):
+ return "Files"
def get_verb(self):
return _("Open location %s") % "<b>%(name)s</b>"
diff -ruN ../deskbar-applet/deskbar/handlers/pathprograms.py deskbar/handlers/pathprograms.py
--- ../deskbar-applet/deskbar/handlers/pathprograms.py 2006-01-02 01:57:54.000000000 +0100
+++ deskbar/handlers/pathprograms.py 2006-01-07 03:44:12.000000000 +0100
@@ -25,6 +25,9 @@
def action(self, text=None):
gobject.spawn_async(text.split(" "), flags=gobject.SPAWN_SEARCH_PATH)
+ def get_category(self):
+ return "Programs"
+
def get_verb(self):
return _("Execute %s") % "<b>%(text)s</b>"
Binary files ../deskbar-applet/deskbar/handlers/pathprograms.pyc and deskbar/handlers/pathprograms.pyc differ
diff -ruN ../deskbar-applet/deskbar/handlers/programs.py deskbar/handlers/programs.py
--- ../deskbar-applet/deskbar/handlers/programs.py 2006-01-02 01:57:54.000000000 +0100
+++ deskbar/handlers/programs.py 2006-01-07 03:44:12.000000000 +0100
@@ -58,6 +58,9 @@
else:
self._desktop.launch([])
+ def get_category(self):
+ return "Programs"
+
def get_verb(self):
#translators: First %s is the programs full name, second is the executable name
#translators: For example: Launch Text Editor (gedit)
Binary files ../deskbar-applet/deskbar/handlers/programs.pyc and deskbar/handlers/programs.pyc differ
diff -ruN ../deskbar-applet/deskbar/handlers/volumes.py deskbar/handlers/volumes.py
--- ../deskbar-applet/deskbar/handlers/volumes.py 2006-01-02 01:57:54.000000000 +0100
+++ deskbar/handlers/volumes.py 2006-01-07 03:44:12.000000000 +0100
@@ -28,6 +28,9 @@
def action(self, text=None):
gobject.spawn_async(["nautilus", self.__drive.get_activation_uri()], flags=gobject.SPAWN_SEARCH_PATH)
+
+ def get_category(self):
+ return "Files"
def get_verb(self):
activation = self.__drive.get_activation_uri()
Binary files ../deskbar-applet/deskbar/handlers/volumes.pyc and deskbar/handlers/volumes.pyc differ
diff -ruN ../deskbar-applet/deskbar/handlers/web_address.py deskbar/handlers/web_address.py
--- ../deskbar-applet/deskbar/handlers/web_address.py 2006-01-02 01:57:54.000000000 +0100
+++ deskbar/handlers/web_address.py 2006-01-07 03:44:12.000000000 +0100
@@ -28,6 +28,9 @@
gnomevfs.url_show(self._url)
else:
gobject.spawn_async(["nautilus", self._url], flags=gobject.SPAWN_SEARCH_PATH)
+
+ def get_category(self):
+ return "Actions"
def get_verb(self):
if not self._has_method:
Binary files ../deskbar-applet/deskbar/handlers/web_address.pyc and deskbar/handlers/web_address.pyc differ
diff -ruN ../deskbar-applet/deskbar/handlers_browsers.py deskbar/handlers_browsers.py
--- ../deskbar-applet/deskbar/handlers_browsers.py 2006-01-02 01:57:53.000000000 +0100
+++ deskbar/handlers_browsers.py 2006-01-07 03:46:06.000000000 +0100
@@ -24,6 +24,9 @@
def action(self, text=None):
gnomevfs.url_show(self._url)
+ def get_category(self):
+ return "Web Browser"
+
def get_verb(self):
if self._is_history:
return _("Open History Item %s") % "<b>%(name)s</b>"
diff -ruN ../deskbar-applet/deskbar/pearl.py deskbar/pearl.py
--- ../deskbar-applet/deskbar/pearl.py 1970-01-01 01:00:00.000000000 +0100
+++ deskbar/pearl.py 2006-01-07 03:46:06.000000000 +0100
@@ -0,0 +1,584 @@
+#
+# Known issues/ Ideas
+#
+# - (EASY) Expanding should be possible with enter/space as well
+#
+# - (?) Multiscreen logic.
+#
+# - (HARD) Detach the search window to "store" the search
+#
+# - (MEDIUM) Drag hits onto desktop/nautilus
+#
+# - (?) The entry loose focus sometimes when the CuemiacWindow appears,
+# really annoying!
+#
+# - (MEDIUM) Store expandedness state of categories
+#
+# - (MEDIUM) User defined (non-static) categories *WITHOUT PERFOMANCE HIT*
+#
+# - (?) Optimize
+
+from os.path import *
+
+import cgi
+import sys
+
+import gtk, gobject
+import gnome
+import gnome.ui, gnomeapplet
+import pango
+
+from categories import CATEGORIES
+
+from gettext import gettext as _
+
+class Nest :
+ """
+ A class used to handle nested results in the CuemiacModel
+ """
+ def __init__(self, category_name, parent):
+ self.__nest_msg = category_name
+ self.__parent = parent # The CuemiacCategory to which this nest belongs
+
+ def get_name (self, text=None):
+ return {"count" : self.__parent.get_count () - self.__parent.get_threshold ()}
+
+ def get_verb (self):
+ return self.__nest_msg
+
+ def get_count (self):
+ return self.__parent.get_count () - self.__parent.get_threshold ()
+
+class CuemiacCategory :
+
+ def __init__ (self, name, parent, threshold=5):
+ self.__category_row_ref = None
+ self.__nest_row_ref = None
+ self.__parent = parent
+
+ self.__name = name
+ self.__threshold = threshold
+ self.__count = 0
+
+ def get_category_row_path (self):
+ return self.__category_row_ref.get_path ()
+
+ def get_nest_row_path (self):
+ return self.__nest_row_ref.get_path ()
+
+ def set_category_iter (self, iter):
+ self.__category_row_ref = gtk.TreeRowReference (self.__parent, self.__parent.get_path(iter))
+
+ def get_category_iter (self):
+ """
+ Returns a gtk.TreeIter pointing at the category
+ """
+ return self.__parent.get_iter (self.__category_row_ref.get_path())
+
+ def set_nest_iter (self, iter):
+ self.__nest_row_ref = gtk.TreeRowReference (self.__parent, self.__parent.get_path(iter))
+
+ def get_nest_iter (self):
+ """
+ Returns a gtk.TreeIter pointing at the nested row
+ """
+ return self.__parent.get_iter (self.__nest_row_ref.get_path())
+
+ def get_name (self):
+ return self.__name
+
+ def inc_count (self):
+ self.__count = self.__count + 1
+
+ def get_count (self):
+ return self.__count
+
+ def get_threshold (self):
+ return self.__threshold
+
+class CuemiacModel (gtk.TreeStore):
+
+ # Column name
+ MATCHES = 0
+
+ def __init__ (self):
+ """
+ """
+ gtk.TreeStore.__init__ (self,
+ gobject.TYPE_PYOBJECT) # Match object
+ self.__categories = {}
+
+ def append (self, match):
+ """
+ Automagically append a match or list of matches
+ to correct category(s), or create a new one(s) if needed.
+ """
+ if type (match) == list:
+ for hit in match:
+ self.__append (hit)
+ else:
+ self.__append (match)
+
+ def __append (self, match):
+ if self.__categories.has_key (match.get_category()):
+ self.__append_to_category (match)
+ else:
+ self.__create_category_with_match (match)
+
+
+ def __create_category_with_match (self, match):
+ """
+ Assumes that the category for the match does not exist.
+ """
+ #FIXME: Check validity of category name and use proper i18n
+ # Set up a new category
+ cat = CuemiacCategory (match.get_category(), self)
+ iter = gtk.TreeStore.append (self, None, [cat])
+ cat.set_category_iter (iter)
+ self.__categories [match.get_category()] = cat
+
+ # Append the match to the category
+ gtk.TreeStore.append (self, iter, [match])
+ cat.inc_count ()
+
+
+ def __append_to_category (self, match):
+
+ cat = self.__categories [match.get_category ()]
+ row_iter = None
+ if cat.get_count() < cat.get_threshold() :
+ cat.inc_count ()
+ gtk.TreeStore.append (self, cat.get_category_iter(), [match])
+
+ elif cat.get_count() == cat.get_threshold():
+ nest = Nest (CATEGORIES[match.get_category ()]["nest"], cat)
+ nest_iter = gtk.TreeStore.append (self, cat.get_category_iter(), [nest])
+ cat.set_nest_iter (nest_iter)
+
+ cat.inc_count ()
+ gtk.TreeStore.append (self, nest_iter, [match])
+ else:
+ cat.inc_count ()
+ gtk.TreeStore.append (self, cat.get_nest_iter(), [match])
+ # Update the nested count in the nest row:
+ self.row_changed (cat.get_nest_row_path(), cat.get_nest_iter())
+
+ # Update the row count in the view:
+ self.row_changed (cat.get_category_row_path(), cat.get_category_iter())
+
+ def clear (self):
+ """
+ Clears this model of data.
+ """
+ gtk.TreeStore.clear (self)
+ self.__categories = {}
+
+class CellRendererCuemiacCategory (gtk.CellRendererText):
+
+ __gproperties__ = {
+ 'category-header' : (gobject.TYPE_STRING, 'markup for category title string',
+ 'markup for category title string, None if this is not a category header',
+ None, gobject.PARAM_READWRITE),
+
+ 'match-count' : (gobject.TYPE_INT, 'number of hits in the category',
+ 'the number of hits for the CuemiacCategory to be rendered',
+ 0,1000,0, gobject.PARAM_READWRITE)
+ }
+
+ def __init__ (self):
+ gtk.CellRendererText.__init__ (self)
+ self.__category_header = None
+ self.__match_count = 0
+
+ def do_render (self, window, widget, background_area, cell_area, expose_area, flags):
+ if not self.get_property ("category-header"):
+ gtk.CellRendererText.do_render (self, window, widget, background_area, cell_area, expose_area, flags)
+ else:
+ self.render_category (window, widget, background_area, cell_area, expose_area, flags)
+
+ def render_category (self, window, widget, background_area, cell_area, expose_area, flag):
+ """
+ Renders the category title from the "markup" property and displays a rigth aligned
+ hit count (read from the "match-count" property).
+ """
+ ctx = window.cairo_create ()
+ font_desc = pango.FontDescription ("sans bold 8") #FIXME: Use gtk theme
+
+ # Set up a pango.Layout for the category title
+ cat_layout = ctx.create_layout ()
+ cat_layout.set_text (self.get_property("category-header"))
+ cat_layout.set_font_description (font_desc)
+
+ # Set up a pango.Layout for the hit count
+ count_layout = ctx.create_layout ()
+ count_layout.set_text ("(" + str(self.get_property("match-count")) + ")")
+ count_layout.set_font_description (font_desc)
+
+ # Position and draw the layouts
+ ctx.move_to (18, background_area.y + 6)
+ ctx.show_layout (cat_layout)
+ w, h = count_layout.get_pixel_size()
+ ctx.move_to (background_area.width - w + 10, background_area.y + 6)
+ ctx.show_layout (count_layout)
+
+ ctx.set_source_rgb (1,1,1)
+ ctx.move_to (0, background_area.y + 1)
+ ctx.line_to (background_area.width + 100, background_area.y + 1)
+ ctx.stroke ()
+
+ def do_get_property(self, property):
+ if property.name == 'category-header':
+ return self.__category_header
+ elif property.name == 'match-count':
+ return self.__match_count
+ else:
+ raise AttributeError, 'unknown property %s' % property.name
+
+ def do_set_property(self, property, value):
+ if property.name == 'category-header':
+ self.__category_header = value
+ elif property.name == 'match-count':
+ self.__match_count = value
+ else:
+ raise AttributeError, 'unknown property %s' % property.name
+
+
+class CuemiacTreeView (gtk.TreeView):
+ """
+ Shows a DeskbarCategoryModel. Used internally in the CuemiacWidget.
+ """
+
+ __gsignals__ = {
+ "match-selected" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [gobject.TYPE_PYOBJECT]),
+ }
+
+ def __init__ (self, model):
+ gtk.TreeView.__init__ (self, model)
+
+ icon = gtk.CellRendererPixbuf ()
+ hit_title = CellRendererCuemiacCategory ()
+ hit_title.set_property ("ellipsize", pango.ELLIPSIZE_END)
+ hit_title.set_property ("width-chars", 50) #FIXME: Pick width according to screen size
+ hits = gtk.TreeViewColumn ("Hits")
+ hits.pack_start (icon)
+ hits.pack_start (hit_title)
+ hits.set_cell_data_func(hit_title, self.__get_match_title_for_cell)
+ hits.set_cell_data_func(icon, self.__get_match_icon_for_cell)
+ self.append_column (hits)
+
+ self.connect ("cursor-changed", self.__on_cursor_changed)
+ self.set_property ("headers-visible", False)
+ self.set_property ("hover-selection", True)
+ self.set_reorderable(True)
+ self.connect ("button-press-event", self.__on_click)
+
+ def __on_cursor_changed (self, view):
+ model, iter = self.get_selection().get_selected()
+
+ def __get_match_icon_for_cell (self, column, cell, model, iter, data=None):
+
+ match = model[iter][model.MATCHES]
+
+ if match.__class__ == CuemiacCategory:
+ cell.set_property ("pixbuf", None)
+ cell.set_property ("cell-background", "gray")
+
+ else:
+ cell.set_property ("cell-background", "white")
+ if match.__class__ == Nest:
+ cell.set_property ("pixbuf", None)
+ else:
+ cell.set_property ("pixbuf", match.get_icon())
+
+
+ def __get_match_title_for_cell (self, column, cell, model, iter, data=None):
+
+ match = model[iter][model.MATCHES]
+
+ if match.__class__ == CuemiacCategory:
+ # Look up i18n category name
+ cell.set_property ("cell-background", "gray")
+ #cell.set_property ("height", 20)
+ cell.set_property ("category-header", match.get_name())
+ cell.set_property ("match-count", match.get_count ())
+ return
+ else:
+ cell.set_property ("category-header", None)
+ cell.set_property ("height", -1)
+ cell.set_property ("cell-background", "white")
+
+ t = entry.get_text().strip () # FIXME: This will have to be changed in a proper implementation
+ # Pass unescaped query to the matches
+ verbs = {"text" : t}
+ verbs.update(match.get_name(t))
+ # Escape the query now for display
+ verbs["text"] = cgi.escape(verbs["text"])
+
+ cell.set_property ("markup", match.get_verb () % verbs)
+
+
+ def clear (self):
+ self.model.clear ()
+
+ def __on_click (self, widget, event):
+
+ model, iter = self.get_selection().get_selected()
+ match = model[iter][model.MATCHES]
+ self.emit ("match-selected", match)
+
+class CuemiacWindow (gtk.Window):
+ """
+ Borderless window aligning itself to a given widget
+ """
+ def __init__(self, widgetToAlignWith, alignment):
+ """
+ alignment should be one of
+ gnomeapplet.ORIENT_{DOWN,UP,LEFT,RIGHT}
+
+ The window will be placed accordingly relative to the given widget
+ upon invoking .show().
+ """
+ gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
+ self.set_decorated(False)
+
+ self.widgetToAlignWith = widgetToAlignWith
+ self.alignment = alignment
+ self.__is_shown = False
+
+ self.scroll_win = gtk.ScrolledWindow ()
+ self.scroll_win.set_policy (gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ gtk.Window.add (self, self.scroll_win)
+
+ self.screen_height = self.get_screen().get_height ()
+ self.max_window_height = int (0.6 * self.screen_height)
+
+ def add (self, child):
+ # Register a callback to respond to resizing of the child
+ self.scroll_win.add_with_viewport (child)
+ child.connect ("size-request", self.adjust_size)
+
+ def adjust_size (self, child, event):
+ # FIXME: SHould we handle width intelligently also?
+ w, h = child.size_request ()
+ h = h + 4 # To ensure we don't always show scrollbars
+ h = min (h, self.max_window_height)
+ self.resize (w, h)
+
+ def show (self):
+ """
+ Calculates the position and shows the window
+ """
+ # Get our own dimensions & position
+ self.realize()
+ gtk.gdk.flush()
+ window_width = (self.window.get_geometry())[2]
+ window_height = (self.window.get_geometry())[3]
+
+ # Skip the taskbar, and the pager, stick and stay on top
+ self.stick()
+ self.set_keep_above(True)
+ self.set_skip_pager_hint(True)
+ self.set_skip_taskbar_hint(True)
+ self.set_type_hint (gtk.gdk.WINDOW_TYPE_HINT_DOCK)
+
+ # Get the dimensions/position of the widgetToAlignWith
+ self.widgetToAlignWith.realize()
+ (x, y) = self.widgetToAlignWith.window.get_origin()
+
+ (w, h) = self.get_size()
+ (w, h) = self.size_request()
+
+ target_w = self.widgetToAlignWith.allocation.width
+ target_h = self.widgetToAlignWith.allocation.height
+
+ screen = self.get_screen()
+
+ found_monitor = False
+ n = screen.get_n_monitors()
+ for i in range(0, n):
+ monitor = screen.get_monitor_geometry(i)
+ if (x >= monitor.x and x <= monitor.x + monitor.width and \
+ y >= monitor.y and y <= monitor.y + monitor.height):
+ found_monitor = True
+ break
+
+ if not found_monitor:
+ monitor = gtk.gdk.Rectangle(0, 0, screen.get_width(), screen.get_width())
+
+ self.alignment
+ if self.alignment == gnomeapplet.ORIENT_RIGHT:
+ x += target_w
+
+ if ((y + h) > monitor.y + monitor.height):
+ y -= (y + h) - (monitor.y + monitor.height)
+
+ if ((y + h) > (monitor.height / 2)):
+ gravity = gtk.gdk.GRAVITY_SOUTH_WEST
+ else:
+ gravity = gtk.gdk.GRAVITY_NORTH_WEST
+ elif self.alignment == gnomeapplet.ORIENT_LEFT:
+ x -= w
+
+ if ((y + h) > monitor.y + monitor.height):
+ y -= (y + h) - (monitor.y + monitor.height)
+
+ if ((y + h) > (monitor.height / 2)):
+ gravity = gtk.gdk.GRAVITY_SOUTH_EAST
+ else:
+ gravity = gtk.gdk.GRAVITY_NORTH_EAST
+ elif self.alignment == gnomeapplet.ORIENT_DOWN:
+ y += target_h
+
+ if ((x + w) > monitor.x + monitor.width):
+ x -= (x + w) - (monitor.x + monitor.width)
+
+ gravity = gtk.gdk.GRAVITY_NORTH_WEST
+ elif self.alignment == gnomeapplet.ORIENT_UP:
+ y -= h
+
+ if ((x + w) > monitor.x + monitor.width):
+ x -= (x + w) - (monitor.x + monitor.width)
+
+ gravity = gtk.gdk.GRAVITY_SOUTH_WEST
+
+ # -"Coordinates locked in captain."
+ # -"Engage."
+ self.move(x, y)
+ #print "Move win to "+x+","+y
+ self.set_gravity(gravity)
+ gtk.Window.show (self)
+ self.__is_shown = True
+
+ def show_all (self):
+ self.show ()
+ gtk.Window.show_all (self)
+
+ def hide (self):
+ self.__is_shown = False
+ gtk.Window.hide (self)
+
+ def is_shown (self):
+ return self.__is_shown
+
+# --------------------BEGIN CUT-N-PASTE FROM DESKBAR-APPLET ---------------
+import gtk
+gtk.threads_init()
+import gnome.ui, gnomeapplet
+
+import getopt, sys
+from os.path import *
+
+# Allow to use uninstalled
+def _check(path):
+ return exists(path) and isdir(path) and isfile(path+"/AUTHORS")
+
+name = join(dirname(__file__), "..")
+if _check(name):
+ print 'Running uninstalled deskbar, modifying PYTHONPATH'
+ sys.path.insert(0, abspath(name))
+else:
+ print "Running installed deskbar, using normal PYTHONPATH"
+
+# Now the path is set, import our applet
+import deskbar, deskbar.applet, deskbar.defs
+
+import gettext, locale
+gettext.bindtextdomain('deskbar-applet', abspath(join(deskbar.defs.DATA_DIR, "locale")))
+gettext.textdomain('deskbar-applet')
+
+locale.bindtextdomain('deskbar-applet', abspath(join(deskbar.defs.DATA_DIR, "locale")))
+locale.textdomain('deskbar-applet')
+# --------------------END CUT-N-PASTE FROM DESKBAR-APPLET ---------------
+
+#
+# Load modules and set up async handling of matches
+#
+modules = []
+def on_module_loaded (loader, ctx):
+ loader.initialize_module (ctx)
+ modules.append (ctx)
+ if ctx.module.is_async ():
+ ctx.module.connect ("query-ready", lambda sender, match: cmodel.append(match))
+
+from module_list import ModuleLoader, ModuleList
+mloader = ModuleLoader (deskbar.MODULES_DIRS)
+mlist = ModuleList ()
+mloader.connect ("module-loaded", on_module_loaded)
+
+mloader.load_all()
+
+#
+# Callback when somehting is typed into the entry
+#
+def on_entry_changed (entry):
+ # FIXME: We should store the expandedness state of the categories somehow
+ cmodel.clear()
+ text = entry.get_text().strip()
+
+ if text == "":
+ cwindow.hide ()
+ return
+
+ for ctx in modules:
+ if not ctx.enabled:
+ continue
+
+ if ctx.module.is_async ():
+ ctx.module.query_async (text, 10)
+ else:
+ cmodel.append (ctx.module.query (text, 10))
+
+ if not cwindow.is_shown ():
+ cwindow.show_all ()
+#
+# Callback to monitor special keys (like Esc)
+#
+def on_entry_key_press (entry, event):
+ if event.keyval == gtk.keysyms.Escape:
+ # bind Escape to clear the GtkEntry
+ if not entry.get_text().strip() == "":
+ # If we cleared some text, tell async handlers to stop.
+ for ctx in modules:
+ if ctx.module.is_async ():
+ ctx.module.stop_query ()
+ entry.set_text("")
+
+#
+# Setup up the UI and create the Cuemiac
+#
+vbox = gtk.VBox ()
+
+entry = gtk.Entry()
+entry.connect ("changed", on_entry_changed)
+entry.connect ("key-press-event", on_entry_key_press)
+
+cmodel = CuemiacModel ()
+cview = CuemiacTreeView (cmodel)
+cwindow = CuemiacWindow (entry, gnomeapplet.ORIENT_DOWN)
+cwindow.add (cview)
+#cwindow.connect ("focus-out-event", lambda widget,event: cwindow.hide())
+
+#
+# Callback to trigger the action associated to a match
+#
+def do_action(sender, match):
+ if hasattr(match, 'action'):
+ match.action(entry.get_text())
+
+
+#
+# Setup final GUI stuff
+#
+cview.connect ("match-selected", do_action)
+
+vbox.pack_start (entry, False)
+
+window = gtk.Window()
+window.connect ("destroy", gtk.main_quit)
+window.add (vbox)
+window.show_all()
+
+
+cview.show_all()
+
+gtk.main ()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]