Reimplemented lookuplet in Python and Glade.

git-svn-id: https://samskivert.googlecode.com/svn/trunk@661 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2002-03-17 09:03:06 +00:00
parent 02c2f6a7b7
commit 7a280c80f9
6 changed files with 664 additions and 5 deletions
+1 -5
View File
@@ -1,5 +1 @@
Makefile.in
Makefile
lookuplet
.deps
.libs
*.pyc
+141
View File
@@ -0,0 +1,141 @@
#
# $Id: bindings.py,v 1.1 2002/03/17 09:03:06 mdb Exp $
#
# lookuplet - a utility for quickly looking up information
# Copyright (C) 2001 Michael Bayne
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2.1 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import posix
import re
import string
import urllib
import gnome.config
import gnome.url
class Binding:
"Contains the configuration for a particular key binding and its \
associated query mapping."
# constants defining which type of binding this is
URL = 0;
EXEC = 1;
# the key combination associated with this binding
key = "";
# the type of binding (URL or Exec)
type = URL;
# the human readable name of the binding
name = "";
# the URL or command line assosciated with the binding
argument = "";
#
# Constructs a binding with its requisite parameters.
#
def __init__ (self, key, type, name, argument):
self.key = key;
self.type = type;
self.name = name;
self.argument = argument;
def invoke (self, terms):
command = re.sub("%T", terms, self.argument);
command = re.sub("%U", urllib.quote(terms), command);
if (self.type == self.EXEC):
posix.system(command)
else:
gnome.url.show(command)
def update (self, key, type, name, argument):
modified = 0;
if (cmp(key, self.key)):
self.key = key;
modified = 1;
if (type != self.type):
self.type = type;
modified = 1;
if (cmp(name, self.name)):
self.name = name;
modified = 1;
if (cmp(argument, self.argument)):
self.argument = argument;
modified = 1;
return modified;
def to_string (self):
return "[key=%s, type=%d, name=%s, arg=%s]" % (
self.key, self.type, self.name, self.argument);
class BindingSet:
"Maintains the set of bindings loading into the program."
# the list of Binding objects
bindings = [];
#
# The default constructor.
#
def __init__ (self):
gnome.config.push_prefix("/lookuplet/");
count = gnome.config.get_int("lookuplet/bindings/count");
for b in range(0, count):
key = gnome.config.get_string("lookuplet/bindings/key_%.2u" % b);
type = gnome.config.get_int("lookuplet/bindings/type_%.2u" % b);
name = gnome.config.get_string("lookuplet/bindings/name_%.2u" % b);
arg = gnome.config.get_string("lookuplet/bindings/arg_%.2u" % b);
self.bindings.append(Binding(key, type, name, arg));
gnome.config.pop_prefix();
return;
#
# Returns the binding with a keysym matching the specified keysym or
# None if no binding matches.
#
def get_match (self, keysym):
for binding in self.bindings:
if (binding.key == keysym):
return binding
return None;
#
# Stores our updated bindings to our GConf preferences.
#
def flush (self):
gnome.config.push_prefix("/lookuplet/");
gnome.config.set_int("lookuplet/bindings/count", len(self.bindings));
b = 0
for binding in self.bindings:
gnome.config.set_string(
"lookuplet/bindings/key_%.2u" % b, binding.key);
gnome.config.set_int(
"lookuplet/bindings/type_%.2u" % b, binding.type);
gnome.config.set_string(
"lookuplet/bindings/name_%.2u" % b, binding.name);
gnome.config.set_string(
"lookuplet/bindings/arg_%.2u" % b, binding.argument);
b += 1;
gnome.config.sync();
gnome.config.drop_all();
gnome.config.pop_prefix();
return;
@@ -0,0 +1,159 @@
#
# $Id: edit_binding.py,v 1.1 2002/03/17 09:03:06 mdb Exp $
#
# lookuplet - a utility for quickly looking up information
# Copyright (C) 2001 Michael Bayne
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2.1 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import gtk
import GDK
import gnome.ui
import libglade
import string
import re
import bindings
import keyval_util
class BindingEditor:
# the properties instance for which we're editing bindings
props = None;
# our bindings set
bindings = None;
# the binding editor panel
bindPanel = None;
# the grab window
grabWindow = None;
# the index of the binding we're editing
index = -1;
# the binding we're editing
binding = None;
# the key entry field
keyField = None;
# the name entry field
nameField = None;
# the argument type selector
argTypeSel = None;
# the URL menu item of the arg selection widget
urlItem = None;
# the argument entry field
argField = None;
def __init__ (self, xmlui, props, bindings):
# keep these around for later
self.props = props;
self.bindings = bindings;
# get a reference to some widgets
self.bindPanel = xmlui.get_widget("binding");
self.grabWindow = xmlui.get_widget("grab");
self.keyField = xmlui.get_widget("key");
self.nameField = xmlui.get_widget("name");
self.argTypeSel = xmlui.get_widget("type");
self.urlItem = self.argTypeSel.get_menu().get_active();
self.argField = xmlui.get_widget("argument");
# wire up our handlers
nameFuncMap = {};
for key in dir(self.__class__):
nameFuncMap[key] = getattr(self, key);
xmlui.signal_autoconnect(nameFuncMap);
#
# Instructs the binding panel to display itself, configured for
# editing the supplied binding.
#
def editBinding (self, index):
# keep a reference to the binding
self.index = index;
self.binding = self.bindings.bindings[index];
self.populateAndShow(self.binding);
#
# Instructs the binding panel to create a blank binding and make that
# available for editing by the user.
#
def createBinding (self):
# create a blank binding and edit it
self.index = -1;
self.binding = bindings.Binding("", bindings.Binding.URL, "", "");
self.populateAndShow(self.binding);
#
# A helper function used to populate our widgets and show the dialog.
#
def populateAndShow (self, binding):
print "populating from binding " + binding.to_string();
# populate our widgets with the binding values
self.keyField.set_text(binding.key);
self.nameField.set_text(binding.name);
self.argTypeSel.set_history(binding.type);
self.argField.set_text(binding.argument);
# and show the bind dialog
self.bindPanel.show();
#
# A callback, called when the OK button is clicked.
#
def on_ok_clicked (self, button):
# figure out which type menu item is selected; what a hack
active = self.argTypeSel.get_menu().get_active();
if (active == self.urlItem):
type = bindings.Binding.URL;
else:
type = bindings.Binding.EXEC;
# repopulate our binding
modified = self.binding.update(self.keyField.get_text(), type,
self.nameField.get_text(),
self.argField.get_text());
# let the props panel know if there were any modifications
if (modified):
if (self.index >= 0):
self.props.updated(self.index);
else:
self.props.created(self.binding);
# hide the binding panel
self.bindPanel.hide();
#
# A callback, called when the cancel button is clicked.
#
def on_cancel_clicked (self, button):
# hide the binding panel
self.bindPanel.hide();
def on_key_key_press_event (self, textfield, event):
# ignore plain or shifted keystrokes
if (event.state > 1):
# convert the key press into a string
keystr = keyval_util.convert_keyval_state_to_string(
event.keyval, event.state);
textfield.set_text(keystr);
return gtk.TRUE;
@@ -0,0 +1,57 @@
#
# $Id: keyval_util.py,v 1.1 2002/03/17 09:03:06 mdb Exp $
#
# lookuplet - a utility for quickly looking up information
# Copyright (C) 2001 Michael Bayne
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2.1 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import string
import GDK
# these are used when doing our conversion
_CODES = [ GDK.CONTROL_MASK, GDK.LOCK_MASK, GDK.SHIFT_MASK, GDK.MOD1_MASK,
GDK.MOD2_MASK, GDK.MOD3_MASK ];
_NAMES = [ "Control", "Lock", "Shift", "Mod1", "Mod2", "Mod3" ];
#
# Converts a (keyval, state) pair to a human readable string.
#
def convert_keyval_state_to_string (keyval, state):
# bail if we've got an invalid kesym
if (keyval == 0):
return "None";
# start with the empty string
modstr = "";
# we'd like to ask GDK to convert the key itself to a string, but they
# don't wrap those functions. dooh!
# key = GDK.keyval_name(keyval);
# so we do this hack instead
if (keyval < 0 or keyval > 255):
return "None";
key = string.lower(chr(keyval));
# we have to handle the modifiers ourselves
i = 0;
for code in _CODES:
if (state & code):
modstr += _NAMES[i];
modstr += "-";
i += 1;
return modstr + key;
+173
View File
@@ -0,0 +1,173 @@
#
# $Id: lookuplet.py,v 1.1 2002/03/17 09:03:06 mdb Exp $
#
# lookuplet - a utility for quickly looking up information
# Copyright (C) 2001 Michael Bayne
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2.1 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import gnome.applet
import gtk
import GDK
import gnome.ui
import gnome.uiconsts
import string
import re
import bindings
import keyval_util
import properties
class Lookuplet:
"Handles the primary setup and operation of the lookuplet application."
# in theory these should be defined by GDK but seem not to be
SELECTION_PRIMARY = 1;
CURRENT_TIME = 0;
# a reference to our key bindings
bindings = None;
# our about box
about = None;
# a reference to the properties manager
props = None;
# whether or not we're running as a Gnome applet
appletMode = 0;
def __init__ (self, xmlui, bindings, props, appletMode):
window = xmlui.get_widget("lookuplet");
query = xmlui.get_widget("query");
self.about = xmlui.get_widget("about");
self.string_atom = None;
self.bindings = bindings;
self.props = props;
self.appletMode = appletMode;
# wire up our handlers
nameFuncMap = {};
for key in dir(self.__class__):
nameFuncMap[key] = getattr(self, key);
xmlui.signal_autoconnect(nameFuncMap);
# if we're in applet mode, extract the UI and stick it into an
# applet widget
if (appletMode):
applet = gnome.applet.AppletWidget("lookuplet");
mainbox = xmlui.get_widget("mainbox");
# lose the border
mainbox.set_border_width(0);
# and hide the prefs button
prefs = xmlui.get_widget("prefs");
prefs.hide();
# remove everything from the window
window.remove(mainbox);
# and add it to the applet
applet.add(mainbox);
# register our menu items
applet.register_stock_callback(
"properties", gnome.uiconsts.STOCK_MENU_PROP,
"Properties...", self.on_props_selected, None);
applet.register_stock_callback(
"about", gnome.uiconsts.STOCK_MENU_ABOUT,
"About...", self.on_about_selected, None);
applet.show();
else:
window.show();
# request the selection
if (self.string_atom == None):
self.string_atom = gtk.atom_intern("STRING", gtk.FALSE);
query.selection_convert(self.SELECTION_PRIMARY,
self.string_atom,
self.CURRENT_TIME);
# put the focus in the query box
query.grab_focus();
def on_props_selected (self, one, two):
self.props.editProperties();
def on_about_selected (self, one, two):
self.about.show();
def on_prefs_clicked (self, button):
self.props.editProperties();
def on_query_key_press_event (self, query, event):
# handle special keystrokes such as history and auto-complete
# if (handle_special_keys(widget, ek)):
# return true;
# ignore plain or shifted keystrokes
if (event.state <= 1):
return gtk.FALSE;
# convert the key press into a string
keystr = keyval_util.convert_keyval_state_to_string(
event.keyval, event.state);
# look up a binding for that key string
binding = self.bindings.get_match(keystr);
if (binding != None):
# if we found one, invoke it
binding.invoke(query.get_text());
if (self.appletMode):
query.set_text("");
else:
gtk.mainquit();
return gtk.TRUE;
else:
# otherwise, let GTK know that we didn't handle the key press
return gtk.FALSE;
def on_query_selection_received (self, query, selection_data, data):
if (selection_data.length < 0):
# print "Selection retrieval failed.";
return;
if (selection_data.type != GDK.SELECTION_TYPE_STRING):
print "Selection target not returned as a string.";
return;
print "Got selection '%s'." % selection_data.data;
# prune spaces from the end of the text
text = string.strip(selection_data.data);
# compress whitespace (and convert newlines to spaces)
text = re.sub("[ \r\n]+", " ", text);
# make sure some selection was provided
if (len(text) > 0):
# check to see if we're looking at a url here
# is_url = url_p(text);
# if this is a URL, we want to eat whitespace
# if (is_url):
# text.tr!(" ", "");
if (cmp(text, selection_data.data)):
# print "Setting trimmed text '" + text + "'.";
query.set_text(text);
query.select_region(0, len(text));
# print "Selected from %d to %d." % (0, len(text));
def exit_lookuplet (self, button):
gtk.mainquit();
+133
View File
@@ -0,0 +1,133 @@
#
# $Id: properties.py,v 1.1 2002/03/17 09:03:06 mdb Exp $
#
# lookuplet - a utility for quickly looking up information
# Copyright (C) 2001-2002 Michael Bayne
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2.1 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import gtk
import GDK
import gnome.ui
import libglade
import string
import re
import edit_binding
class Properties:
# our configured key bindings
bindings = None;
# the properties panel
propsPanel = None;
# our binding editor
bindEditor = None;
# the bindings list
bindList = None;
# the edit button
editButton = None;
# the delete button
deleteButton = None;
# the selected binding index
selection = -1;
def __init__ (self, xmlui, bindings):
# keep a handle on our bindings
self.bindings = bindings;
# create our binding editor
self.bindEditor = edit_binding.BindingEditor(xmlui, self, bindings);
# get a reference to some widgets
self.propsPanel = xmlui.get_widget("properties");
self.editButton = xmlui.get_widget("edit");
self.deleteButton = xmlui.get_widget("delete");
self.bindList = xmlui.get_widget("bindings");
# wire up our handlers
nameFuncMap = {};
for key in dir(self.__class__):
nameFuncMap[key] = getattr(self, key);
xmlui.signal_autoconnect(nameFuncMap);
# configure our properties panel with the loaded bindings
for binding in bindings.bindings:
self.bindList.append([binding.key, binding.name]);
def editProperties (self):
self.propsPanel.show();
return;
def updated (self, index):
binding = self.bindings.bindings[index];
# refresh the display for the specified index
self.bindList.set_text(index, 0, binding.key);
self.bindList.set_text(index, 1, binding.name);
# and make a note that we've updated ourselves
self.propsPanel.changed();
def created (self, binding):
# add the new binding to our list
self.bindings.bindings.append(binding);
# add it to the display
self.bindList.append([binding.key, binding.name]);
# and make a note that we've updated ourselves
self.propsPanel.changed();
def on_properties_apply (self, panel, page):
if (page == 0):
self.bindings.flush();
def on_bindings_select_row (self, clist, row, column, event):
# enable our buttons
self.editButton.set_sensitive(gtk.TRUE);
self.deleteButton.set_sensitive(gtk.TRUE);
# make a note of the selected binding index
self.selection = row;
# make like they pressed the edit button on a double click
if (event.type == GDK._2BUTTON_PRESS):
self.on_edit_clicked(None);
def on_bindings_unselect_row (self, clist, row, column, event):
# disable our buttons
self.editButton.set_sensitive(gtk.FALSE);
self.deleteButton.set_sensitive(gtk.FALSE);
def on_add_clicked (self, button):
# show the binding creation dialog
self.bindEditor.createBinding();
return;
def on_edit_clicked (self, button):
# tell the binding editor to edit this binding
self.bindEditor.editBinding(self.selection);
return;
def on_delete_clicked (self, button):
# remove the binding from the display and our bindings list
binding = self.bindings.bindings[self.selection];
self.bindList.remove(self.selection)
self.bindings.bindings.remove(binding);
self.selection = -1;
self.propsPanel.changed();
return;