diff --git a/projects/lookuplet/src/Makefile.am b/projects/lookuplet/src/Makefile.am index ba7fa6de..3801e8d2 100644 --- a/projects/lookuplet/src/Makefile.am +++ b/projects/lookuplet/src/Makefile.am @@ -1,5 +1,5 @@ # -# $Id: Makefile.am,v 1.4 2001/08/18 02:34:06 mdb Exp $ +# $Id: Makefile.am,v 1.5 2002/03/14 16:45:26 shaper Exp $ bin_PROGRAMS = lookuplet @@ -9,7 +9,8 @@ lookuplet_SOURCES = \ querybox.c \ preferences.c \ binding.c \ - keysym-util.c + keysym-util.c \ + history.c INCLUDES = \ -I. \ diff --git a/projects/lookuplet/src/c/history.c b/projects/lookuplet/src/c/history.c new file mode 100644 index 00000000..25b69db8 --- /dev/null +++ b/projects/lookuplet/src/c/history.c @@ -0,0 +1,118 @@ +/** + * $Id: history.c,v 1.1 2002/03/14 16:45:26 shaper 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 + */ + +#include + +#include "history.h" + +/* the array of historical entries */ +static gchar** _history; + +/* the last entry index retrieved */ +static int _ridx = 0; + +/* the insertion index for new history items */ +static int _iidx = 0; + +/* the number of entries saved in the text entry history */ +#define HISTORY_COUNT (10) + +void +lk_init_history (void) +{ + /* allocate and initialize the array of history entries */ + size_t size = sizeof(gchar*) * HISTORY_COUNT; + _history = g_malloc(size); + memset(_history, (int)NULL, size); +} + +const gchar* +lk_get_history (gboolean next) +{ + int actidx; + + /* make sure the array is available */ + if (_history == NULL) { + return NULL; + } + + /* determine the sought-after index */ + actidx = _ridx + ((next) ? -1 : 1); + + /* make sure the index is valid and an entry exists */ + if (actidx < 0 || actidx >= HISTORY_COUNT || _history[actidx] == NULL) { + return NULL; + } + + /* update the retrieved index */ + _ridx = actidx; + + return _history[actidx]; +} + +const gchar* +lk_get_history_expand (const gchar* entry) +{ + int i, len; + + if (_history == NULL || entry == NULL) { + return NULL; + } + + len = strlen(entry); + for (i = _iidx; i >= 0; i--) { + gchar* str = _history[i]; + if (str != NULL && !g_strncasecmp(str, entry, len)) { + /* update the retrieved index for potential subsequent retrievals */ + _ridx = i; + return str; + } + } + + return NULL; +} + +void +lk_add_history (const gchar* entry) +{ + /* make sure the array is available and the entry is valid */ + if (_history == NULL || entry == NULL) { + return; + } + + /* if there's no space remaining, shift off the oldest entry */ + if (_iidx == HISTORY_COUNT - 1 && _history[_iidx] != NULL) { + g_free(_history[0]); + memmove(_history, _history + 1, sizeof(gchar*) * (HISTORY_COUNT - 1)); + _history[_iidx] = NULL; + } + + /* remember the new entry */ + _history[_iidx] = g_strdup(entry); + + /* increment the insertion and retrieved index */ + if (_iidx < HISTORY_COUNT - 1) { + _iidx++; + _ridx = _iidx; + } else { + _ridx = HISTORY_COUNT; + } +} diff --git a/projects/lookuplet/src/c/history.h b/projects/lookuplet/src/c/history.h new file mode 100644 index 00000000..c87fb537 --- /dev/null +++ b/projects/lookuplet/src/c/history.h @@ -0,0 +1,59 @@ +/** + * $Id: history.h,v 1.1 2002/03/14 16:45:26 shaper 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 + */ + +#ifndef _HISTORY_H_ +#define _HISTORY_H_ + +#include + +/** + * Initializes the history storage. + */ +void +lk_init_history (void); + +/** + * Returns the next history entry if next is true, else returns the + * previous history entry. + */ +const gchar* +lk_get_history (gboolean next); + +/** + * Returns the most recent history entry that matches the specified + * partial entry text, or NULL if there are no matches. String + * comparisons are case-insensitive as this is intended for use in + * effecting auto-completion of sloppily-inputted partial entries. If a + * matching entry is found, the current history item index is set to point + * to that entry such that subsequent history entry retrievals will + * automagically pick up from that point. + */ +const gchar* +lk_get_history_expand (const gchar* entry); + +/** + * Adds an entry to the history and resets the current history item index + * to point to the new entry. + */ +void +lk_add_history (const gchar* entry); + +#endif /* _HISTORY_H_ */ diff --git a/projects/lookuplet/src/c/lookuplet.c b/projects/lookuplet/src/c/lookuplet.c index 66632bcc..8bbf7f07 100644 --- a/projects/lookuplet/src/c/lookuplet.c +++ b/projects/lookuplet/src/c/lookuplet.c @@ -1,5 +1,5 @@ /** - * $Id: lookuplet.c,v 1.6 2001/08/18 02:34:06 mdb Exp $ + * $Id: lookuplet.c,v 1.7 2002/03/14 16:45:26 shaper Exp $ * * lookuplet - a utility for quickly looking up information * Copyright (C) 2001 Michael Bayne @@ -84,7 +84,7 @@ main (int argc, char** argv) #endif if (applet_mode) { - /* intialize; this will basically set up the applet, corba and + /* initialize; this will basically set up the applet, corba and call gnome_init() */ applet_widget_init(PACKAGE, VERSION, argc, argv, NULL, 0, NULL); diff --git a/projects/lookuplet/src/c/querybox.c b/projects/lookuplet/src/c/querybox.c index e639b51d..707de17a 100644 --- a/projects/lookuplet/src/c/querybox.c +++ b/projects/lookuplet/src/c/querybox.c @@ -1,5 +1,5 @@ /** - * $Id: querybox.c,v 1.8 2001/08/21 18:46:10 mdb Exp $ + * $Id: querybox.c,v 1.9 2002/03/14 16:45:26 shaper Exp $ * * lookuplet - a utility for quickly looking up information * Copyright (C) 2001 Michael Bayne @@ -27,16 +27,25 @@ #include "binding.h" #include "launcher.h" +#include "history.h" #include "keysym-util.h" #include "preferences.h" #include "lookuplet.h" #include "querybox.h" +/* the query text entry field */ static GtkWidget* _query; /* used by url_p */ #define MATCH_PREFIX(text, prefix) !strncmp(text, prefix, sizeof(prefix)-1) +/* key codes for navigating the entry history */ +#define NEXT_HISTORY_KEY (GDK_Up) +#define PREVIOUS_HISTORY_KEY (GDK_Down) + +/* key code for auto-completion of a partial entry */ +#define AUTO_COMPLETE_KEY (GDK_Tab) + /** * A very primitive function to try to determine if the selection is a URL * of some sort. @@ -95,6 +104,41 @@ selection_received (GtkWidget* widget, GtkSelectionData* selection_data, } } +static gint +handle_special_keys (GtkWidget* widget, GdkEventKey* ek) +{ + const gchar* entry = NULL; + + switch (ek->keyval) { + case NEXT_HISTORY_KEY: + case PREVIOUS_HISTORY_KEY: + /* retrieve the sought-after historical entry */ + entry = lk_get_history(ek->keyval == NEXT_HISTORY_KEY); + break; + + case AUTO_COMPLETE_KEY: { + /* get the terms from the query box */ + gchar* text = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); + /* seek an expanded historical entry for the current text */ + entry = lk_get_history_expand(text); + } + break; + } + + /* if we've an entry, fill it in and we're done */ + if (entry != NULL) { + /* place the entry in the text field */ + gtk_entry_set_text(GTK_ENTRY(widget), entry); + + /* select the text in the entry so that it can be easily replaced */ + gtk_editable_select_region(GTK_EDITABLE(_query), 0, strlen(entry)); + + return TRUE; + } + + return FALSE; +} + static gint key_pressed (GtkWidget* widget, GdkEvent* event, gpointer callback_data) { @@ -103,6 +147,11 @@ key_pressed (GtkWidget* widget, GdkEvent* event, gpointer callback_data) gint handled = FALSE, i; gchar* keystr; + /* handle special keystrokes such as history and auto-complete */ + if (handle_special_keys(widget, ek)) { + return TRUE; + } + /* ignore plain or shifted keystrokes */ if (ek->state <= 1) { return FALSE; @@ -110,6 +159,9 @@ key_pressed (GtkWidget* widget, GdkEvent* event, gpointer callback_data) /* otherwise convert the key combo to a name and look it up */ keystr = convert_keysym_state_to_string(ek->keyval, ek->state); + if (keystr == NULL) { + return FALSE; + } bindings = lk_prefs_get_bindings(); for (i = 0; i < bindings->len; i++) { @@ -118,9 +170,11 @@ key_pressed (GtkWidget* widget, GdkEvent* event, gpointer callback_data) /* get the terms from the query box */ gchar* search_text = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); + /* save this entry in the history */ + lk_add_history(search_text); /* launch the appropriate thing */ lk_launcher_launch(binding, search_text); - g_free(search_text); + g_free(search_text); if (applet_mode) { /* clear out the contents of the entry box */ gtk_entry_set_text(GTK_ENTRY(widget), ""); @@ -151,9 +205,11 @@ launch (GtkWidget* widget, gpointer data) * instead of pressing some special key combination) */ gchar* search_text = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); lk_launcher_launch(NULL, search_text); - g_free(search_text); if (applet_mode) { + /* save this entry in the history */ + lk_add_history(search_text); + g_free(search_text); /* clear out the contents of the entry box */ gtk_entry_set_text(GTK_ENTRY(widget), ""); } else { @@ -195,6 +251,9 @@ lk_querybox_create (void) gtk_box_pack_start(GTK_BOX(hbox), prefs, FALSE, FALSE, 0); } + /* create the array of history commands */ + lk_init_history(); + return hbox; }