Old deskbar

Tomas R <[email protected]>
Newsgroups gmane.comp.gnome.dashboard.devel
Message-ID <20080420181540.5d8131ef@ubuntu>
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

_______________________________________________
Dashboard-hackers mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/dashboard-hackers
beagle-live.py (text/x-python, 12 KB)
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)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.