1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
2 *
3 * This file is part of GtkSourceView
4 *
5 * Copyright (C) 2007 - Jesús Barbero Rodríguez <chuchiperriman@gmail.com>
6 * Copyright (C) 2013 - Sébastien Wilmet <swilmet@gnome.org>
7 *
8 * GtkSourceView is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * GtkSourceView is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <gtk/gtk.h>
23 #include <gtksourceview/gtksource.h>
24
25 typedef struct _TestProvider TestProvider;
26 typedef struct _TestProviderClass TestProviderClass;
27
28 static GtkSourceCompletionWords *word_provider;
29 static TestProvider *fixed_provider;
30 static TestProvider *random_provider;
31
32 struct _TestProvider
33 {
34 GObject parent;
35
36 GList *proposals;
37 gint priority;
38 gchar *name;
39
40 GdkPixbuf *provider_icon;
41
42 GdkPixbuf *item_icon;
43 GIcon *item_gicon;
44
45 /* If it's a random provider, a subset of 'proposals' are choosen on
46 * each populate. Otherwise, all the proposals are shown. */
47 guint is_random : 1;
48 };
49
50 struct _TestProviderClass
51 {
52 GObjectClass parent_class;
53 };
54
55 static void test_provider_iface_init (GtkSourceCompletionProviderIface *iface);
56 GType test_provider_get_type (void);
57
G_DEFINE_TYPE_WITH_CODE(TestProvider,test_provider,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (GTK_SOURCE_TYPE_COMPLETION_PROVIDER,test_provider_iface_init))58 G_DEFINE_TYPE_WITH_CODE (TestProvider,
59 test_provider,
60 G_TYPE_OBJECT,
61 G_IMPLEMENT_INTERFACE (GTK_SOURCE_TYPE_COMPLETION_PROVIDER,
62 test_provider_iface_init))
63
64 static gchar *
65 test_provider_get_name (GtkSourceCompletionProvider *provider)
66 {
67 return g_strdup (((TestProvider *)provider)->name);
68 }
69
70 static gint
test_provider_get_priority(GtkSourceCompletionProvider * provider)71 test_provider_get_priority (GtkSourceCompletionProvider *provider)
72 {
73 return ((TestProvider *)provider)->priority;
74 }
75
76 static GList *
select_random_proposals(GList * all_proposals)77 select_random_proposals (GList *all_proposals)
78 {
79 GList *selection = NULL;
80 GList *prop;
81
82 for (prop = all_proposals; prop != NULL; prop = g_list_next (prop))
83 {
84 if (g_random_boolean ())
85 {
86 selection = g_list_prepend (selection, prop->data);
87 }
88 }
89
90 return selection;
91 }
92
93 static void
test_provider_populate(GtkSourceCompletionProvider * completion_provider,GtkSourceCompletionContext * context)94 test_provider_populate (GtkSourceCompletionProvider *completion_provider,
95 GtkSourceCompletionContext *context)
96 {
97 TestProvider *provider = (TestProvider *)completion_provider;
98 GList *proposals;
99
100 if (provider->is_random)
101 {
102 proposals = select_random_proposals (provider->proposals);
103 }
104 else
105 {
106 proposals = provider->proposals;
107 }
108
109 gtk_source_completion_context_add_proposals (context,
110 completion_provider,
111 proposals,
112 TRUE);
113 }
114
115 static GdkPixbuf *
test_provider_get_icon(GtkSourceCompletionProvider * provider)116 test_provider_get_icon (GtkSourceCompletionProvider *provider)
117 {
118 TestProvider *tp = (TestProvider *)provider;
119
120 return tp->is_random ? NULL : tp->provider_icon;
121 }
122
123 static void
test_provider_iface_init(GtkSourceCompletionProviderIface * iface)124 test_provider_iface_init (GtkSourceCompletionProviderIface *iface)
125 {
126 iface->get_name = test_provider_get_name;
127 iface->populate = test_provider_populate;
128 iface->get_priority = test_provider_get_priority;
129 iface->get_icon = test_provider_get_icon;
130 }
131
132 static void
test_provider_dispose(GObject * gobject)133 test_provider_dispose (GObject *gobject)
134 {
135 TestProvider *self = (TestProvider *)gobject;
136
137 g_list_free_full (self->proposals, g_object_unref);
138 self->proposals = NULL;
139
140 g_clear_object (&self->provider_icon);
141 g_clear_object (&self->item_icon);
142 g_clear_object (&self->item_gicon);
143
144 G_OBJECT_CLASS (test_provider_parent_class)->dispose (gobject);
145 }
146
147 static void
test_provider_finalize(GObject * gobject)148 test_provider_finalize (GObject *gobject)
149 {
150 TestProvider *self = (TestProvider *)gobject;
151
152 g_free (self->name);
153 self->name = NULL;
154
155 G_OBJECT_CLASS (test_provider_parent_class)->finalize (gobject);
156 }
157
158 static void
test_provider_class_init(TestProviderClass * klass)159 test_provider_class_init (TestProviderClass *klass)
160 {
161 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
162
163 gobject_class->dispose = test_provider_dispose;
164 gobject_class->finalize = test_provider_finalize;
165 }
166
167 static void
test_provider_init(TestProvider * self)168 test_provider_init (TestProvider *self)
169 {
170 GtkIconTheme *theme;
171 GIcon *icon;
172 GIcon *emblem_icon;
173 GEmblem *emblem;
174
175 theme = gtk_icon_theme_get_default ();
176 self->provider_icon = gtk_icon_theme_load_icon (theme, "dialog-information", 16, 0, NULL);
177
178 self->item_icon = gtk_icon_theme_load_icon (theme, "trophy-gold", 16, 0, NULL);
179
180 icon = g_themed_icon_new ("trophy-silver");
181 emblem_icon = g_themed_icon_new ("emblem-urgent");
182 emblem = g_emblem_new (emblem_icon);
183 self->item_gicon = g_emblemed_icon_new (icon, emblem);
184 g_object_unref (icon);
185 g_object_unref (emblem_icon);
186 g_object_unref (emblem);
187 }
188
189 static void
test_provider_set_fixed(TestProvider * provider,gint nb_proposals)190 test_provider_set_fixed (TestProvider *provider,
191 gint nb_proposals)
192 {
193 GtkSourceCompletionItem *item;
194 GList *proposals = NULL;
195 gint i;
196
197 g_list_free_full (provider->proposals, g_object_unref);
198
199 item = gtk_source_completion_item_new ();
200 gtk_source_completion_item_set_markup (item, "A very <b>long</b> proposal. I <i>repeat</i>, a very long proposal!");
201 gtk_source_completion_item_set_text (item, "A very long proposal. I repeat, a very long proposal!");
202 gtk_source_completion_item_set_icon (item, provider->item_icon);
203 gtk_source_completion_item_set_info (item, "To test the horizontal scrollbar and the markup.");
204 proposals = g_list_prepend (proposals, item);
205
206 item = gtk_source_completion_item_new ();
207 gtk_source_completion_item_set_markup (item, "A proposal with a <b>symbolic</b> icon");
208 gtk_source_completion_item_set_text (item, "Test setting the icon-name property");
209 gtk_source_completion_item_set_icon_name (item, "face-cool-symbolic");
210 proposals = g_list_prepend (proposals, item);
211
212 item = gtk_source_completion_item_new ();
213 gtk_source_completion_item_set_markup (item, "A proposal with an emblem <b>GIcon</b>");
214 gtk_source_completion_item_set_text (item, "Test setting the GIcon property");
215 gtk_source_completion_item_set_gicon (item, provider->item_gicon);
216 proposals = g_list_prepend (proposals, item);
217
218 for (i = nb_proposals - 1; i > 0; i--)
219 {
220 gchar *name = g_strdup_printf ("Proposal %d", i);
221
222 item = gtk_source_completion_item_new ();
223 gtk_source_completion_item_set_label (item, name);
224 gtk_source_completion_item_set_text (item, name);
225 gtk_source_completion_item_set_icon (item, provider->item_icon);
226 gtk_source_completion_item_set_info (item, "The extra info of the proposal.\nA second line.");
227 proposals = g_list_prepend (proposals, item);
228
229 g_free (name);
230 }
231
232 provider->proposals = proposals;
233 provider->is_random = 0;
234 }
235
236 static void
test_provider_set_random(TestProvider * provider,gint nb_proposals)237 test_provider_set_random (TestProvider *provider,
238 gint nb_proposals)
239 {
240 GList *proposals = NULL;
241 gint i;
242
243 g_list_free_full (provider->proposals, g_object_unref);
244
245 for (i = 0; i < nb_proposals; i++)
246 {
247 GtkSourceCompletionItem *item;
248 gchar *padding = g_strnfill ((i * 3) % 10, 'o');
249 gchar *name = g_strdup_printf ("Propo%ssal %d", padding, i);
250
251 item = gtk_source_completion_item_new ();
252 gtk_source_completion_item_set_label (item, name);
253 gtk_source_completion_item_set_text (item, name);
254 gtk_source_completion_item_set_icon (item, provider->item_icon);
255 proposals = g_list_prepend (proposals, item);
256
257 g_free (padding);
258 g_free (name);
259 }
260
261 provider->proposals = proposals;
262 provider->is_random = 1;
263 }
264
265 static void
add_remove_provider(GtkToggleButton * button,GtkSourceCompletion * completion,GtkSourceCompletionProvider * provider)266 add_remove_provider (GtkToggleButton *button,
267 GtkSourceCompletion *completion,
268 GtkSourceCompletionProvider *provider)
269 {
270 g_return_if_fail (provider != NULL);
271
272 if (gtk_toggle_button_get_active (button))
273 {
274 gtk_source_completion_add_provider (completion, provider, NULL);
275 }
276 else
277 {
278 gtk_source_completion_remove_provider (completion, provider, NULL);
279 }
280 }
281
282 static void
enable_word_provider_toggled_cb(GtkToggleButton * button,GtkSourceCompletion * completion)283 enable_word_provider_toggled_cb (GtkToggleButton *button,
284 GtkSourceCompletion *completion)
285 {
286 add_remove_provider (button,
287 completion,
288 GTK_SOURCE_COMPLETION_PROVIDER (word_provider));
289 }
290
291 static void
enable_fixed_provider_toggled_cb(GtkToggleButton * button,GtkSourceCompletion * completion)292 enable_fixed_provider_toggled_cb (GtkToggleButton *button,
293 GtkSourceCompletion *completion)
294 {
295 add_remove_provider (button,
296 completion,
297 GTK_SOURCE_COMPLETION_PROVIDER (fixed_provider));
298 }
299
300 static void
enable_random_provider_toggled_cb(GtkToggleButton * button,GtkSourceCompletion * completion)301 enable_random_provider_toggled_cb (GtkToggleButton *button,
302 GtkSourceCompletion *completion)
303 {
304 add_remove_provider (button,
305 completion,
306 GTK_SOURCE_COMPLETION_PROVIDER (random_provider));
307 }
308
309 static void
nb_proposals_changed_cb(GtkSpinButton * spin_button,TestProvider * provider)310 nb_proposals_changed_cb (GtkSpinButton *spin_button,
311 TestProvider *provider)
312 {
313 gint nb_proposals = gtk_spin_button_get_value_as_int (spin_button);
314
315 if (provider->is_random)
316 {
317 test_provider_set_random (provider, nb_proposals);
318 }
319 else
320 {
321 test_provider_set_fixed (provider, nb_proposals);
322 }
323 }
324
325 static void
create_completion(GtkSourceView * source_view,GtkSourceCompletion * completion)326 create_completion (GtkSourceView *source_view,
327 GtkSourceCompletion *completion)
328 {
329 /* Words completion provider */
330 word_provider = gtk_source_completion_words_new (NULL, NULL);
331
332 gtk_source_completion_words_register (word_provider,
333 gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view)));
334
335 gtk_source_completion_add_provider (completion,
336 GTK_SOURCE_COMPLETION_PROVIDER (word_provider),
337 NULL);
338
339 g_object_set (word_provider, "priority", 10, NULL);
340
341 /* Fixed provider: the proposals don't change */
342 fixed_provider = g_object_new (test_provider_get_type (), NULL);
343 test_provider_set_fixed (fixed_provider, 3);
344 fixed_provider->priority = 5;
345 fixed_provider->name = g_strdup ("Fixed Provider");
346
347 gtk_source_completion_add_provider (completion,
348 GTK_SOURCE_COMPLETION_PROVIDER (fixed_provider),
349 NULL);
350
351 /* Random provider: the proposals vary on each populate */
352 random_provider = g_object_new (test_provider_get_type (), NULL);
353 test_provider_set_random (random_provider, 10);
354 random_provider->priority = 1;
355 random_provider->name = g_strdup ("Random Provider");
356
357 gtk_source_completion_add_provider (completion,
358 GTK_SOURCE_COMPLETION_PROVIDER (random_provider),
359 NULL);
360 }
361
362 static void
create_window(void)363 create_window (void)
364 {
365 GtkBuilder *builder;
366 GError *error = NULL;
367 GtkWindow *window;
368 GtkSourceView *source_view;
369 GtkSourceCompletion *completion;
370 GtkCheckButton *remember_info_visibility;
371 GtkCheckButton *select_on_show;
372 GtkCheckButton *show_headers;
373 GtkCheckButton *show_icons;
374 GtkCheckButton *enable_word_provider;
375 GtkCheckButton *enable_fixed_provider;
376 GtkCheckButton *enable_random_provider;
377 GtkSpinButton *nb_fixed_proposals;
378 GtkSpinButton *nb_random_proposals;
379
380 builder = gtk_builder_new ();
381
382 gtk_builder_add_from_resource (builder,
383 "/org/gnome/gtksourceview/tests/ui/test-completion.ui",
384 &error);
385
386 if (error != NULL)
387 {
388 g_error ("Impossible to load test-completion.ui: %s", error->message);
389 }
390
391 window = GTK_WINDOW (gtk_builder_get_object (builder, "window"));
392 source_view = GTK_SOURCE_VIEW (gtk_builder_get_object (builder, "source_view"));
393 remember_info_visibility = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, "checkbutton_remember_info_visibility"));
394 select_on_show = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, "checkbutton_select_on_show"));
395 show_headers = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, "checkbutton_show_headers"));
396 show_icons = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, "checkbutton_show_icons"));
397 enable_word_provider = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, "checkbutton_word_provider"));
398 enable_fixed_provider = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, "checkbutton_fixed_provider"));
399 enable_random_provider = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, "checkbutton_random_provider"));
400 nb_fixed_proposals = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "spinbutton_nb_fixed_proposals"));
401 nb_random_proposals = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "spinbutton_nb_random_proposals"));
402
403 completion = gtk_source_view_get_completion (source_view);
404
405 g_signal_connect (window,
406 "destroy",
407 G_CALLBACK (gtk_main_quit),
408 NULL);
409
410 g_object_bind_property (completion, "remember-info-visibility",
411 remember_info_visibility, "active",
412 G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
413
414 g_object_bind_property (completion, "select-on-show",
415 select_on_show, "active",
416 G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
417
418 g_object_bind_property (completion, "show-headers",
419 show_headers, "active",
420 G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
421
422 g_object_bind_property (completion, "show-icons",
423 show_icons, "active",
424 G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
425
426 create_completion (source_view, completion);
427
428 g_signal_connect (enable_word_provider,
429 "toggled",
430 G_CALLBACK (enable_word_provider_toggled_cb),
431 completion);
432
433 g_signal_connect (enable_fixed_provider,
434 "toggled",
435 G_CALLBACK (enable_fixed_provider_toggled_cb),
436 completion);
437
438 g_signal_connect (enable_random_provider,
439 "toggled",
440 G_CALLBACK (enable_random_provider_toggled_cb),
441 completion);
442
443 g_signal_connect (nb_fixed_proposals,
444 "value-changed",
445 G_CALLBACK (nb_proposals_changed_cb),
446 fixed_provider);
447
448 g_signal_connect (nb_random_proposals,
449 "value-changed",
450 G_CALLBACK (nb_proposals_changed_cb),
451 random_provider);
452
453 g_object_unref (builder);
454 }
455
456 int
main(int argc,char * argv[])457 main (int argc, char *argv[])
458 {
459 gtk_init (&argc, &argv);
460
461 create_window ();
462
463 gtk_main ();
464
465 /* Not really useful, except for debugging memory leaks. */
466 g_object_unref (word_provider);
467 g_object_unref (fixed_provider);
468 g_object_unref (random_provider);
469
470 return 0;
471 }
472