GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-gtk-utils.c
1 /********************************************************************\
2  * gnc-gtk-utils.c -- utility functions based on glib functions *
3  * Copyright (C) 2006 David Hampton <[email protected]> *
4  * *
5  * This program is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU General Public License as *
7  * published by the Free Software Foundation; either version 2 of *
8  * the License, or (at your option) any later version. *
9  * *
10  * This program 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 *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License*
16  * along with this program; if not, contact: *
17  * *
18  * Free Software Foundation Voice: +1-617-542-5942 *
19  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
20  * Boston, MA 02110-1301, USA [email protected] *
21  * *
22 \********************************************************************/
23 
24 #include "config.h"
25 
26 #include "gnc-gtk-utils.h"
27 
28 #define LAST_INDEX "last_index"
29 #define CHANGED_ID "changed_id"
30 
31 
40 void
41 gnc_cbwe_set_by_string(GtkComboBox *cbwe,
42  const gchar *text)
43 {
44  GtkTreeModel *model;
45  GtkTreeIter iter;
46  gchar *tree_string;
47  gint column, index, id;
48  gboolean match;
49 
50  model = gtk_combo_box_get_model(GTK_COMBO_BOX(cbwe));
51  if (!gtk_tree_model_get_iter_first(model, &iter))
52  {
53  /* empty tree */
54  gtk_combo_box_set_active(GTK_COMBO_BOX(cbwe), -1);
55  return;
56  }
57 
58  column = gtk_combo_box_get_entry_text_column(cbwe);
59  do
60  {
61  gtk_tree_model_get(model, &iter, column, &tree_string, -1);
62  match = g_utf8_collate(text, tree_string) == 0;
63  g_free(tree_string);
64  if (!match)
65  continue;
66 
67  /* Found a matching string */
68  id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cbwe), CHANGED_ID));
69  g_signal_handler_block(cbwe, id);
70  gtk_combo_box_set_active_iter(GTK_COMBO_BOX(cbwe), &iter);
71  g_signal_handler_unblock(cbwe, id);
72 
73  index = gtk_combo_box_get_active(GTK_COMBO_BOX(cbwe));
74  g_object_set_data(G_OBJECT(cbwe), LAST_INDEX, GINT_TO_POINTER(index));
75  return;
76  }
77  while (gtk_tree_model_iter_next(model, &iter));
78 }
79 
80 
88 static void
89 gnc_cbwe_changed_cb (GtkComboBox *widget,
90  GtkComboBox *cbwe)
91 {
92  gint index;
93 
94  index = gtk_combo_box_get_active(widget);
95  if (index == -1)
96  return;
97  g_object_set_data(G_OBJECT(cbwe), LAST_INDEX, GINT_TO_POINTER(index));
98 }
99 
100 
117 static gboolean
118 gnc_cbwe_match_selected_cb (GtkEntryCompletion *completion,
119  GtkTreeModel *comp_model,
120  GtkTreeIter *comp_iter,
121  GtkComboBox *cbwe)
122 {
123  gint column;
124  gchar *text;
125 
126  column = gtk_combo_box_get_entry_text_column(cbwe);
127  gtk_tree_model_get(comp_model, comp_iter, column, &text, -1);
128  gnc_cbwe_set_by_string(cbwe, text);
129  g_free(text);
130  return FALSE;
131 }
132 
133 
146 static gboolean
147 gnc_cbwe_focus_out_cb (GtkEntry *entry,
148  GdkEventFocus *event,
149  GtkComboBox *cbwe)
150 {
151  const gchar *text;
152  gint index;
153 
154  /* Make a final attempt to match the current text. */
155  text = gtk_entry_get_text(entry);
156  gnc_cbwe_set_by_string(cbwe, text);
157 
158  /* Get the last known index (which may have just been set). */
159  index = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cbwe), LAST_INDEX));
160  gtk_combo_box_set_active(GTK_COMBO_BOX(cbwe), index);
161  return FALSE;
162 }
163 
164 void
165 gnc_cbwe_add_completion (GtkComboBox *cbwe)
166 {
167  GtkEntry *entry;
168  GtkEntryCompletion *completion;
169  GtkTreeModel *model;
170 
171  entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(cbwe)));
172  completion = gtk_entry_get_completion(entry);
173  if (completion)
174  return;
175 
176  /* No completion yet? Set one up. */
177  completion = gtk_entry_completion_new();
178  model = gtk_combo_box_get_model(GTK_COMBO_BOX(cbwe));
179  gtk_entry_completion_set_model(completion, model);
180  gtk_entry_completion_set_text_column(completion, 0);
181  gtk_entry_completion_set_inline_completion(completion, TRUE);
182  gtk_entry_set_completion(entry, completion);
183  g_object_unref(completion);
184 }
185 
186 void
187 gnc_cbwe_require_list_item (GtkComboBox *cbwe)
188 {
189  GtkEntry *entry;
190  GtkEntryCompletion *completion;
191  GtkTreeModel *model;
192  GtkTreeIter iter;
193  gint index, id;
194 
195  /* Ensure completion is set up. */
196  gnc_cbwe_add_completion(cbwe);
197 
198  /* If an item in the combo box isn't already selected, then force
199  * select the first item. Take care, the combo box may not have been
200  * filled yet. */
201  entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(cbwe)));
202  completion = gtk_entry_get_completion(entry);
203  index = gtk_combo_box_get_active(GTK_COMBO_BOX(cbwe));
204  if (index == -1)
205  {
206  model = gtk_entry_completion_get_model(completion);
207  if (gtk_tree_model_get_iter_first(model, &iter))
208  {
209  gtk_combo_box_set_active(GTK_COMBO_BOX(cbwe), 0);
210  index = 0;
211  }
212  }
213  g_object_set_data(G_OBJECT(cbwe), LAST_INDEX, GINT_TO_POINTER(index));
214 
215  /* Now the signals to make sure the user can't leave the
216  widget without a valid match. */
217  id = g_signal_connect(cbwe, "changed",
218  G_CALLBACK(gnc_cbwe_changed_cb), cbwe);
219  g_signal_connect(completion, "match_selected",
220  G_CALLBACK(gnc_cbwe_match_selected_cb), cbwe);
221  g_signal_connect(entry, "focus-out-event",
222  G_CALLBACK(gnc_cbwe_focus_out_cb), cbwe);
223 
224  g_object_set_data(G_OBJECT(cbwe), CHANGED_ID, GINT_TO_POINTER(id));
225 }
void gnc_cbwe_set_by_string(GtkComboBox *cbwe, const gchar *text)
Definition: gnc-gtk-utils.c:41
gtk helper routines.