Old deskbar



Hi,
I would like to use beagle live search with deskbar 2.18.1, but when I
try to search for anything, beagle throws an excemption:
http://pastebin.com/m64d489e6

maybe someone could take a look at the beagle handler for deskbar and
fix it (if there is an easy fix).

PS: handler attached.

-- 
Brain: an apparatus with which we think we think. - A. Bierce
import os, sys, cgi, re
import gobject,gtk, gnome, gnome.ui, gnomevfs
import deskbar, deskbar.Handler, deskbar.Utils, deskbar.Match
from gettext import gettext as _
from os.path import exists, dirname
from deskbar.defs import VERSION
from deskbar.Utils import is_program_in_path, spawn_async, url_show, url_show_file

MAX_RESULTS = 20 # per handler

try:
	import beagle
except:
	# If this fails we complain about it in _check_requirements()
	# so do nothing now
	pass

def _show_start_beagle_dialog (dialog):
	dialog = gtk.Dialog(_("Start Beagle Daemon?"), dialog,
				gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
	
	dialog.set_default_size (350, 150)
	dialog.add_button (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)
	dialog.add_button (_("Start Beagle Daemon"), gtk.RESPONSE_ACCEPT)
	label = gtk.Label (_("The Beagle daemon does not appear to be running.\n You need to start it to use the Beagle Live handler."))
	dialog.vbox.add (label)
	label.show()

	response = dialog.run()
	dialog.destroy()
	
	if response == gtk.RESPONSE_ACCEPT :
		print "Starting Beagle Daemon."
		if not spawn_async(["beagled"]):
			print >> sys.stfderr, "Failed to start beagled. Perhaps the beagle daemon isn't installed?"	
			warn = gtk.MessageDialog(flags=gtk.DIALOG_MODAL, 
						type=gtk.MESSAGE_WARNING,
						buttons=gtk.BUTTONS_CLOSE,
						message_format=_("Failed to start Beagle"))
			warn.format_secondary_text (_("Perhaps the beagle daemon isn't installed?"))
			warn.run()
			warn.destroy()

def _check_requirements():
	# Check if we have python bindings for beagle
	try:
		import deskbar
		import beagle
	except Exception, e:
		return (deskbar.Handler.HANDLER_IS_NOT_APPLICABLE, "Could not load beagle, libbeagle has been compiled without python bindings:"+str(e), None)

	# Check if beagled is running		
	if not beagle.beagle_util_daemon_is_running ():
		if is_program_in_path("beagled"):
			return (deskbar.Handler.HANDLER_HAS_REQUIREMENTS, "Beagle daemon is not running.", _show_start_beagle_dialog)
		else:
			return (deskbar.Handler.HANDLER_IS_NOT_APPLICABLE, "Beagled could not be found in your $PATH. Unable to start the beagled daemon", None)
	else:
		return (deskbar.Handler.HANDLER_IS_HAPPY, None, None)
	
HANDLERS = {
	"BeagleLiveHandler" : {
		"name": _("Beagle Live"),
		"description": _("Search all of your documents (using Beagle), as you type"),
		# We must see how to detect properly beagle, for now it will fail on creating a new client
		# when beagle is not available.
		"requirements" : _check_requirements,
		"version": VERSION,
	}
}

# The TYPES dict contains Beagle HitTypes as keys with
# templates for the valid fields.
#
# A Hit Type consists of:
#	"name"		: Template used to find a user-displayable name
#	"action"	: Command to execute
#	"icon"		: The *name* of the icon to be sued for this type. Set to None for no icon.
#	"description"	: A short description. %(*)s may refer to *=name,uri,action or any field in "extra" (see below)
#
# Optionally:
#	"extra"	: A dict containing key:template pairs to search for. You can use %(key)s in "description".
#
# Note:
#  The templates are a tuple of strings which should be tested in order to retreive the beagle property

TYPES = {
	"Contact"	: {
		"name"	: ("fixme:FileAs",),
		"action": "evolution %(uri)s",
		"icon"	: "stock_contact",
		"description": _("Edit contact %s") % "<b>%(name)s</b>",
		"category": "people",
		},
	
	"MailMessage" 	: {
		"name"	:("dc:title", "parent:dc:title"),
		"action": "evolution %(uri)s",
		"icon"	: "stock_mail",
		"extra": {"sender":("fixme:from_name", "parent:fixme:from_name")},
		"description": (_("From %s") % "<i>%(sender)s</i>" ) + "\n<b>%(name)s</b>",
		"category": "emails",
		},
	"File" 		: {
		"name"	: ("beagle:ExactFilename",), 
		"action": lambda d: url_show_file(+d["uri"]),
		"icon"	: "stock_new",
		#translators: This is a file.
		"description": _("Open %s") % "<b>%(name)s</b>",
		"snippet": True,
		"category": "files",
		},
	"FeedItem"	: {
		"name"	: ("dc:title",),
		"action": lambda d: url_show(d["identifier"]),
		"icon"	: "stock_news",
		"description": (_("News from %s") % "<i>%(publisher)s</i>" ) + "\n<b>%(name)s</b>",
		"snippet": True,
		"category": "news",
		"extra": {"publisher":("dc:publisher",), "identifier": ("dc:identifier",)},
		},
	"Note"		: {
		"name"	: ("dc:title",),
		"action": "tomboy --open-note %(uri)s",
		"icon"	:"stock_notes",
		"description": _("Note: %s") % "<b>%(name)s</b>",
		"snippet": True,
		"category": "notes",
		},
	"IMLog"		: {
		"name"	: ("fixme:speakingto",),
		"extra" : {"client": ("fixme:client",)},
		"action": "beagle-imlogviewer --client %(client)s --highlight-search '%(text)s' %(uri)s",
		"icon"	: "im",
		"description": _("With %s") % "<b>%(name)s</b>",
		"snippet": True,
		"category": "conversations",
		},
	"Calendar"	: {
		"name"	: ("fixme:summary",),
		"action": "evolution %(uri)s",
		"icon"	: "stock_calendar",
		"description": _("Calendar: %s") % "<b>%(name)s</b>",
		"category": "documents",
		},
	"WebHistory": {
		"name"	: ("dc:title",), # FIX-BEAGLE bug #330053, dc:title returns as None even though it _is_ set
		"action": lambda d: url_show_file(d["uri"]),
		"icon"	: "stock_bookmark",
		"description": (_("Open History Item %s") % "<i>%(name)s</i>") + "\n%(escaped_uri)s",
		"category": "web",
		},
}

# Append snippet text for snippet-enabled handlers
for key, val in TYPES.items():
	if "snippet" in val and val["snippet"]:
		val["description"] += "%(snippet)s"
		
class BeagleLiveMatch (deskbar.Match.Match):
	def __init__(self, handler, result=None, **args):
		"""
		result: a dict containing:
			"name" : a name sensible to display for this match
			"uri": the uri of the match as provided by the beagled 'Uri: '-field
			"type": One of the types listed in the TYPES dict

		-- and optionally extra fields as provided by the corresponding entry in TYPES.
		Fx. "MailMessage". has an extra "sender" entry.
		"""
		deskbar.Match.Match.__init__ (self, handler, name=result["name"], **args)
		self.result = result

		# IM Log viewer take loca paths only		
		action = TYPES[self.result["type"]]["action"]
		if not callable(action) and action.startswith("beagle-imlogviewer"):
			# Strip the uti descriptor, because imlogviewer takes a local path
			self.result["uri"] = gnomevfs.get_local_path_from_uri(self.result["uri"])			
		
		# Load the correct icon
		
		#
		# There is bug http://bugzilla.gnome.org/show_bug.cgi?id=319549
		# which has been fixed and comitted, so we re-enable this snippet
		#
		
		self._icon = None
		if result["type"] == "File":
			try:
				self._icon = deskbar.Utils.load_icon_for_file(result["uri"])
			except Exception:
				pass
		
		if self._icon == None:
			# Just use an icon from the ICON table
			self._icon = handler.ICONS[result["type"]]
		
	def get_category (self):
		try:
			return TYPES[self.result["type"]]["category"]
		except:
			return "default"
		
	def get_name (self, text=None):
		# We use the result dict itself to look up words
		if text:
			self.result["text"] = text
			# Escape text since we use '%(text)s' as parameter
			self.result["text"] = self.result["text"].replace("'", "\\'")
		return self.result
	
	def get_verb(self):
		# Fetch the "description" template from TYPES
		return TYPES[self.result["type"]]["description"]
		
	def action(self, text=None):
		# The call to get_name(text) ensures that we have
		# the text field in the result dict
		self.get_name(text)
		
		action = TYPES[self.result["type"]]["action"]
		if callable(action):
			action(self.result)
		else:
			# Retrieve the associated action
			action = action % self.result
			args = action.split(" ")

			print "BeagleLive spawning:", action, args
			spawn_async(args)
	
	def get_hash(self, text=None):
		if "uri" in self.result:
			return self.result["uri"]

class SnippetContainer:
	def __init__(self, hit):
		self.hit = hit
		self.snippet = None
	
class BeagleLiveHandler(deskbar.Handler.SignallingHandler):
	def __init__(self):
		deskbar.Handler.SignallingHandler.__init__(self, ("system-search", "best"))
		self.counter = {}
		self.snippets = {}
		self.set_delay (500)
		
	def initialize (self):
		self.beagle = beagle.Client()
		self.ICONS = self.__load_icons()
	
	def __load_icons (self):
		res = {}
		for t in TYPES.iterkeys():
			icon_file = TYPES[t]["icon"]
			if not icon_file: continue
			res[t] = deskbar.Utils.load_icon(icon_file)
		return res
		
	def query (self, qstring):
		beagle_query = beagle.Query()
		beagle_query.add_text(qstring)
		beagle_query.connect("hits-added", self.hits_added, qstring, MAX_RESULTS)
		try:
			self.beagle.send_request_async(beagle_query)
		except:
			return
			
		self.counter[qstring] = {}
		
	def _on_snippet_received(self, request, response, query, container, qstring, qmax):
		container.snippet = response.get_snippet()
		self._on_hit_added(query, container, qstring, qmax)
	
	def _on_snippet_closed(self, request, query, container, qstring, qmax):
		if container.snippet == None:
			self._on_hit_added(query, container, qstring, qmax)
			
		container.hit.unref()
			
	def _on_hit_added(self, query, hit, qstring, qmax):
		fire_signal = False
		snippet = None
		if hit.__class__ == SnippetContainer:
			hit, snippet = hit.hit, hit.snippet
			fire_signal = True
			
		if not hit.get_type() in self.counter[qstring]:
			self.counter[qstring][hit.get_type()] = 0

		if self.counter[qstring][hit.get_type()] >= qmax:
			return
			
		hit_type = TYPES[hit.get_type()]
		result = {
			"uri":  hit.get_uri(),
			"type": hit.get_type(),
		}
			
		name = None
		for prop in hit_type["name"]:
			try:
				name = hit.get_properties(prop)[0] # get_property_one() would be cleaner, but this works around bug #330053
			except:
				try:
					# Beagle < 0.2
					name = hit.get_property(prop)
				except:
					pass
					
			if name != None:
				result["name"] = name
				break
		
		if name == None:
			#translators: This is used for unknown values returned by beagle
			#translators: for example unknown email sender, or unknown note title
			result["name"] = _("?")
			
		if "extra" in hit_type:
			for prop, keys in hit_type["extra"].items():
				val = None
				for key in keys:
					try:
						val = hit.get_properties(key)[0] # get_property_one() would be cleaner, but this works around bug #330053
					except:
						try:
							# Beagle < 0.2
							val = hit.get_property(key)
						except:
							pass
							
					if val != None:
						result[prop] = val
						break
					
				if val == None:
					#translators: This is used for unknown values returned by beagle
					#translators: for example unknown email sender, or unknown note title
					result[prop] = _("?")
		
		# Escape everything for display through pango markup, except filenames. Filenames are escaped in escaped_uri or 
		# escaped_identifier
		for key, val in result.items():
			if key == "uri" or key == "identifier":
				result["escaped_"+key] = cgi.escape(val)
			else:
				result[key] = cgi.escape(val)
		
		# Add the snippet, in escaped form if available
		if snippet != None:
			tmp = re.sub(r"<.*?>", "", snippet)
			tmp = re.sub(r"</.*?>", "", tmp)
			result["snippet"] = "\n<span foreground='grey' size='small'>%s</span>" % cgi.escape(tmp)
		else:
			result["snippet"] = ""
			
		self.counter[qstring][hit.get_type()] = self.counter[qstring][hit.get_type()] +1

		match = BeagleLiveMatch(self, result)
		if fire_signal:
			self.emit_query_ready(qstring, [match])
		else:	
			return match
		
	def hits_added(self, query, response, qstring, qmax):
		hit_matches = []
		for hit in response.get_hits():
			if hit.get_type() not in TYPES:
				print 'WARNING: Beagle live seen an unknown type:', hit.get_type()
				continue

			if "snippet" in TYPES[hit.get_type()] and TYPES[hit.get_type()]["snippet"]:
				req = beagle.SnippetRequest()
				req.set_query(query)
				req.set_hit(hit)
				container = SnippetContainer(hit)
				hit.ref()
				req.connect('response', self._on_snippet_received, query, container, qstring, qmax)
				req.connect('closed', self._on_snippet_closed, query, container, qstring, qmax)
				self.beagle.send_request_async(req)
				continue
							
			match = self._on_hit_added(query, hit, qstring, qmax)
			if match != None:
				hit_matches.append(match)				
			
		self.emit_query_ready(qstring, hit_matches)


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