Hey there.

It's already late - I succeeded at getting 2 deskbar version handlers
into one .py - the problem is, the code is rather ugly, just by
multiple inheritance the problem is not solved, one needs
Implementation classes that wrap the actual work.

I don't know if this one is better suited, it certainly gets us away
from those '2 handlers'. The other benefit from that, fixes and
updates to one handler may automagically work also for the second one
(as i had to port my recent changes from handler1 to handler2).


Cheers, Marcus
import cgi
import deskbar
import gnome
import gobject
import os.path
import re
import sys
import time
import urllib

from gettext import gettext as _

# do the version dance!
import deskbar
_get_deskbar_version = lambda x: sum(map(lambda x: (10**(2*x[0]))*int(x[1]),zip((4,3,2,1),x.split('.'))))

try:
	DESKBAR_VERSION = _get_deskbar_version (deskbar.VERSION)
except:
	import deskbar.defs
	DESKBAR_VERSION = _get_deskbar_version (deskbar.defs.VERSION)

MAX_RESULTS = 10



def dummy_escape (s):
	return s
	#return cgi.escape (s)



# 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



def time_from_purple_log (instr):
	try:
		if instr.find ('+') != -1: # new kind of log timestamp...
			return time.strftime ('%c', time.strptime (re.sub (r'\+\d{4}', '', instr), '%Y-%m-%d.%H%M%S%Z'))
		else: # ...from ancient times
			return time.strftime ('%c', time.strptime (instr, '%Y-%m-%d.%H%M%S'))
	except:
		print >> sys.stderr, '*** time parsing for purple chat log failed: %s' % sys.exc_info ()[1]
	return instr



class TSTHandlerImpl (object):
	def __init__(self):
		pass
	@staticmethod
	def has_requirements ():
		if DESKBAR_VERSION < _get_deskbar_version ('2.19'):
			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)
		else:
			return deskbar.core.Utils.is_program_in_path ('tracker-search-tool')



class TSTMatchImpl (object):
	def __init__ (self):
		pass
	def get_category (self):
		return 'actions'
	def get_hash (self, text=None):
		return 'tst-more-hits-action-'+self.name



class LiveMatchImpl (object):
	def __init__ (self):
		pass

	def init_names (self):
		#print "Parsing ..." % 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

	def wrap_get_name (self, text = None):
		return self.result

	def wrap_get_verb(self):
		try:
			return TYPES[self.result['type']]['description']
		except:
			return _('Open file %s\nin %s')	% ('<b>%(base)s</b>', '<i>%(dir)s</i>')

	def wrap_get_category (self):
		try:
			return TYPES[self.result['type']]['category']
		except:
			return 'files'

	def wrap_get_hash(self, text=None):
		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']



class LiveHandlerImpl (object):
	def __init__ (self):
		self.tracker = self.search_iface = self.keywords_iface = self.files_iface = None
		self.conv_re = re.compile (r'^.*?/logs/([^/]+)/([^/]+)/([^/]+)/(.+?)\.(:?txt|html)$') # all, proto, account, to-whom, time
		try:
			self.have_tst = deskbar.Utils.is_program_in_path ('tracker-search-tool')
		except:
			self.have_tst = deskbar.core.Utils.is_program_in_path ('tracker-search-tool')

	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 ['name'] = output ['name'].replace ('%2b', '+')
		output ['uri'] = info [0]
		uri = info[0]
		m = self.conv_re.match (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'] = urllib.unquote (m.group (2))
			output['conv_to'] = urllib.unquote (m.group (3))
			output['time'] = time_from_purple_log (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])
		output['uri'] = urllib.quote (output['uri'])
		# 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 receive_hits (self, qstring, hits, max):
		matches = []

		for info in hits:
			output = {}

			output['name'] = os.path.basename(info[0])
			output['uri'] = cgi.escape(str (info[0]))
			output['type'] = str (info[1])

			if not TYPES.has_key(output['type']):
				output['type'] = 'Files'

			if output['type'] == 'Emails':
				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'):
				if DESKBAR_VERSION < _get_deskbar_version ('2.19'):
					matches.append(TrackerLiveSearchMatch218 (self, output))
				else:
					matches.append(TrackerLiveSearchMatch220 (output))

		if len (matches):
			self.wrap_emit_query_ready(qstring, matches)
			print 'Tracker response for query "%s" (service %s); %s hits returned, %s shown' % (qstring, hits[0][1], len(hits), len(matches))

	def recieve_error (self, error):
		print >> sys.stderr, '*** Tracker dbus error:', error

	def wrap_emit_query_ready (self, qstring, matches):
		try:
			self._emit_query_ready (qstring, matches)
		except:
			self.emit_query_ready (qstring, matches)

	def wrap_query (self, qstring, max=MAX_RESULTS):
		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
		for service in [key for key in TYPES.iterkeys () if key != 'Extra']:
			self.search_iface.TextDetailed (-1, service, qstring, 0, max, \
					reply_handler = lambda hits: self.receive_hits (qstring, hits, max), \
					error_handler = self.recieve_error)
		print 'Tracker query:', qstring
		if self.have_tst:
			if DESKBAR_VERSION < _get_deskbar_version ('2.19'):
				self.wrap_emit_query_ready (qstring, [TrackerSearchToolMatch218 (self, name=qstring)])
			else:
				self.wrap_emit_query_ready (qstring, [TrackerSearchToolMatch220 (name=qstring, priority=self.get_priority ())])



TYPES = {
	'Applications': {
		'description': (_('Launch %s (%s)') % ('<b>%(name)s</b>', '%(app_name)s')),
		'category': 'actions',
		#'icon': 'stock_run',
	},

	'GaimConversations': {
		'description': (_('See %s conversation\n%s %s\nfrom %s') % ('<b>%(proto)s</b>', '%(channel)s', '<b>%(conv_to)s</b>', '<i>%(time)s</i>')),
		'category': 'conversations',
		'icon': 'stock_people',
	},

	'Emails': {
		'description': (_('Email from %s') % '<i>%(publisher)s</i>' ) + '\n<b>%(title)s</b>',
		'category': 'emails',
		'action': 'evolution %(uri)s',
		'icon': 'stock_mail',
	},

	'Music': {
		'description': _('Listen to music %s\nin %s')	% ('<b>%(base)s</b>', '<i>%(dir)s</i>'),
		'category': 'music',
		#'icon': 'audio',
	},

	'Documents': {
		'description': _('See document %s\nin %s')	% ('<b>%(base)s</b>', '<i>%(dir)s</i>'),
		'category': 'documents',
		#'icon': 'file',
	},

	'Development': {
		'description': _('Open file %s\nin %s')	% ('<b>%(base)s</b>', '<i>%(dir)s</i>'),
		'category': 'develop',
		#'icon': 'file',
	},

	'Images': {
		'description': _('View image %s\nin %s')	% ('<b>%(base)s</b>', '<i>%(dir)s</i>'),
		'category': 'images',
		'icon': 'image',
	},

	'Videos': {
		'description': _('Watch video  %s\nin %s')	% ('<b>%(base)s</b>', '<i>%(dir)s</i>'),
		'category': 'videos',
		'icon': 'video',
	},

	'Files': {
		'description': _('Open file %s\nin %s')	% ('<b>%(base)s</b>', '<i>%(dir)s</i>'),
		'category': 'files',
		#'icon': 'file',
	},

	'Folders': {
		'description': _('Open folder %s\n%s') % ('<b>%(name)s</b>', '<i>%(dir)s/%(name)s</i>'),
		'category': 'places',
		'icon': 'stock_folder',
	},

	'Extra': {
		'description': _('Search for %s with Tracker Search Tool') % ('<b>%(name)s</b>'),
	},
}



#
#
# BEGIN DESKBAR < 2.19 CLASSES
#
#
if DESKBAR_VERSION < _get_deskbar_version ('2.19'):
	import deskbar, deskbar.Utils, deskbar.gnomedesktop
	import deskbar.Handler
	import deskbar.Match



	class TrackerSearchToolMatch218 (deskbar.Match.Match, TSTMatchImpl):
		def __init__(self, backend, **args):
			deskbar.Match.Match.__init__(self, backend, **args)
			TSTMatchImpl.__init__ (self)

		def action(self, text=None):
			gobject.spawn_async(['tracker-search-tool', self.name], flags=gobject.SPAWN_SEARCH_PATH)

		def get_verb(self):
			return _('Search for %s with Tracker Search Tool') % '<b>%(name)s</b>'



	class TrackerSearchToolHandler218 (deskbar.Handler.Handler, TSTHandlerImpl):
		def __init__(self):
			deskbar.Handler.Handler.__init__(self, 'tracker')
			TSTHandlerImpl.__init__ (self)

		def query(self, query):
			return [TrackerSearchToolMatch218 (self, name=query)]



	class TrackerLiveSearchMatch218  (deskbar.Match.Match, LiveMatchImpl):
		def __init__(self, handler,result=None, **args):
			deskbar.Match.Match.__init__ (self, handler,name=result['name'], **args)
			LiveMatchImpl.__init__ (self)

			self.result = result
			self.fullpath = result['uri']
			self.init_names()

			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'])
			except:
				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 action(self, text=None):
			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
				try:
					# deskbar >= 2.17
					deskbar.Utils.spawn_async(cmd)
				except AttributeError:
					# deskbar <= 2.16
					gobject.spawn_async(args, flags=gobject.SPAWN_SEARCH_PATH)
			else:
				if self.result.has_key ('desktop'):
					self.result['desktop'].launch([])
				else:
					try: # catch errors on gnome.url_show()
						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']
					except:
						print >> sys.stderr, '*** Could not open URL %s: %s' % (self.result['uri'], sys.exc_info ()[1])

		def get_name (self, text = None):
			return self.wrap_get_name (text)

		def get_verb(self):
			return self.wrap_get_verb ()

		def get_category (self):
			return self.wrap_get_category ()

		def get_hash(self, text=None):
			return self.wrap_get_hash (text)



	class TrackerLiveSearchHandler218 (deskbar.Handler.SignallingHandler, LiveHandlerImpl):
		def __init__(self):
			deskbar.Handler.SignallingHandler.__init__(self, 'tracker')
			LiveHandlerImpl.__init__ (self)

			# initing on search request, see self.query
			self.set_delay (500)

		def query (self, qstring, max):
			self.wrap_query (qstring, max)

		@staticmethod
		def has_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)



	HANDLERS = {
		'TrackerSearchToolHandler218': {
			'name': 'Search for files using Tracker Search Tool',
			'description': _('Search all of your documents with Tracker Search Tool'),
			#'requirements': TrackerSearchToolHandler.requirements, # XXX makes deskbar 2.18.1 not load the handler!!
		},

		'TrackerLiveSearchHandler218': {
			'name': 'Search for files using Tracker',
			'description': _('Search all of your documents, <b>as you type</b>'),
			'requirements': TrackerLiveSearchHandler218.has_requirements,
			'categories': {
				'develop': {
					'name': _('Development Files'),
				},
				'music': {
					'name': _('Music'),
				},
				'images': {
					'name': _('Images'),
				},
				'videos': {
					'name': _('Videos'),
				},
				'conversations': {
					'name': _('Conversations'),
				},
				'applications': {
					'name': _('Applications'),
				},
				'places': {
					'name': _('Places'),
				},
				'actions': {
					'name': _('Actions'),
				},
			},
		},
	}



#
#
# BEGIN DESKBAR >= 2.19 CLASSES
#
#
else:
	import deskbar.core.Utils
	import deskbar.core.gnomedesktop
	import deskbar.interfaces.Module
	import deskbar.interfaces.Match
	import deskbar.interfaces.Action
	from gettext import gettext as _

	HANDLERS = ['TrackerSearchToolHandler220', 'TrackerLiveSearchHandler220']

	class TrackerSearchToolMatch220 (deskbar.interfaces.Match, TSTMatchImpl):
		def __init__(self, **kwargs):
			deskbar.interfaces.Match.__init__(self, **kwargs)
			TSTMatchImpl.__init__ (self)
			self.name = kwargs['name']
			self.add_action (TrackerSearchToolAction220 (kwargs['name']))



	class TrackerSearchToolAction220 (deskbar.interfaces.Action):
		def __init__(self, name):
			deskbar.interfaces.Action.__init__ (self, name)
			self.name = name

		def activate(self, text=None):
			gobject.spawn_async(['tracker-search-tool', self.name], \
					flags=gobject.SPAWN_SEARCH_PATH)

		def get_verb(self):
			return _('Search for %s with Tracker Search Tool') % '<b>%(name)s</b>'

		def get_hash (self):
			return 't-s-t:'+self.name



	class TrackerSearchToolHandler220 (deskbar.interfaces.Module, TSTHandlerImpl):
		INFOS = {
				'icon': deskbar.core.Utils.load_icon ('tracker'),
				'name': _('Tracker Search'),
				'description': _('Search with Tracker Search Tool'),
		}

		def __init__(self):
			deskbar.interfaces.Module.__init__(self)
			TSTHandlerImpl.__init__ (self)

		def query(self, query):
			self._emit_query_ready (query, [TrackerSearchToolMatch220(name=query, priority=self.get_priority ())])



	class TrackerLiveSearchMatch220 (deskbar.interfaces.Match, LiveMatchImpl):

		def __init__(self, result, **args):
			deskbar.interfaces.Match.__init__ (self)
			LiveMatchImpl.__init__ (self)

			self.result = result
			try:
				desktop = result['desktop']
				del result['desktop']
			except:
				desktop = None

			# Set the match icon
			try:
				self._pixbuf = deskbar.core.Utils.load_icon(TYPES[result['type']]['icon'])
			except:
				if self.result.has_key ('icon'):
					self._pixbuf = deskbar.core.Utils.load_icon_for_desktop_icon (result ['icon'])
				else:
					if self.result['type'] != 'Conversations':
						try:
							self._pixbuf = deskbar.core.Utils.load_icon ('file://'+result['uri'])
						except:
							pass # some icons cannot be loaded... (e.g. for non existent file or illegal URI)

			self.add_action (TrackerLiveSearchAction220 (result, desktop))
			#if result['type'] == 'Images':
			#	for prg in ('gimp', 'gthumb', 'gwenview'):
			#		if is_program_in_path (prg):
			#			self.add_action (OpenWithApplicationAction (result['name'], prg, [result['uri']]))

		def get_name (self, text = None):
			return self.result ['name']

		def get_verb(self):
			return self.wrap_get_verb ()

		def get_category (self):
			return self.wrap_get_category ()

		def get_hash(self, text=None):
			return self.wrap_get_hash (text)



	class TrackerLiveSearchAction220 (deskbar.interfaces.Action, LiveMatchImpl):

		def __init__ (self, result, desktop):
			deskbar.interfaces.Action (self)
			LiveMatchImpl.__init__ (self)
			self.name = result['name']
			self.desktop = desktop
			self.result = result
			self.fullpath = result['uri']
			self.init_names()
			self.result['base'] = self.base
			self.result['dir'] = self.dir

		def get_name(self, text=None):
			return self.wrap_get_name (text)

		def get_hash(self, text=None):
			return self.wrap_get_hash (text)

		def get_verb(self):
			return self.wrap_get_verb ()

		def activate (self, text=None):
			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
				deskbar.core.Utils.spawn_async(cmd)
			else:
				if self.desktop:
					self.desktop.launch ([])
				else:
					deskbar.core.Utils.url_show ('file://'+dummy_escape(self.result['uri']))
				print 'Opening Tracker hit:', self.result['uri']



	class TrackerLiveSearchHandler220 (deskbar.interfaces.Module, LiveHandlerImpl):

		INFOS = {
				'icon': deskbar.core.Utils.load_icon ('tracker'),
				'name': _('Tracker Live Search'),
				'description': _('Search with Tracker, as you type'),
				'categories': {
				'develop': {
					'name': _('Development Files'),
				},
				'music': {
					'name': _('Music'),
				},
				'images': {
					'name': _('Images'),
				},
				'videos': {
					'name': _('Videos'),
				},
				'folders': {
					'name': _('Folders'),
				},
			},
		}

		def __init__(self):
			deskbar.interfaces.Module.__init__(self)
			LiveHandlerImpl.__init__ (self)

		def query (self, qstring):
			return self.wrap_query (qstring, MAX_RESULTS)

		@staticmethod
		def has_prerequisites ():
			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:
						TrackerLiveSearchHandler220.INSTRUCTIONS = ('Tracker is not activatable via dbus')
						return False
				except:
					TrackerLiveSearchHandler220.INSTRUCTIONS = ('Python dbus.glib bindings not found.')
					return False
				return True
			except:
				TrackerLiveSearchHandler220.INSTRUCTIONS = ('Python dbus bindings not found.')
				return False
_______________________________________________
tracker-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/tracker-list

Reply via email to