[Deskbar] Man I'm gonna regret this :)
- From: Mikkel Kamstrup Erlandsen <kamstrup daimi au dk>
- To: deskbar-applet-list gnome org
- Subject: [Deskbar] Man I'm gonna regret this :)
- Date: Thu, 20 Oct 2005 02:05:25 +0200
Ok... *Only* because I promised to do this...
Here's a Beagle Live handler. It is heavily IN THE WORKS, but has some
basic functionality. It is only tested against Beagle 0.1.1 on Ubuntu
Breezy, and I have no idea how it fares against other Beagle
versions :-S
If you try it out, please post your experiences here. But be aware that
this handler probably never makes it into any release. It is a toy.
Caveat Emptor!
Cheers
Mikkel
PS: You almost certainly need a fresh cvs to use this handler.
import os, sys, signal
import popen2
from os.path import expanduser, exists, join
from gettext import gettext as _
import gnome, gnome.ui
import gtk
icon_theme = gtk.icon_theme_get_default()
thumb_factory = gnome.ui.ThumbnailFactory(16)
import deskbar
from deskbar.handler import AsyncHandler, Match
import deskbar.defs
QUERY_DELAY = 1
MAX_HITS=2
def _check_requirements():
return (True, None)
HANDLERS = {
"BeagleLiveHandler" : {
"name": _("Live Beagle Queries"),
"description": _("Query Beagle automatically as you type."),
"requirements" : _check_requirements
}
}
class UnknownBeagleTask (Exception):
pass
class NoBeagleDaemon (Exception):
pass
class BeagleProcess (popen2.Popen3):
"""
"""
# Mental note to self: The beagle-query --max-hits switch sets
#max number of hits *per backend*.
# Task definitions
GET_DAEMON_VERSION = 0
QUERY = 1
def __init__ (self, task, query=None, max_hits=MAX_HITS):
if task is self.GET_DAEMON_VERSION:
popen2.Popen3.__init__(self, "beagle-info --daemon-version",)
return
elif task is self.QUERY and query is not None:
print "Querying for", query
popen2.Popen3.__init__(self,
"beagle-query %s --verbose --max-hits %s" % (query, MAX_HITS))
else:
raise UnknownBeagleTask()
#
# The following lists are separated (not using dicts of dicts)
# to allow easier iteration.
#
# This dict contains Beagle HitTypes as keys with
# sensible match name fields as values.
NAME_PATTERNS = {
"Contact" : "fixme:FileAs = ",
"MailMessage" : "dc:title = ",
"File" : "beagle:ExactFilename = ",
"FeedItem" : "dc:title = ",
"Note" : "dc:title = ",
"IMLog" : "fixme:speakingto = "
}
ACTIONS = {
"Contact" : "evolution",
"MailMessage" : "evolution",
"File" : "gnome-open",
"FeedItem" : "gnome-open",
"Note" : "tomboy --open-note", # FIXME: Doesn't work with spawnlp - we need to put the --open-note somewhere else
"IMLog" : "gnome-open" # FIXME: WHow do we call th eIM log viewer?
}
ICONS = {
"Contact" : "stock_contact",
"MailMessage" : "stock_mail",
"File" : "stock_new",
"FeedItem" : "stock_news",
"Note" : "stock_notes",
"IMLog" : "im"
}
#icon_theme.load_icon(drive.get_icon(), deskbar.ICON_SIZE, gtk.ICON_LOOKUP_USE_BUILTIN),
class BeagleMatch (Match):
def __init__(self, handler, name, uri, hittype, mime=None):
if mime:
# We only get mimetypes for files. Fetch a matching icon.
try:
icon_name, num = gnome.ui.icon_lookup(icon_theme, thumb_factory, file_uri=uri, custom_icon="")#uri, None, None, mime, None)#info)
icon = icon_theme.load_icon(icon_name, deskbar.ICON_SIZE, gtk.ICON_LOOKUP_USE_BUILTIN)
if icon:
Match.__init__ (self, handler, name, icon)
else:
raise Exception()
except Exception:
Match.__init__ (self, handler, name, ICONS[hittype])
print >> sys.stderr, "BeagleLive: Failed to load icon for file %s" % uri
else:
# We are not a file. Just use an icon from the ICON table
Match.__init__ (self, handler, name, ICONS[hittype])
self.__uri = uri
self.__hittype = hittype
def get_verb(self):
# FIXME: We should prepend sensible strings for each hittype
return "%(name)s"
def action(self, text=None):
os.spawnlp(os.P_NOWAIT, ACTIONS[self.__hittype], ACTIONS[self.__hittype], self.__uri)
class BeagleLiveHandler (AsyncHandler):
"""
"""
def __init__ (self):
AsyncHandler.__init__ (self)
self.__process = None
def initialize (self):
"""
Loads needed icons into memory, also
try to connect to the beagle daemon an get its' version number.
This method raises a NoBeagleDaemon exception if the beagle daemon
is not running.
"""
# Load the icons here. This ought to be thread safe.
# Initially ICONS contains a dict of hittype:icon_name.
# We replace icon_name with the corresponding pixbufs.
# This is a *trick* not a hack :-)
for hittype in ICONS.iterkeys():
if ICONS[hittype]:
try:
ICONS[hittype] = icon_theme.load_icon(ICONS[hittype], deskbar.ICON_SIZE, gtk.ICON_LOOKUP_USE_BUILTIN)
except Exception:
ICONS[hittype] = None
print >> sys.stderr, "BeagleLive: Unable to load icon for %s" % hittype
# Check if beagled is running and get the version
process = BeagleProcess (BeagleProcess.GET_DAEMON_VERSION)
process.wait()
self.__daemon_version = process.fromchild.readline()
idx = self.__daemon_version.find(":")
if idx == -1:
print >> sys.stderr, "BeagleLive: Unable to connect to Beagle daemon!"
raise NoBeagleDaemon()
self.__daemon_version = self.__daemon_version[idx+2:]
print "BeagleLive: Using Beagle daemon version %s"% self.__daemon_version
def query (self, qstring, qmax=5):
# Delay query
self.check_query_changed (timeout=QUERY_DELAY)
print "BeagleLive: Querying for %s" % qstring
self.__process = BeagleProcess (BeagleProcess.QUERY, qstring, qmax)
self.parse (self.__process.fromchild)
self.__process.wait()
self.__process = None
print "BeagleLive: query for '%s' completed" % qstring
def __clean_up (self):
# If we have a running beagle query, send it a SIGINT
if self.__process:
os.kill (self.__process.pid, signal.SIGINT)
self.__process.wait()
self.__process = None
print "BeagleLive: Beagle query interupted."
def parse (self, pipe):
"""
All the work is being done here. We basically walk line by
line through the beagle-query output and match each line against
known keywords.
"""
result = {}
line = "a"
while True:
line = pipe.readline()
if line == "":
break
line = line.strip()
if line.startswith("Uri: ") or line == "":
# A new hit is starting or we've hit EOF
# Do we have a qualified match?
if ( result.has_key("name") and
result.has_key("uri") and
result.has_key("hittype")):
# If this is file with a detected mime type
# we should retrieve an icon for it. This will
# be done in BeagleMatch.__init__
mime = None
if result.has_key("mime") and result["hittype"] == "File":
mime = result["mime"]
# We have all we need.
# Emit "query-ready" to main loop
# if the query is still valid
self.check_query_changed(self.__clean_up)
match = BeagleMatch(self, result["name"], result["uri"], result["hittype"], mime)
self.emit_query_ready ([match])
# Reset our result
result = {}
if not result.has_key("uri"):
if line.startswith ("Uri: "):
result ["uri"] = line[5:]
elif not result.has_key("hittype"):
if line.startswith ("Type: "):
result["hittype"] = line[6:]
elif not result.has_key("mime"):
if line.startswith ("MimeT: "):
result["mime"] = line [7:]
print "Found MIME:", result["mime"]
elif not result.has_key("name"):
# Try and look up a name pattern by our hittype
# Since there's no common field for a display_String
# or the like we have to heuristically determine one.
# First try to look up a name pattern from NAME_PATTERNS
if result.has_key ("hittype")
idx = line.find (NAME_PATTERNS[result["hittype"]])
if idx != -1:
result["name"] = line[idx+len(NAME_PATTERNS[result["hittype"]]):]
else:
# We have no detected hittype yet.
# Use brute force.
for hittype in NAME_PATTERNS.itervalues():
idx = line.find (hittype)
if idx != -1:
result["name"] = line[idx+len(hittype):]
break
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]