]> Pileus Git - ~andy/gtk/commitdiff
Tue, 19 May 1998 11:51:02 +0200 Paolo Molaro <lupus@debian.org>
authorPaolo Molaro <lupus@src.gnome.org>
Tue, 19 May 1998 10:17:31 +0000 (10:17 +0000)
committerPaolo Molaro <lupus@src.gnome.org>
Tue, 19 May 1998 10:17:31 +0000 (10:17 +0000)
* added generic functions for completion in glib.
* used the above functions in the gtkcombo widget.

12 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
glib/ChangeLog
glib/Makefile.am
glib/gcompletion.c [new file with mode: 0644]
glib/glib.h
gtk/gtkcombo.c

index 95514a69ad726d1f07e8ad543035296a33ce8066..50dfcb49f3899d9373863e08d8e4819b551d999a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Tue, 19 May 1998 09:03:03 +0200  Paolo Molaro <lupus@debian.org>
+
+       * gtk/gtkcombo.c: implemented completion in the entry.
+
 1998-05-18    <sopwith@moebuis.labs.redhat.com>
 
        * gtk/gtk{debug.h,signal.c,main.c}: Allow GTK_DEBUG=signals
index 95514a69ad726d1f07e8ad543035296a33ce8066..50dfcb49f3899d9373863e08d8e4819b551d999a 100644 (file)
@@ -1,3 +1,7 @@
+Tue, 19 May 1998 09:03:03 +0200  Paolo Molaro <lupus@debian.org>
+
+       * gtk/gtkcombo.c: implemented completion in the entry.
+
 1998-05-18    <sopwith@moebuis.labs.redhat.com>
 
        * gtk/gtk{debug.h,signal.c,main.c}: Allow GTK_DEBUG=signals
index 95514a69ad726d1f07e8ad543035296a33ce8066..50dfcb49f3899d9373863e08d8e4819b551d999a 100644 (file)
@@ -1,3 +1,7 @@
+Tue, 19 May 1998 09:03:03 +0200  Paolo Molaro <lupus@debian.org>
+
+       * gtk/gtkcombo.c: implemented completion in the entry.
+
 1998-05-18    <sopwith@moebuis.labs.redhat.com>
 
        * gtk/gtk{debug.h,signal.c,main.c}: Allow GTK_DEBUG=signals
index 95514a69ad726d1f07e8ad543035296a33ce8066..50dfcb49f3899d9373863e08d8e4819b551d999a 100644 (file)
@@ -1,3 +1,7 @@
+Tue, 19 May 1998 09:03:03 +0200  Paolo Molaro <lupus@debian.org>
+
+       * gtk/gtkcombo.c: implemented completion in the entry.
+
 1998-05-18    <sopwith@moebuis.labs.redhat.com>
 
        * gtk/gtk{debug.h,signal.c,main.c}: Allow GTK_DEBUG=signals
index 95514a69ad726d1f07e8ad543035296a33ce8066..50dfcb49f3899d9373863e08d8e4819b551d999a 100644 (file)
@@ -1,3 +1,7 @@
+Tue, 19 May 1998 09:03:03 +0200  Paolo Molaro <lupus@debian.org>
+
+       * gtk/gtkcombo.c: implemented completion in the entry.
+
 1998-05-18    <sopwith@moebuis.labs.redhat.com>
 
        * gtk/gtk{debug.h,signal.c,main.c}: Allow GTK_DEBUG=signals
index 95514a69ad726d1f07e8ad543035296a33ce8066..50dfcb49f3899d9373863e08d8e4819b551d999a 100644 (file)
@@ -1,3 +1,7 @@
+Tue, 19 May 1998 09:03:03 +0200  Paolo Molaro <lupus@debian.org>
+
+       * gtk/gtkcombo.c: implemented completion in the entry.
+
 1998-05-18    <sopwith@moebuis.labs.redhat.com>
 
        * gtk/gtk{debug.h,signal.c,main.c}: Allow GTK_DEBUG=signals
index 95514a69ad726d1f07e8ad543035296a33ce8066..50dfcb49f3899d9373863e08d8e4819b551d999a 100644 (file)
@@ -1,3 +1,7 @@
+Tue, 19 May 1998 09:03:03 +0200  Paolo Molaro <lupus@debian.org>
+
+       * gtk/gtkcombo.c: implemented completion in the entry.
+
 1998-05-18    <sopwith@moebuis.labs.redhat.com>
 
        * gtk/gtk{debug.h,signal.c,main.c}: Allow GTK_DEBUG=signals
index 541430f3c3f90f575477dbd0d1489a10899522c6..adf2e3393e45b075c714f80224ce9cdf14b60489 100644 (file)
@@ -1,3 +1,7 @@
+Tue, 19 May 1998 09:00:02 +0200  Â§Paolo Molaro <lupus@debian.org>
+
+       * gcompletion.c: generic functions for com<TAB>pletion...
+
 Sun May 17 10:48:27 1998  Tim Janik  <timj@gtk.org>
 
        * gscanner.c (g_scanner_unexp_token): provide usefull default
index ef28c3e2f4aa61659e40ce98adb083eaf6522dc2..b2c617d7af9118dfb68b6f0bff832d639d469c0d 100644 (file)
@@ -7,6 +7,7 @@ lib_LTLIBRARIES = libglib-1.1.la
 libglib_1_1_la_SOURCES = \
                garray.c        \
                gcache.c        \
+               gcompletion.c   \
                gdataset.c      \
                gerror.c        \
                ghash.c         \
diff --git a/glib/gcompletion.c b/glib/gcompletion.c
new file mode 100644 (file)
index 0000000..947a6bd
--- /dev/null
@@ -0,0 +1,238 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "glib.h"
+#include <string.h>
+
+static void completion_check_cache (GCompletion* cmp, gchar** new_prefix);
+
+GCompletion* 
+g_completion_new (GCompletionFunc func) {
+       GCompletion* gcomp;
+
+       gcomp = g_new(GCompletion, 1);
+       gcomp->items = NULL;
+       gcomp->cache = NULL;
+       gcomp->prefix = NULL;
+       if ( func )
+               gcomp->func = func;
+       else
+               gcomp->func = NULL;
+       return gcomp;
+}
+
+void 
+g_completion_add_items (GCompletion* cmp, GList* items) {
+       GList* it;
+
+       g_return_if_fail( cmp != NULL);
+       g_return_if_fail( items != NULL);
+
+       /* optimize adding to cache? */
+       if ( cmp->cache ) {
+               g_list_free(cmp->cache);
+               cmp->cache = NULL;
+       }
+       if ( cmp->prefix ) {
+               g_free(cmp->prefix);
+               cmp->prefix = NULL;
+       }
+
+       it = items;
+       while ( it ) {
+               cmp->items = g_list_prepend(cmp->items, it->data);
+               it = it->next;
+       }
+}
+
+void 
+g_completion_remove_items (GCompletion* cmp, GList* items) {
+       GList* it;
+       
+       g_return_if_fail( cmp != NULL);
+       g_return_if_fail( items != NULL);
+
+       it = items;
+       while ( cmp->items && it ) {
+               cmp->items = g_list_remove(cmp->items, it->data);
+               it = it->next;
+       }
+       it = items;
+       while ( cmp->cache && it ) {
+               cmp->cache = g_list_remove(cmp->cache, it->data);
+               it = it->next;
+       }
+}
+
+void 
+g_completion_clear_items  (GCompletion* cmp) {
+       g_return_if_fail(cmp != NULL);
+
+       g_list_free(cmp->items);
+       cmp->items = NULL;
+       g_list_free(cmp->cache);
+       cmp->cache = NULL;
+       g_free(cmp->prefix);
+       cmp->prefix = NULL;
+}
+
+static void   
+completion_check_cache (GCompletion* cmp, gchar** new_prefix) {
+       register GList* list;
+       register gint len;
+       register gint i;
+       register gint plen;
+       gchar* postfix=NULL;
+       gchar* s;
+
+       if ( !new_prefix )
+               return;
+       if ( !cmp->cache ) {
+               *new_prefix = NULL;
+               return;
+       }
+
+       len = strlen(cmp->prefix);
+       list = cmp->cache;
+       s = cmp->func?(*cmp->func)(list->data):(gchar*)list->data;
+       postfix = s + len;
+       plen = strlen(postfix);
+       list = list->next;
+
+       while (list && plen) {
+               s = cmp->func?(*cmp->func)(list->data):(gchar*)list->data;
+               s += len;
+               for (i=0; i < plen; ++i) {
+                       if ( postfix[i] != s[i] ) 
+                               break;
+               }
+               plen = i;
+               list = list->next;
+       }
+
+       *new_prefix = g_new0(gchar, len+plen+1);
+       strncpy(*new_prefix, cmp->prefix, len);
+       strncpy(*new_prefix+len, postfix, plen);
+}
+
+GList* 
+g_completion_complete (GCompletion* cmp, gchar* prefix, gchar** new_prefix) {
+       gint plen, len;
+       gint done=0;
+       GList* list;
+       
+       g_return_val_if_fail(cmp != NULL, NULL);
+       g_return_val_if_fail(prefix != NULL, NULL);
+
+       len = strlen(prefix);
+       if ( cmp->prefix && cmp->cache ) {
+               plen = strlen(cmp->prefix);
+               if ( plen <= len && !strncmp(prefix, cmp->prefix, plen) ) { 
+                       /* use the cache */
+                       list = cmp->cache;
+                       while ( list ) {
+                               if ( strncmp(prefix, cmp->func?(*cmp->func)(list->data):(gchar*)list->data, len) ) {
+                                       list = g_list_remove_link(cmp->cache, list);
+                                       if ( list != cmp->cache )
+                                               cmp->cache = list;
+                               } else
+                                       list = list->next;
+                       }
+                       done = 1;
+               }
+       }
+
+       if (!done) { /* normal code */
+               g_list_free(cmp->cache);
+               cmp->cache = NULL;
+               list = cmp->items;
+               while (*prefix && list) {
+                       if ( !strncmp(prefix, cmp->func?(*cmp->func)(list->data):(gchar*)list->data, len) )
+                               cmp->cache = g_list_prepend(cmp->cache, list->data);
+                       list = list->next;
+               }
+       }
+       if ( cmp->prefix ) {
+               g_free(cmp->prefix);
+               cmp->prefix = NULL;
+       }
+       if ( cmp->cache )
+               cmp->prefix = g_strdup(prefix);
+       completion_check_cache(cmp, new_prefix);
+       return *prefix?cmp->cache:cmp->items;
+
+}
+
+void 
+g_completion_free (GCompletion* cmp) {
+       g_return_if_fail(cmp != NULL);
+
+       g_completion_clear_items(cmp);
+       g_free(cmp);
+}
+
+#ifdef TEST_COMPLETION
+
+#include <stdio.h>
+
+int main (int argc, char* argv[]) {
+
+       FILE * file;
+       gchar buf[1024];
+       GList *list;
+       GList *result;
+       GList *tmp;
+       GCompletion * cmp;
+       gint i;
+       gchar* longp=NULL;
+
+       if ( argc < 3 ) {
+               g_warning("Usage: %s filename prefix1 [prefix2 ...]\n", argv[0]);
+               return 1;
+       }
+
+       if ( !(file=fopen(argv[1], "r")) ) {
+               g_warning("Cannot open %s\n", argv[1]);
+               return 1;
+       }
+
+       cmp = g_completion_new(NULL);
+       list = g_list_alloc();
+       while (fgets(buf, 1024, file)) {
+               list->data = g_strdup(buf);
+               g_completion_add_items(cmp, list);
+       }
+       fclose(file);
+
+       for ( i= 2; i < argc; ++i) {
+               printf("COMPLETING: %s\n", argv[i]);
+               result = g_completion_complete(cmp, argv[i], &longp);
+               g_list_foreach(result, (GFunc)printf, NULL);
+               printf("LONG MATCH: %s\n", longp);
+               g_free(longp);
+               longp = NULL;
+       }
+
+       g_list_foreach(cmp->items, (GFunc)g_free, NULL);
+       g_completion_free(cmp);
+       g_list_free(list);
+       return 0;
+}
+
+#endif
index 282288c977991d8cccf866b31f89d26c186746d7..92fba23a5f0001dc528b0f812414a2fd954fc3f4 100644 (file)
@@ -1065,6 +1065,33 @@ void             g_scanner_warn                  (GScanner       *scanner,
 gint           g_scanner_stat_mode             (const gchar    *filename);
 
 
+/* Completion */
+
+typedef gchar* (*GCompletionFunc)(gpointer);
+
+typedef struct _GCompletion GCompletion;
+
+struct _GCompletion {
+       GList* items;
+       GCompletionFunc func;
+
+       gchar* prefix;
+       GList* cache;
+
+};
+
+GCompletion* g_completion_new          (GCompletionFunc func);
+void         g_completion_add_items    (GCompletion* cmp, 
+                                        GList* items);
+void         g_completion_remove_items (GCompletion* cmp, 
+                                        GList* items);
+void         g_completion_clear_items  (GCompletion* cmp);
+GList*       g_completion_complete     (GCompletion* cmp, 
+                                        gchar* prefix,
+                                        gchar** new_prefix);
+void         g_completion_free         (GCompletion* cmp);
+
+
 
 #ifdef __cplusplus
 }
index 0c2f7ccd49efa27bc25136cb681b5da43d815f82..8c8b3521c2a013f4c296b95ea611a3db59500f78 100644 (file)
@@ -117,11 +117,28 @@ gtk_combo_entry_key_press (GtkEntry * entry, GdkEventKey * event, GtkCombo * com
 {
   GList *li;
 
-  /* completion? */
-  /*if ( event->keyval == GDK_Tab ) {
-     gtk_signal_emit_stop_by_name (GTK_OBJECT (entry), "key_press_event");
-     return TRUE;
-     } else */
+  /* completion */
+  if ( event->keyval == GDK_Tab ) {
+    GCompletion * cmpl;
+    gchar* prefix;
+    gchar* nprefix = NULL;
+    guint pos;
+    
+    gtk_signal_emit_stop_by_name (GTK_OBJECT (entry), "key_press_event");
+    cmpl = g_completion_new((GCompletionFunc)gtk_combo_func);
+    g_completion_add_items(cmpl, GTK_LIST(combo->list)->children);
+    pos = GTK_EDITABLE(entry)->current_pos;
+    prefix = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, pos);
+    g_completion_complete(cmpl, prefix, &nprefix);
+    if ( nprefix && strlen(nprefix) > strlen(prefix) ) {
+       gtk_editable_insert_text(GTK_EDITABLE(entry), nprefix+pos, 
+               strlen(nprefix)-strlen(prefix), &pos);
+       GTK_EDITABLE(entry)->current_pos = pos;
+    }
+    g_free(prefix);
+    g_completion_free(cmpl);
+    return TRUE;
+  }
   if (!combo->use_arrows || !GTK_LIST (combo->list)->children)
     return FALSE;
   li = g_list_find (GTK_LIST (combo->list)->children, gtk_combo_find (combo));