1 /* testentrycompletion.c
2  * Copyright (C) 2004  Red Hat, Inc.
3  * Author: Matthias Clasen
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 
21 #include "config.h"
22 #include <stdlib.h>
23 #include <string.h>
24 #include <gtk/gtk.h>
25 
26 #include "prop-editor.h"
27 
28 /* Don't copy this bad example; inline RGB data is always a better
29  * idea than inline XPMs.
30  */
31 static char  *book_closed_xpm[] = {
32 "16 16 6 1",
33 "       c None s None",
34 ".      c black",
35 "X      c red",
36 "o      c yellow",
37 "O      c #808080",
38 "#      c white",
39 "                ",
40 "       ..       ",
41 "     ..XX.      ",
42 "   ..XXXXX.     ",
43 " ..XXXXXXXX.    ",
44 ".ooXXXXXXXXX.   ",
45 "..ooXXXXXXXXX.  ",
46 ".X.ooXXXXXXXXX. ",
47 ".XX.ooXXXXXX..  ",
48 " .XX.ooXXX..#O  ",
49 "  .XX.oo..##OO. ",
50 "   .XX..##OO..  ",
51 "    .X.#OO..    ",
52 "     ..O..      ",
53 "      ..        ",
54 "                "
55 };
56 
57 static GtkWidget *window = NULL;
58 
59 
60 /* Creates a tree model containing the completions */
61 GtkTreeModel *
create_simple_completion_model(void)62 create_simple_completion_model (void)
63 {
64   GtkListStore *store;
65   GtkTreeIter iter;
66 
67   store = gtk_list_store_new (1, G_TYPE_STRING);
68 
69   gtk_list_store_append (store, &iter);
70   gtk_list_store_set (store, &iter, 0, "GNOME", -1);
71   gtk_list_store_append (store, &iter);
72   gtk_list_store_set (store, &iter, 0, "gnominious", -1);
73   gtk_list_store_append (store, &iter);
74   gtk_list_store_set (store, &iter, 0, "Gnomonic projection", -1);
75 
76   gtk_list_store_append (store, &iter);
77   gtk_list_store_set (store, &iter, 0, "total", -1);
78   gtk_list_store_append (store, &iter);
79   gtk_list_store_set (store, &iter, 0, "totally", -1);
80   gtk_list_store_append (store, &iter);
81   gtk_list_store_set (store, &iter, 0, "toto", -1);
82   gtk_list_store_append (store, &iter);
83   gtk_list_store_set (store, &iter, 0, "tottery", -1);
84   gtk_list_store_append (store, &iter);
85   gtk_list_store_set (store, &iter, 0, "totterer", -1);
86   gtk_list_store_append (store, &iter);
87   gtk_list_store_set (store, &iter, 0, "Totten trust", -1);
88   gtk_list_store_append (store, &iter);
89   gtk_list_store_set (store, &iter, 0, "totipotent", -1);
90   gtk_list_store_append (store, &iter);
91   gtk_list_store_set (store, &iter, 0, "totipotency", -1);
92   gtk_list_store_append (store, &iter);
93   gtk_list_store_set (store, &iter, 0, "totemism", -1);
94   gtk_list_store_append (store, &iter);
95   gtk_list_store_set (store, &iter, 0, "totem pole", -1);
96   gtk_list_store_append (store, &iter);
97   gtk_list_store_set (store, &iter, 0, "Totara", -1);
98   gtk_list_store_append (store, &iter);
99   gtk_list_store_set (store, &iter, 0, "totalizer", -1);
100   gtk_list_store_append (store, &iter);
101   gtk_list_store_set (store, &iter, 0, "totalizator", -1);
102   gtk_list_store_append (store, &iter);
103   gtk_list_store_set (store, &iter, 0, "totalitarianism", -1);
104   gtk_list_store_append (store, &iter);
105   gtk_list_store_set (store, &iter, 0, "total parenteral nutrition", -1);
106   gtk_list_store_append (store, &iter);
107   gtk_list_store_set (store, &iter, 0, "total hysterectomy", -1);
108   gtk_list_store_append (store, &iter);
109   gtk_list_store_set (store, &iter, 0, "total eclipse", -1);
110   gtk_list_store_append (store, &iter);
111   gtk_list_store_set (store, &iter, 0, "Totipresence", -1);
112   gtk_list_store_append (store, &iter);
113   gtk_list_store_set (store, &iter, 0, "Totipalmi", -1);
114   gtk_list_store_append (store, &iter);
115   gtk_list_store_set (store, &iter, 0, "zombie", -1);
116   gtk_list_store_append (store, &iter);
117   gtk_list_store_set (store, &iter, 0, "a\303\246x", -1);
118   gtk_list_store_append (store, &iter);
119   gtk_list_store_set (store, &iter, 0, "a\303\246y", -1);
120   gtk_list_store_append (store, &iter);
121   gtk_list_store_set (store, &iter, 0, "a\303\246z", -1);
122 
123   return GTK_TREE_MODEL (store);
124 }
125 
126 /* Creates a tree model containing the completions */
127 GtkTreeModel *
create_completion_model(void)128 create_completion_model (void)
129 {
130   GtkListStore *store;
131   GtkTreeIter iter;
132   GdkPixbuf *pixbuf;
133 
134   pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)book_closed_xpm);
135 
136   store = gtk_list_store_new (2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
137 
138   gtk_list_store_append (store, &iter);
139   gtk_list_store_set (store, &iter, 0, pixbuf, 1, "ambient", -1);
140   gtk_list_store_append (store, &iter);
141   gtk_list_store_set (store, &iter, 0, pixbuf, 1, "ambidextrously", -1);
142   gtk_list_store_append (store, &iter);
143   gtk_list_store_set (store, &iter, 0, pixbuf, 1, "ambidexter", -1);
144   gtk_list_store_append (store, &iter);
145   gtk_list_store_set (store, &iter, 0, pixbuf, 1, "ambiguity", -1);
146   gtk_list_store_append (store, &iter);
147   gtk_list_store_set (store, &iter, 0, pixbuf, 1, "American Party", -1);
148   gtk_list_store_append (store, &iter);
149   gtk_list_store_set (store, &iter, 0, pixbuf, 1, "American mountain ash", -1);
150   gtk_list_store_append (store, &iter);
151   gtk_list_store_set (store, &iter, 0, pixbuf, 1, "amelioration", -1);
152   gtk_list_store_append (store, &iter);
153   gtk_list_store_set (store, &iter, 0, pixbuf, 1, "Amelia Earhart", -1);
154   gtk_list_store_append (store, &iter);
155   gtk_list_store_set (store, &iter, 0, pixbuf, 1, "Totten trust", -1);
156   gtk_list_store_append (store, &iter);
157   gtk_list_store_set (store, &iter, 0, pixbuf, 1, "Laminated arch", -1);
158 
159   return GTK_TREE_MODEL (store);
160 }
161 
162 static gboolean
match_func(GtkEntryCompletion * completion,const gchar * key,GtkTreeIter * iter,gpointer user_data)163 match_func (GtkEntryCompletion *completion,
164 	    const gchar        *key,
165 	    GtkTreeIter        *iter,
166 	    gpointer            user_data)
167 {
168   gchar *item = NULL;
169   GtkTreeModel *model;
170 
171   gboolean ret = FALSE;
172 
173   model = gtk_entry_completion_get_model (completion);
174 
175   gtk_tree_model_get (model, iter, 1, &item, -1);
176 
177   if (item != NULL)
178     {
179       g_print ("compare %s %s\n", key, item);
180       if (strncmp (key, item, strlen (key)) == 0)
181 	ret = TRUE;
182 
183       g_free (item);
184     }
185 
186   return ret;
187 }
188 
189 static void
activated_cb(GtkEntryCompletion * completion,gint index,gpointer user_data)190 activated_cb (GtkEntryCompletion *completion,
191 	      gint                index,
192 	      gpointer            user_data)
193 {
194   g_print ("action activated: %d\n", index);
195 }
196 
197 static gint timer_count = 0;
198 
199 static gchar *dynamic_completions[] = {
200   "GNOME",
201   "gnominious",
202   "Gnomonic projection",
203   "total",
204   "totally",
205   "toto",
206   "tottery",
207   "totterer",
208   "Totten trust",
209   "totipotent",
210   "totipotency",
211   "totemism",
212   "totem pole",
213   "Totara",
214   "totalizer",
215   "totalizator",
216   "totalitarianism",
217   "total parenteral nutrition",
218   "total hysterectomy",
219   "total eclipse",
220   "Totipresence",
221   "Totipalmi",
222   "zombie"
223 };
224 
225 static gint
animation_timer(GtkEntryCompletion * completion)226 animation_timer (GtkEntryCompletion *completion)
227 {
228   GtkTreeIter iter;
229   gint n_completions = G_N_ELEMENTS (dynamic_completions);
230   gint n;
231   static GtkListStore *old_store = NULL;
232   GtkListStore *store = GTK_LIST_STORE (gtk_entry_completion_get_model (completion));
233 
234   if (timer_count % 10 == 0)
235     {
236       if (!old_store)
237 	{
238 	  g_print ("removing model!\n");
239 
240 	  old_store = g_object_ref (gtk_entry_completion_get_model (completion));
241 	  gtk_entry_completion_set_model (completion, NULL);
242 	}
243       else
244 	{
245 	  g_print ("readding model!\n");
246 
247 	  gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (old_store));
248 	  g_object_unref (old_store);
249 	  old_store = NULL;
250 	}
251 
252       timer_count ++;
253       return TRUE;
254     }
255 
256   if (!old_store)
257     {
258       if ((timer_count / n_completions) % 2 == 0)
259 	{
260 	  n = timer_count % n_completions;
261 	  gtk_list_store_append (store, &iter);
262 	  gtk_list_store_set (store, &iter, 0, dynamic_completions[n], -1);
263 
264 	}
265       else
266 	{
267 	  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
268 	    gtk_list_store_remove (store, &iter);
269 	}
270     }
271 
272   timer_count++;
273   return TRUE;
274 }
275 
276 gboolean
match_selected_cb(GtkEntryCompletion * completion,GtkTreeModel * model,GtkTreeIter * iter)277 match_selected_cb (GtkEntryCompletion *completion,
278 		   GtkTreeModel       *model,
279 		   GtkTreeIter        *iter)
280 {
281   gchar *str;
282   GtkWidget *entry;
283 
284   entry = gtk_entry_completion_get_entry (completion);
285   gtk_tree_model_get (GTK_TREE_MODEL (model), iter, 1, &str, -1);
286   gtk_entry_set_text (GTK_ENTRY (entry), str);
287   gtk_editable_set_position (GTK_EDITABLE (entry), -1);
288   g_free (str);
289 
290   return TRUE;
291 }
292 
293 static void
new_prop_editor(GObject * object)294 new_prop_editor (GObject *object)
295 {
296 	gtk_widget_show (create_prop_editor (object, G_OBJECT_TYPE (object)));
297 }
298 
299 static void
add_with_prop_edit_button(GtkWidget * vbox,GtkWidget * entry,GtkEntryCompletion * completion)300 add_with_prop_edit_button (GtkWidget *vbox, GtkWidget *entry, GtkEntryCompletion *completion)
301 {
302 	GtkWidget *hbox, *button;
303 
304 	hbox = gtk_hbox_new (FALSE, 12);
305 	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
306 
307 	gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
308 
309 	button = gtk_button_new_with_label ("Properties");
310 	g_signal_connect_swapped (button, "clicked", G_CALLBACK (new_prop_editor), completion);
311 	gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
312 }
313 
314 int
main(int argc,char * argv[])315 main (int argc, char *argv[])
316 {
317   GtkWidget *vbox;
318   GtkWidget *label;
319   GtkWidget *entry;
320   GtkEntryCompletion *completion;
321   GtkTreeModel *completion_model;
322   GtkCellRenderer *cell;
323 
324   gtk_init (&argc, &argv);
325 
326   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
327   gtk_container_set_border_width (GTK_CONTAINER (window), 5);
328   g_signal_connect (window, "delete_event", gtk_main_quit, NULL);
329 
330   vbox = gtk_vbox_new (FALSE, 2);
331   gtk_container_add (GTK_CONTAINER (window), vbox);
332 
333   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
334 
335   label = gtk_label_new (NULL);
336 
337   gtk_label_set_markup (GTK_LABEL (label), "Completion demo, try writing <b>total</b> or <b>gnome</b> for example.");
338   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
339 
340   /* Create our first entry */
341   entry = gtk_entry_new ();
342 
343   /* Create the completion object */
344   completion = gtk_entry_completion_new ();
345   gtk_entry_completion_set_inline_completion (completion, TRUE);
346 
347   /* Assign the completion to the entry */
348   gtk_entry_set_completion (GTK_ENTRY (entry), completion);
349   g_object_unref (completion);
350 
351   add_with_prop_edit_button (vbox, entry, completion);
352 
353   /* Create a tree model and use it as the completion model */
354   completion_model = create_simple_completion_model ();
355   gtk_entry_completion_set_model (completion, completion_model);
356   g_object_unref (completion_model);
357 
358   /* Use model column 0 as the text column */
359   gtk_entry_completion_set_text_column (completion, 0);
360 
361   /* Create our second entry */
362   entry = gtk_entry_new ();
363 
364   /* Create the completion object */
365   completion = gtk_entry_completion_new ();
366 
367   /* Assign the completion to the entry */
368   gtk_entry_set_completion (GTK_ENTRY (entry), completion);
369   g_object_unref (completion);
370 
371   add_with_prop_edit_button (vbox, entry, completion);
372 
373   /* Create a tree model and use it as the completion model */
374   completion_model = create_completion_model ();
375   gtk_entry_completion_set_model (completion, completion_model);
376   gtk_entry_completion_set_minimum_key_length (completion, 2);
377   g_object_unref (completion_model);
378 
379   /* Use model column 1 as the text column */
380   cell = gtk_cell_renderer_pixbuf_new ();
381   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), cell, FALSE);
382   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (completion), cell,
383 				  "pixbuf", 0, NULL);
384 
385   cell = gtk_cell_renderer_text_new ();
386   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), cell, FALSE);
387   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (completion), cell,
388 				  "text", 1, NULL);
389 
390   gtk_entry_completion_set_match_func (completion, match_func, NULL, NULL);
391   g_signal_connect (completion, "match-selected",
392 		    G_CALLBACK (match_selected_cb), NULL);
393 
394   gtk_entry_completion_insert_action_text (completion, 100, "action!");
395   gtk_entry_completion_insert_action_text (completion, 101, "'nother action!");
396   g_signal_connect (completion, "action_activated", G_CALLBACK (activated_cb), NULL);
397 
398   /* Create our third entry */
399   entry = gtk_entry_new ();
400 
401   /* Create the completion object */
402   completion = gtk_entry_completion_new ();
403 
404   /* Assign the completion to the entry */
405   gtk_entry_set_completion (GTK_ENTRY (entry), completion);
406   g_object_unref (completion);
407 
408   add_with_prop_edit_button (vbox, entry, completion);
409 
410   /* Create a tree model and use it as the completion model */
411   completion_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
412 
413   gtk_entry_completion_set_model (completion, completion_model);
414   g_object_unref (completion_model);
415 
416   /* Use model column 0 as the text column */
417   gtk_entry_completion_set_text_column (completion, 0);
418 
419   /* Fill the completion dynamically */
420   gdk_threads_add_timeout (1000, (GSourceFunc) animation_timer, completion);
421 
422   /* Fourth entry */
423   gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("Model-less entry completion"), FALSE, FALSE, 0);
424 
425   entry = gtk_entry_new ();
426 
427   /* Create the completion object */
428   completion = gtk_entry_completion_new ();
429 
430   /* Assign the completion to the entry */
431   gtk_entry_set_completion (GTK_ENTRY (entry), completion);
432   g_object_unref (completion);
433 
434   add_with_prop_edit_button (vbox, entry, completion);
435 
436   gtk_widget_show_all (window);
437 
438   gtk_main ();
439 
440   return 0;
441 }
442 
443 
444