diff --git a/python/deskbar-handler/tracker-handler.py b/python/deskbar-handler/tracker-handler.py
index 72fb72f..13a56d2 100644
--- a/python/deskbar-handler/tracker-handler.py
+++ b/python/deskbar-handler/tracker-handler.py
@@ -9,168 +9,157 @@ import gnome
import gobject
from gettext import gettext as _
-import re, cgi
+import re, cgi, sys
import os.path
-import dbus
-import deskbar
+import deskbar, deskbar.Utils, deskbar.gnomedesktop
from deskbar.Handler import SignallingHandler
from deskbar.Match import Match
#Edit this var for change the numer of output results
-MAX_RESULTS = 10
+MAX_RESULTS = 20
-def _check_requirements ():
- try:
- import dbus
- try :
- if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
- import dbus.glib
-
- # Check that Tracker can be started via dbus activation, we will have trouble if it's not
- bus = dbus.SessionBus()
- proxy_obj = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
- dbus_iface = dbus.Interface(proxy_obj, 'org.freedesktop.DBus')
- activatables = dbus_iface.ListActivatableNames()
- if not "org.freedesktop.Tracker" in activatables:
- return (deskbar.Handler.HANDLER_IS_NOT_APPLICABLE, "Tracker is not activatable via dbus", None)
-
- except:
- return (deskbar.Handler.HANDLER_IS_NOT_APPLICABLE, "Python dbus.glib bindings not found.", None)
- return (deskbar.Handler.HANDLER_IS_HAPPY, None, None)
- except:
- return (deskbar.Handler.HANDLER_IS_NOT_APPLICABLE, "Python dbus bindings not found.", None)
+# XXX: HANDLERS defined at end of file
-HANDLERS = {
- "TrackerSearchHandler" : {
- "name": "Search for files using Tracker Search Tool",
- "description": _("Search all of your documents (using Tracker), as you type"),
- "requirements" : _check_requirements,
+# For now description param it's not used
+TYPES = {
+ 'Applications': {
+ 'description': (_('Launch %s (%s)') % ('%(name)s', '%(app_name)s')),
+ 'category': 'applications',
},
- "TrackerLiveSearchHandler" : {
- "name": "Search for files using Tracker(live result)",
- "description": _("Search all of your documents (using Tracker live), as you type"),
- "requirements" : _check_requirements,
- "categories" : {
- "develop" : {
- "name": _("Development Files"),
- },
- "music" : {
- "name": _("Music"),
- },
- "images" : {
- "name": _("Images"),
- },
- "videos" : {
- "name": _("Videos"),
- },
- },
+
+ 'GaimConversations': {
+ 'description': (_('See %s conversation\n%s %s\nfrom %s') % ('%(proto)s', '%(channel)s', '%(conv_to)s', '%(time)s')),
+ 'category': 'conversations',
},
-}
-#For now description param it's not used
-TYPES = {
- "Conversations" : {
- "description": (_("See conversations %s") % "%(publisher)s" ) + "\n%(base)s",
- "category": "conversations",
- },
- "Email" : {
- "description": (_("Email from %s") % "%(publisher)s" ) + "\n%(title)s",
- "category": "emails",
- "action" : "evolution %(uri)s",
- "icon" : "stock_mail",
- },
- "Music" : {
- "description": _("Listen to music %s\nin %s") % ("%(base)s", "%(dir)s"),
- "category": "music",
- },
- "Documents" : {
- "description": _("See document %s\nin %s") % ("%(base)s", "%(dir)s"),
- "category": "documents",
- },
- "Development Files" : {
- "description": _("Open file %s\nin %s") % ("%(base)s", "%(dir)s"),
- "category": "develop",
- },
- "Images" : {
- "description": _("View image %s\nin %s") % ("%(base)s", "%(dir)s"),
- "category": "images",
- },
- "Videos" : {
- "description": _("Watch video %s\nin %s") % ("%(base)s", "%(dir)s"),
- "category": "videos",
- },
- "Other Files" : {
- "description": _("Open file %s\nin %s") % ("%(base)s", "%(dir)s"),
- "category": "files",
- },
- "Extra" : {
- "description": _("See more result with t-s-t"),
- },
+ 'Email': {
+ 'description': (_('Email from %s') % '%(publisher)s' ) + '\n%(title)s',
+ 'category': 'emails',
+ 'action': 'evolution %(uri)s',
+ 'icon': 'stock_mail',
+ },
+
+ 'Music': {
+ 'description': _('Listen to music %s\nin %s') % ('%(base)s', '%(dir)s'),
+ 'category': 'music',
+ },
+
+ 'Documents': {
+ 'description': _('See document %s\nin %s') % ('%(base)s', '%(dir)s'),
+ 'category': 'documents',
+ },
+
+ 'Development': {
+ 'description': _('Open file %s\nin %s') % ('%(base)s', '%(dir)s'),
+ 'category': 'develop',
+ },
+
+ 'Images': {
+ 'description': _('View image %s\nin %s') % ('%(base)s', '%(dir)s'),
+ 'category': 'images',
+ },
+
+ 'Videos': {
+ 'description': _('Watch video %s\nin %s') % ('%(base)s', '%(dir)s'),
+ 'category': 'videos',
+ },
+
+ 'Other Files': {
+ 'description': _('Open file %s\nin %s') % ('%(base)s', '%(dir)s'),
+ 'category': 'files',
+ },
+
+ 'Folders': {
+ 'description': _('Open folder %s\n%s') % ('%(name)s', '%(dir)s/%(name)s'),
+ 'category': 'folders',
+ },
+
+ 'Extra': {
+ 'description': _('See more result with Tracker Search Tool'),
+ },
}
-#STATIC HANDLER---------------------------------
+
class TrackerFileMatch (Match):
+
def __init__(self, backend, **args):
deskbar.Match.Match.__init__(self, backend, **args)
-
+
def action(self, text=None):
- gobject.spawn_async(["tracker-search-tool", self.name], flags=gobject.SPAWN_SEARCH_PATH)
-
+ gobject.spawn_async(['tracker-search-tool', self.name], flags=gobject.SPAWN_SEARCH_PATH)
+
def get_verb(self):
- return _("Search "+self.name+" with Tracker Search Tool")
-
+ return _('Search %s with Tracker Search Tool') % (''+self.name+'')
+
def get_category (self):
- return "actions"
+ return 'actions'
+
+
+
class TrackerSearchHandler(deskbar.Handler.Handler):
+
def __init__(self):
- deskbar.Handler.Handler.__init__(self, ("system-search", "tracker"))
-
+ deskbar.Handler.Handler.__init__(self, ('system-search', 'tracker'))
+
def query(self, query):
return [TrackerFileMatch(self, name=query)]
-#LIVE HANDLER---------------------------------
+ @staticmethod
+ def requirements ():
+ if deskbar.Utils.is_program_in_path ('tracker-search-tool'):
+ return (deskbar.Handler.HANDLER_IS_HAPPY, None, None)
+ return (deskbar.Handler.HANDLER_IS_NOT_APPLICABLE, 'tracker-search-tool not found', None)
+
+
+
class TrackerMoreMatch (Match):
- def __init__(self, backend, qstring, category="files", **args):
+
+ def __init__(self, backend, qstring, category='files', **args):
Match.__init__(self, backend, **args)
- self._icon = deskbar.Utils.load_icon("tracker")
+ self._icon = deskbar.Utils.load_icon('tracker')
self.qstring = qstring
self.category = category
def get_verb(self):
- return TYPES["Extra"]["description"]
+ return TYPES['Extra']['description']
def get_category (self):
try:
- return TYPES[self.category]["category"]
+ return TYPES[self.category]['category']
except:
- pass
+ return "files"
def action(self, text=None):
- gobject.spawn_async(["tracker-search-tool", self.qstring], flags=gobject.SPAWN_SEARCH_PATH)
-
+ gobject.spawn_async(['tracker-search-tool', self.qstring], flags=gobject.SPAWN_SEARCH_PATH)
+
+
+
+
class TrackerLiveFileMatch (Match):
+
def __init__(self, handler,result=None, **args):
- Match.__init__ (self, handler,name=result["name"], **args)
+ Match.__init__ (self, handler,name=result['name'], **args)
self.result = result
self.fullpath = result['uri']
self.init_names()
-
- self.result["base"] = self.base
- self.result["dir"] = self.dir
-
+
+ self.result['base'] = self.base
+ self.result['dir'] = self.dir
+
# Set the match icon
try:
- self._icon = deskbar.Utils.load_icon(TYPES[result['type']]["icon"])
+ self._icon = deskbar.Utils.load_icon(TYPES[result['type']]['icon'])
except:
- self._icon = deskbar.Utils.load_icon_for_file(result['uri'])
-
- print result
+ if self.result.has_key ('icon'):
+ self._icon = deskbar.Utils.load_icon_for_desktop_icon (result ['icon'])
+ else:
+ self._icon = deskbar.Utils.load_icon_for_file(result['uri'])
def get_name(self, text=None):
try:
@@ -180,21 +169,25 @@ class TrackerLiveFileMatch (Match):
def get_verb(self):
try:
- return TYPES[self.result["type"]]["description"]
+ return TYPES[self.result['type']]['description']
except:
- return _("Open file %s\nin %s") % ("%(base)s", "%(dir)s")
-
+ return _('Open file %s\nin %s') % ('%(base)s', '%(dir)s')
+
def get_hash(self, text=None):
try:
+ if self.result ['type'] == 'Applications':
+ # return a name that matches the one returned by the Program handler of deskbar
+ return 'generic_' + self.result ['app_basename']
return self.result['uri']
except:
pass
def action(self, text=None):
- if TYPES[self.result["type"]].has_key("action"):
- cmd = TYPES[self.result["type"]]["action"]
+ if TYPES[self.result['type']].has_key('action'):
+ cmd = TYPES[self.result['type']]['action']
cmd = map(lambda arg : arg % self.result, cmd.split()) # we need this to handle spaces correctly
- print "Opening Tracker hit with command:", cmd
+
+ print 'Opening Tracker hit with command:', cmd
try:
# deskbar >= 2.17
deskbar.Utils.spawn_async(cmd)
@@ -202,84 +195,237 @@ class TrackerLiveFileMatch (Match):
# deskbar <= 2.16
gobject.spawn_async(args, flags=gobject.SPAWN_SEARCH_PATH)
else:
- try:
- # deskbar >= 2.17
- deskbar.Utils.url_show ("file://"+cgi.escape(self.result['uri']))
- except AttributeError:
- gnome.url_show("file://"+cgi.escape(self.result['uri']))
- print "Opening Tracker hit:", self.result['uri']
-
+ if self.result.has_key ('desktop'):
+ self.result['desktop'].launch([])
+ else:
+ try:
+ # deskbar >= 2.17
+ deskbar.Utils.url_show ('file://'+cgi.escape(self.result['uri']))
+ except AttributeError:
+ gnome.url_show('file://'+cgi.escape(self.result['uri']))
+ print 'Opening Tracker hit:', self.result['uri']
+
def get_category (self):
try:
- return TYPES[self.result["type"]]["category"]
+ return TYPES[self.result['type']]['category']
except:
- return "files"
+ return 'files'
def init_names (self):
#print "Parsing «%r»" % self.fullpath
dirname, filename = os.path.split(self.fullpath)
if filename == '': #We had a trailing slash
dirname, filename = os.path.split(dirname)
-
+
#Reverse-tilde-expansion
home = os.path.normpath(os.path.expanduser('~'))
regexp = re.compile(r'^%s(/|$)' % re.escape(home))
dirname = re.sub(regexp, r'~\1', dirname)
-
+
self.dir = dirname
self.base = filename
+
+
class TrackerLiveSearchHandler(SignallingHandler):
+
def __init__(self):
- SignallingHandler.__init__(self, "tracker")
- bus = dbus.SessionBus()
- self.tracker = bus.get_object('org.freedesktop.Tracker','/org/freedesktop/tracker')
- self.search_iface = dbus.Interface(self.tracker, 'org.freedesktop.Tracker.Search')
- self.keywords_iface = dbus.Interface(self.tracker, 'org.freedesktop.Tracker.Keywords')
- self.files_iface = dbus.Interface(self.tracker, 'org.freedesktop.Tracker.Files')
+ SignallingHandler.__init__(self, 'tracker')
+ # initing on search request, see self.query
+ self.tracker = self.search_iface = self.keywords_iface = self.files_iface = None
self.set_delay (500)
-
+ self.conv_re = re.compile (r'^.*?/logs/([^/]+)/([^/]+)/([^/]+)/(.+?)\.(:?txt|html)$') # all, proto, account, to-whom, time
+
+ def handle_email_hits (self, info, output):
+ output['title'] = cgi.escape(info[3])
+ output['publisher'] = cgi.escape(info[4])
+
+ def handle_conversation_hits (self, info, output):
+ output ['uri'] = info [0]
+ m = self.conv_re.match (output['uri'])
+ output['channel']=_('with')
+ output['proto']=output['conv_from']=output['conv_to']=output['time']='' # XXX, never happened during tests
+ if m:
+ output['proto'] = m.group (1)
+ output['conv_from'] = m.group (2)
+ output['conv_to'] = m.group (3)
+ output['time'] = m.group (4)
+ if output['conv_to'].endswith ('.chat'):
+ output['channel'] = _('in channel')
+ output['conv_to'] = output['conv_to'].replace ('.chat','')
+ if output['proto'] == 'irc':
+ nick_server = output['conv_from'].split ('@')
+ if len (nick_server) > 1:
+ output['conv_to'] = '%s on %s' % (output['conv_to'], nick_server[1])
+ # escape those entities, purple uses this to escape / on jabber channel/user conversations
+ output['uri'] = output['uri'].replace ('%', '%25')
+ # escape irc channel prefixes, else the path name parsing of stops at '#' (this holds also for the icon search)
+ output['uri'] = output['uri'].replace ('#', '%23')
+
+ def handle_application_hits (self, info, output):
+ # print info
+ # dbus.Array(
+ # [
+ # dbus.String(u'/usr/share/applications/gksu.desktop'), # TrackerUri 0
+ # dbus.String(u'Applications'), # TrackerType 1
+ # dbus.String(u'Application'), # DesktopType 2
+ # dbus.String(u'Root Terminal'), # DesktopName 3
+ # dbus.String(u'gksu /usr/bin/x-terminal-emulator'), # DesktopExec 4
+ # dbus.String(u'gksu-root-terminal') # DesktopIcon 5
+ # ],
+ # signature=dbus.Signature('s'))
+ # Strip %U or whatever arguments in Exec field
+ output['app_name'] = re.sub(r'%\w+', '', info [4]).strip ()
+ output['app_basename'] = cgi.escape (os.path.basename (output['app_name']))
+ output['app_name'] = cgi.escape (output['app_name'])
+ if output['app_basename'] == '': # strange // in app_name, e.g. nautilus burn:///
+ output['app_basename'] = output['app_name']
+ output['name'] = cgi.escape (info [3])
+ output['icon'] = cgi.escape (info [5])
+
+ desktop = parse_desktop_file (output['uri'])
+ if not desktop:
+ print >> sys.stderr, '*** Could not read .desktop file: %s' % info[0]
+ else:
+ output['desktop'] = desktop
+
def recieve_hits (self, qstring, hits, max):
matches = []
- self.results = {}
-
+ results = {}
+
for info in hits:
- output = {}
+ output = {}
+
output['name'] = os.path.basename(info[0])
output['uri'] = str(cgi.escape(info[0]))
output['type'] = info[1]
- if TYPES.has_key(output['type']) == 0:
- output['type'] = "Other Files"
- try:
- self.results[output['type']].append(output)
- except:
- self.results[output['type']] = [output]
-
- if output["type"] == "Email":
- output["title"] = cgi.escape(info[3])
- output["publisher"] = cgi.escape(info[4])
-
- for key in self.results.keys():
- for res in self.results[key][0:MAX_RESULTS]:
- matches.append(TrackerLiveFileMatch(self,res))
- #if len(self.results[key]) > MAX_RESULTS:
- # matches.append( TrackerMoreMatch(self,qstring,key) )
+
+ if not TYPES.has_key(output['type']):
+ output['type'] = 'Other Files'
+
+ if output['type'] == 'Email':
+ self.handle_email_hits (info, output)
+
+ elif output['type'] in ('GaimConversations', 'Conversations'):
+ self.handle_conversation_hits (info, output)
+
+ elif output['type'] == 'Applications':
+ self.handle_application_hits (info, output)
+
+ # applications are launched by .desktop file, if not readable: exclude
+ if output['type'] != 'Applications' or output.has_key ('desktop'):
+ try:
+ results[output['type']].append(output)
+ except:
+ results[output['type']] = [output]
+
+ for key in results.iterkeys ():
+ for res in results[key][0:MAX_RESULTS]:
+ matches.append(TrackerLiveFileMatch(self,res))
+
self.emit_query_ready(qstring, matches)
- print "Tracker response for %s, - %s hits returned, %s shown" % (qstring, len(hits), len(matches))
-
+ print 'Tracker response for %s; %d hits returned, %d shown' % (qstring, len(hits), len(matches))
+
def recieve_error (self, error):
- print "*** Tracker dbus error:", error
-
+ print >> sys.stderr, '*** Tracker dbus error:', error
+
def query (self, qstring, max):
- if qstring.count("tag:") == 0:
- self.search_iface.TextDetailed (-1, "Files", qstring, 0,10, reply_handler=lambda hits : self.recieve_hits(qstring, hits, max), error_handler=self.recieve_error)
- self.search_iface.TextDetailed (-1, "Emails", qstring, 0,10, reply_handler=lambda hits : self.recieve_hits(qstring, hits, max), error_handler=self.recieve_error)
- print "Tracker query:", qstring
+ if not self.tracker:
+ try:
+ import dbus
+ bus = dbus.SessionBus()
+ self.tracker = bus.get_object('org.freedesktop.Tracker','/org/freedesktop/tracker')
+ self.search_iface = dbus.Interface(self.tracker, 'org.freedesktop.Tracker.Search')
+ self.keywords_iface = dbus.Interface(self.tracker, 'org.freedesktop.Tracker.Keywords')
+ self.files_iface = dbus.Interface(self.tracker, 'org.freedesktop.Tracker.Files')
+ except:
+ print >> sys.stderr, 'DBus connection to tracker failed, check your settings.'
+ return
+ if qstring.count('tag:') == 0:
+ for service in ('Files', 'Emails', 'Conversations', 'Applications'):
+ self.search_iface.TextDetailed (-1, service, qstring, 0,10, reply_handler=lambda hits : self.recieve_hits(qstring, hits, max), error_handler=self.recieve_error)
+ print 'Tracker query:', qstring
else:
if self.tracker.GetVersion() == 502:
- self.search_iface.Query(-1,"Files",["File.Format"],"",qstring.replace("tag:",""),"",False,0,100, reply_handler=lambda hits : self.recieve_hits(qstring, hits, max), error_handler=self.recieve_error)
+ self.search_iface.Query(-1,'Files',['File.Format'],'',qstring.replace('tag:',''),'',False,0,100, reply_handler=lambda hits : self.recieve_hits(qstring, hits, max), error_handler=self.recieve_error)
elif self.tracker.GetVersion() == 503:
- self.search_iface.Query(-1,"Files",["File:Mime"],"",qstring.replace("tag:",""),"",False,0,100, reply_handler=lambda hits : self.recieve_hits(qstring, hits, max), error_handler=self.recieve_error)
- print "Tracker tag query:", qstring.replace("tag:","")
+ self.search_iface.Query(-1,'Files',['File:Mime'],'',qstring.replace('tag:',''),'',False,0,100, reply_handler=lambda hits : self.recieve_hits(qstring, hits, max), error_handler=self.recieve_error)
+ print 'Tracker tag query:', qstring.replace('tag:','')
+
+ @staticmethod
+ def requirements ():
+ try:
+ import dbus
+ try :
+ if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
+ import dbus.glib
+
+ # Check that Tracker can be started via dbus activation, we will have trouble if it's not
+ bus = dbus.SessionBus()
+ proxy_obj = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
+ dbus_iface = dbus.Interface(proxy_obj, 'org.freedesktop.DBus')
+ activatables = dbus_iface.ListActivatableNames()
+ if not 'org.freedesktop.Tracker' in activatables:
+ return (deskbar.Handler.HANDLER_IS_NOT_APPLICABLE, 'Tracker is not activatable via dbus', None)
+ except:
+ return (deskbar.Handler.HANDLER_IS_NOT_APPLICABLE, 'Python dbus.glib bindings not found.', None)
+ return (deskbar.Handler.HANDLER_IS_HAPPY, None, None)
+ except:
+ return (deskbar.Handler.HANDLER_IS_NOT_APPLICABLE, 'Python dbus bindings not found.', None)
+
+
+
+
+# this code is stolen from the programs handler of deskbar
+def parse_desktop_file(desktop, only_if_visible=False):
+ try:
+ desktop = deskbar.gnomedesktop.item_new_from_file(desktop, deskbar.gnomedesktop.LOAD_ONLY_IF_EXISTS)
+ except Exception, e:
+ print 'Couldn\'t read desktop file:%s:%s' % (desktop, e)
+ return None
+ if desktop == None or desktop.get_entry_type() != deskbar.gnomedesktop.TYPE_APPLICATION:
+ return None
+ if only_if_visible and desktop.get_boolean(deskbar.gnomedesktop.KEY_NO_DISPLAY):
+ return None
+ return desktop
+
+
+
+HANDLERS = {
+ 'TrackerSearchHandler': {
+ 'name': 'Search for files using Tracker Search Tool',
+ 'description': _('Search all of your documents with Tracker Search Tool'),
+ 'requirements': TrackerSearchHandler.requirements,
+ },
+
+ 'TrackerLiveSearchHandler': {
+ 'name': 'Search for files using Tracker(live result)',
+ 'description': _('Search all of your documents (using Tracker live), as you type'),
+ 'requirements': TrackerLiveSearchHandler.requirements,
+ 'categories': {
+ 'develop': {
+ 'name': _('Development Files'),
+ },
+ 'music': {
+ 'name': _('Music'),
+ },
+ 'images': {
+ 'name': _('Images'),
+ },
+ 'videos': {
+ 'name': _('Videos'),
+ },
+ 'conversations': {
+ 'name': _('Conversations'),
+ },
+ 'applications': {
+ 'name': _('Applications'),
+ },
+ 'folders': {
+ 'name': _('Folders'),
+ },
+ },
+ },
+}