Re: [Deskbar] Man I'm gonna regret this :)
- From: Mikkel Kamstrup Erlandsen <kamstrup daimi au dk>
- To: deskbar-applet-list gnome org
- Subject: Re: [Deskbar] Man I'm gonna regret this :)
- Date: Thu, 20 Oct 2005 14:40:46 +0200
I've restructured the internals a bit. But I have problems opening the
hits on activation...
Play to your hearts content :) But until I figure out what I'm doing
wrong you won't be able to open any hits :(
Perhaps you guys have a clue. If you look at the terminal output you
will see that I definitely get the correct commandline arguments, they
just don't work when I os.spawn* them...
Cheers
Mikkel
On Thu, 2005-10-20 at 02:05 +0200, Mikkel Kamstrup Erlandsen wrote:
> 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.
> _______________________________________________
> deskbar-applet-list mailing list
> deskbar-applet-list gnome org
> http://mail.gnome.org/mailman/listinfo/deskbar-applet-list
import os, sys, signal
import popen2
from os.path import expanduser, exists, join
from gettext import gettext as _
import gnome, gnome.ui
import gtk
from gobject import spawn_async, SPAWN_SEARCH_PATH
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 = 0.6
MAX_HITS=2 # Max hits *per backend*
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 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,sender,action
#
# Optionally:
# "sender" : Template used to extract the "sender" field
TYPES = {
"Contact" : {
"name" : "fixme:FileAs = ",
"action": "evolution",
"icon" : "stock_contact",
"description": "Contact: %(name)s"
},
"MailMessage" : {
"name" :"dc:title = ",
"action": "evolution",
"icon" : "stock_mail",
"sender": "from_name = ",
"description": "Email from %(sender)s: %(name)s"
},
"File" : {
"name" : "beagle:ExactFilename = ",
"action": "gnome-open",
"icon" : None,
"description": "%(name)s"
},
"FeedItem" : {
"name" :"dc:title = ",
"action": "gnome-open",
"icon" : "stock_news",
"description": "News: %(name)s",# There don't seem to be a good "sender" template :(
},
"Note" : {
"name" : "dc:title = ",
"action": "tomboy",
"action_args": "--open-note",
"icon" :"stock_notes",
"description": "Note: %(name)s"
},
"IMLog" : {
"name" : "fixme:speakingto = ",
"action": "gnome-open", #FIXME how do we open chat logs like Beagle?
"icon" : "im",
"description": "Conversation with %(name)s"
}
}
class BeagleMatch (Match):
"""
"""
def __init__(self, handler, result):
"""
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:
"sender": Sender of email, chat message, poster of news item...
"""
if result["type"] == "File":
try:
icon_name, num = gnome.ui.icon_lookup(icon_theme, thumb_factory, file_uri=result["uri"], custom_icon="")
icon = icon_theme.load_icon(icon_name, deskbar.ICON_SIZE, gtk.ICON_LOOKUP_USE_BUILTIN)
if icon:
Match.__init__ (self, handler, result["name"], icon)
else:
raise Exception()
except Exception:
Match.__init__ (self, handler, result["name"], handler.ICONS["File"])
print >> sys.stderr, "BeagleLive: Failed to load icon for file %s" % result["uri"]
else:
# We are not a file. Just use an icon from the ICON table
Match.__init__ (self, handler, result["name"], handler.ICONS[result["type"]])
self.__result = result
def get_name (self, text=None):
# We use the result dict itself to look up words
return self.__result
def get_verb(self):
# Fetch the "description" template form TYPES
return TYPES[self.__result["type"]]["description"]
def action(self, text=None):
# FIXME FIXME FIXME
# This looks like it should work, but somehow doesn't.
# Retrieve the associated action
action = TYPES[self.__result["type"]]["action"]
args = [action]
# If the result requires additional arguments
# prepend them to args.
if TYPES[self.__result["type"]].has_key ("action_args"):
args.append(TYPES[self.__result["type"]]["action_args"])
args.append (self.__result["uri"])
# FIXME: URI opening does not seem to work no matter
# what I do!
print "BeagleLive: FIXME - ARGS:", args
os.spawnlp(os.P_NOWAIT, action, args)
#os.spawnvpe(os.P_NOWAIT, action, args, os.environ)
#spawn_async ([action]+args, flags=SPAWN_SEARCH_PATH)
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.
"""
# We need to contruct a few look-up tables to ease the parsing
self.SENDER_SUBSCRIBERS = self.__parse_sender_subscribers()
self.ICONS = self.__load_icons()
# 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 = {}
res_type = None # Since the "type" will be really handy, keep a direct ref to it
res_needs_sender = False
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("type")):
# 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)
self.emit_query_ready ([match])
# Reset our result
result = {}
res_type = None
res_needs_sender = False
if not result.has_key("uri"):
if line.startswith ("Uri: "):
result ["uri"] = line[5:]
continue
if not result.has_key("type"):
# Lots of stuff require us to have the 'Type: '-field
# at hand. Do all this stuff here, so we don't have to check
# for has_key("type") all over the place.
if line.startswith ("Type: "):
result["type"] = line[6:]
res_type = result["type"] # This is for handy reference
res_needs_sender = (res_type in self.SENDER_SUBSCRIBERS)
continue
else:
# Lots of stuff require us to have the 'Type: '-field
# at hand. Do all this stuff here, so we don't have to check
# for has_key("type") all over the place.
if not result.has_key("name"):
# Try and look up a name pattern by our type
# Since there's no common field for a display_String
# or the like we have to heuristically determine one.
# Look up a name pattern from NAME_PATTERNS
idx = line.find (TYPES[res_type]["name"])
if idx != -1:
result["name"] = line[idx+len(TYPES[res_type]["name"]):]
continue
if res_needs_sender:
if not result.has_key ("sender"):
idx = line.find (TYPES[res_type]["sender"])
if idx != -1:
result["sender"] = line[idx+len(TYPES[res_type]["sender"]):]
def __parse_sender_subscribers (self):
res = []
for t in TYPES.iterkeys():
if TYPES[t].has_key ("sender"):
res.append (t)
return res
def __load_icons (self):
res = {}
for t in TYPES.iterkeys():
icon_file = TYPES[t]["icon"]
if not icon_file: continue
try:
res[t] = icon_theme.load_icon(icon_file, deskbar.ICON_SIZE, gtk.ICON_LOOKUP_USE_BUILTIN)
except Exception:
res[t] = None
print >> sys.stderr, "BeagleLive: Unable to load icon for %s" % t
return res
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]