1 /* gdict-source-chooser.h - display widget for dictionary sources
2  *
3  * Copyright (C) 2007  Emmanuele Bassi <ebassi@gnome.org>
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 Lesser General Public License
16  * along with this library. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /**
20  * SECTION:gdict-source-chooser
21  * @short_description: Display the list of available sources
22  *
23  * #GdictSourceChooser is a widget that shows the list of available
24  * dictionary sources using a #GdictSourceLoader instance as a model.
25  * It can be used to allow choosing the current dictionary source.
26  *
27  * #GdictSourceChooser is available since Gdict 0.12.
28  */
29 
30 #include "config.h"
31 
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include <glib/gi18n-lib.h>
36 
37 #include <gdk/gdk.h>
38 
39 #include <gtk/gtk.h>
40 
41 #include "gdict-source-chooser.h"
42 #include "gdict-utils.h"
43 #include "gdict-private.h"
44 #include "gdict-enum-types.h"
45 #include "gdict-marshal.h"
46 
47 struct _GdictSourceChooserPrivate
48 {
49   GtkListStore *store;
50 
51   GtkWidget *treeview;
52   GtkWidget *refresh_button;
53   GtkWidget *buttons_box;
54 
55   GdictSourceLoader *loader;
56   gint n_sources;
57 
58   gchar *current_source;
59 };
60 
61 enum
62 {
63   SOURCE_TRANSPORT,
64   SOURCE_NAME,
65   SOURCE_DESCRIPTION,
66   SOURCE_CURRENT,
67 
68   SOURCE_N_COLUMNS
69 };
70 
71 enum
72 {
73   PROP_0,
74 
75   PROP_LOADER,
76   PROP_COUNT
77 };
78 
79 enum
80 {
81   SOURCE_ACTIVATED,
82   SELECTION_CHANGED,
83 
84   LAST_SIGNAL
85 };
86 
87 static guint source_chooser_signals[LAST_SIGNAL] = { 0, };
88 
G_DEFINE_TYPE_WITH_PRIVATE(GdictSourceChooser,gdict_source_chooser,GTK_TYPE_BOX)89 G_DEFINE_TYPE_WITH_PRIVATE (GdictSourceChooser, gdict_source_chooser, GTK_TYPE_BOX)
90 
91 static void
92 gdict_source_chooser_finalize (GObject *gobject)
93 {
94   GdictSourceChooser *chooser = GDICT_SOURCE_CHOOSER (gobject);
95   GdictSourceChooserPrivate *priv = chooser->priv;
96 
97   g_free (priv->current_source);
98 
99   G_OBJECT_CLASS (gdict_source_chooser_parent_class)->finalize (gobject);
100 }
101 
102 static void
gdict_source_chooser_dispose(GObject * gobject)103 gdict_source_chooser_dispose (GObject *gobject)
104 {
105   GdictSourceChooser *chooser = GDICT_SOURCE_CHOOSER (gobject);
106   GdictSourceChooserPrivate *priv = chooser->priv;
107 
108   if (priv->store)
109     {
110       g_object_unref (priv->store);
111       priv->store = NULL;
112     }
113 
114   if (priv->loader)
115     {
116       g_object_unref (priv->loader);
117       priv->loader = NULL;
118     }
119 
120   G_OBJECT_CLASS (gdict_source_chooser_parent_class)->dispose (gobject);
121 }
122 
123 static void
gdict_source_chooser_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * pspec)124 gdict_source_chooser_set_property (GObject      *gobject,
125                                    guint         prop_id,
126                                    const GValue *value,
127                                    GParamSpec   *pspec)
128 {
129   switch (prop_id)
130     {
131     case PROP_LOADER:
132       gdict_source_chooser_set_loader (GDICT_SOURCE_CHOOSER (gobject),
133                                        g_value_get_object (value));
134       break;
135     default:
136       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
137       break;
138     }
139 }
140 
141 static void
gdict_source_chooser_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * pspec)142 gdict_source_chooser_get_property (GObject    *gobject,
143                                    guint       prop_id,
144                                    GValue     *value,
145                                    GParamSpec *pspec)
146 {
147   GdictSourceChooserPrivate *priv;
148 
149   priv = GDICT_SOURCE_CHOOSER (gobject)->priv;
150 
151   switch (prop_id)
152     {
153     case PROP_LOADER:
154       g_value_set_object (value, priv->loader);
155       break;
156     case PROP_COUNT:
157       g_value_set_int (value, priv->n_sources);
158       break;
159     default:
160       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
161       break;
162     }
163 }
164 
165 static void
row_activated_cb(GtkTreeView * treeview,GtkTreePath * path,GtkTreeViewColumn * column,gpointer data)166 row_activated_cb (GtkTreeView       *treeview,
167                   GtkTreePath       *path,
168                   GtkTreeViewColumn *column,
169                   gpointer           data)
170 {
171   GdictSourceChooser *chooser = GDICT_SOURCE_CHOOSER (data);
172   GdictSourceChooserPrivate *priv = chooser->priv;
173   GtkTreeIter iter;
174   gchar *name;
175   GdictSource *source;
176 
177   if (!priv->loader)
178     return;
179 
180   if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path))
181     return;
182 
183   gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
184                       SOURCE_NAME, &name,
185                       -1);
186   if (!name)
187     return;
188 
189   source = gdict_source_loader_get_source (priv->loader, name);
190   if (!source)
191     {
192       g_free (name);
193       return;
194     }
195 
196   g_signal_emit (chooser, source_chooser_signals[SOURCE_ACTIVATED], 0,
197                  name, source);
198 
199   g_free (name);
200   g_object_unref (source);
201 }
202 
203 static void
refresh_button_clicked_cb(GtkButton * button,gpointer data)204 refresh_button_clicked_cb (GtkButton *button,
205                            gpointer   data)
206 {
207   gdict_source_chooser_refresh (GDICT_SOURCE_CHOOSER (data));
208 }
209 
210 static void
selection_changed_cb(GtkTreeSelection * selection,gpointer data)211 selection_changed_cb (GtkTreeSelection *selection,
212                       gpointer          data)
213 {
214   g_signal_emit (data, source_chooser_signals[SELECTION_CHANGED], 0);
215 }
216 
217 static GObject *
gdict_source_chooser_constructor(GType gtype,guint n_params,GObjectConstructParam * params)218 gdict_source_chooser_constructor (GType                  gtype,
219                                   guint                  n_params,
220                                   GObjectConstructParam *params)
221 {
222   GdictSourceChooser *chooser;
223   GdictSourceChooserPrivate *priv;
224   GObjectClass *parent_class;
225   GObject *retval;
226   GtkWidget *sw;
227   GtkCellRenderer *renderer;
228   GtkTreeViewColumn *column;
229   GtkWidget *hbox;
230 
231   parent_class = G_OBJECT_CLASS (gdict_source_chooser_parent_class);
232   retval = parent_class->constructor (gtype, n_params, params);
233 
234   chooser = GDICT_SOURCE_CHOOSER (retval);
235   priv = chooser->priv;
236 
237   sw = gtk_scrolled_window_new (NULL, NULL);
238   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
239                                   GTK_POLICY_AUTOMATIC,
240                                   GTK_POLICY_AUTOMATIC);
241   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
242                                        GTK_SHADOW_IN);
243   gtk_box_pack_start (GTK_BOX (chooser), sw, TRUE, TRUE, 0);
244   gtk_widget_show (sw);
245 
246   renderer = gtk_cell_renderer_text_new ();
247   column = gtk_tree_view_column_new_with_attributes ("sources",
248                                                      renderer,
249                                                      "text", SOURCE_DESCRIPTION,
250                                                      "weight", SOURCE_CURRENT,
251                                                      NULL);
252   priv->treeview = gtk_tree_view_new ();
253   gtk_tree_view_set_model (GTK_TREE_VIEW (priv->treeview),
254                            GTK_TREE_MODEL (priv->store));
255   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->treeview), FALSE);
256   gtk_tree_view_append_column (GTK_TREE_VIEW (priv->treeview), column);
257   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview)),
258                     "changed", G_CALLBACK (selection_changed_cb),
259                     chooser);
260   g_signal_connect (priv->treeview,
261                     "row-activated", G_CALLBACK (row_activated_cb),
262                     chooser);
263   gtk_container_add (GTK_CONTAINER (sw), priv->treeview);
264   gtk_widget_show (priv->treeview);
265 
266   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
267   priv->buttons_box = hbox;
268 
269   priv->refresh_button = gtk_button_new ();
270   gtk_button_set_image (GTK_BUTTON (priv->refresh_button),
271                         gtk_image_new_from_icon_name ("view-refresh-symbolic", GTK_ICON_SIZE_BUTTON));
272   g_signal_connect (priv->refresh_button,
273                     "clicked", G_CALLBACK (refresh_button_clicked_cb),
274                     chooser);
275   gtk_box_pack_start (GTK_BOX (hbox), priv->refresh_button, FALSE, FALSE, 0);
276   gtk_widget_show (priv->refresh_button);
277   gtk_widget_set_tooltip_text (priv->refresh_button,
278                                _("Reload the list of available sources"));
279 
280   gtk_box_pack_end (GTK_BOX (chooser), hbox, FALSE, FALSE, 0);
281   gtk_widget_show (hbox);
282 
283   return retval;
284 }
285 
286 static void
gdict_source_chooser_class_init(GdictSourceChooserClass * klass)287 gdict_source_chooser_class_init (GdictSourceChooserClass *klass)
288 {
289   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
290 
291   gobject_class->finalize = gdict_source_chooser_finalize;
292   gobject_class->dispose = gdict_source_chooser_dispose;
293   gobject_class->set_property = gdict_source_chooser_set_property;
294   gobject_class->get_property = gdict_source_chooser_get_property;
295   gobject_class->constructor = gdict_source_chooser_constructor;
296 
297   /**
298    * GdictSourceChooser:loader:
299    *
300    * The #GdictSourceLoader used to retrieve the list of available
301    * dictionary sources.
302    *
303    * Since: 0.12
304    */
305   g_object_class_install_property (gobject_class,
306                                    PROP_LOADER,
307                                    g_param_spec_object ("loader",
308                                                         "Loader",
309                                                         "The GdictSourceLoader used to get the list of sources",
310                                                         GDICT_TYPE_SOURCE_LOADER,
311                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
312   /**
313    * GdictSourceChooser:count:
314    *
315    * The number of available dictionary sources, or -1 if no
316    * #GdictSourceLoader is set.
317    *
318    * Since: 0.12
319    */
320   g_object_class_install_property (gobject_class,
321                                    PROP_COUNT,
322                                    g_param_spec_int ("count",
323                                                      "Count",
324                                                      "The number of available dictionary sources",
325                                                      -1, G_MAXINT, -1,
326                                                      G_PARAM_READABLE));
327 
328   /**
329    * GdictSourceChooser::source-activated:
330    * @chooser: the #GdictSourceChooser that received the signal
331    * @source_name: the name of the activated source
332    * @source: the activated #GdictSource
333    *
334    * The ::source-activated signal is emitted each time the user
335    * activates a row in the source chooser widget, either by double
336    * clicking on it or by a keyboard event.
337    *
338    * Since: 0.12
339    */
340   source_chooser_signals[SOURCE_ACTIVATED] =
341     g_signal_new ("source-activated",
342                   G_OBJECT_CLASS_TYPE (gobject_class),
343                   G_SIGNAL_RUN_LAST,
344                   G_STRUCT_OFFSET (GdictSourceChooserClass, source_activated),
345                   NULL, NULL,
346                   gdict_marshal_VOID__STRING_OBJECT,
347                   G_TYPE_NONE, 2,
348                   G_TYPE_STRING,
349                   GDICT_TYPE_SOURCE);
350   /**
351    * GdictSourceChooser::selection-changed:
352    * @chooser: the #GdictSourceChooser that received the signal
353    *
354    * The ::selection-changed signal is emitted each time the
355    * selection inside the source chooser widget has been changed.
356    *
357    * Since: 0.12
358    */
359   source_chooser_signals[SELECTION_CHANGED] =
360     g_signal_new ("selection-changed",
361                   G_OBJECT_CLASS_TYPE (gobject_class),
362                   G_SIGNAL_RUN_LAST,
363                   G_STRUCT_OFFSET (GdictSourceChooserClass, selection_changed),
364                   NULL, NULL,
365                   gdict_marshal_VOID__VOID,
366                   G_TYPE_NONE, 0);
367 }
368 
369 static void
gdict_source_chooser_init(GdictSourceChooser * chooser)370 gdict_source_chooser_init (GdictSourceChooser *chooser)
371 {
372   GdictSourceChooserPrivate *priv;
373 
374   chooser->priv = priv = gdict_source_chooser_get_instance_private (chooser);
375 
376   gtk_orientable_set_orientation (GTK_ORIENTABLE (chooser), GTK_ORIENTATION_VERTICAL);
377 
378   priv->store = gtk_list_store_new (SOURCE_N_COLUMNS,
379                                     G_TYPE_INT,    /* TRANSPORT */
380                                     G_TYPE_STRING, /* NAME */
381                                     G_TYPE_STRING, /* DESCRIPTION */
382                                     G_TYPE_INT     /* CURRENT */);
383 
384   priv->loader = NULL;
385   priv->n_sources = -1;
386 }
387 
388 /**
389  * gdict_source_chooser_new:
390  *
391  * Creates a new #GdictSourceChooser widget. This widget can be used to
392  * display the list of available dictionary sources.
393  *
394  * Return value: the newly created #GdictSourceChooser widget.
395  *
396  * Since: 0.12
397  */
398 GtkWidget *
gdict_source_chooser_new(void)399 gdict_source_chooser_new (void)
400 {
401   return g_object_new (GDICT_TYPE_SOURCE_CHOOSER, NULL);
402 }
403 
404 /**
405  * gdict_source_chooser_new_with_loader:
406  * @loader: a #GdictSourceLoader
407  *
408  * Creates a new #GdictSourceChooser widget and sets @loader as the
409  * #GdictSourceLoader object to be used to retrieve the list of
410  * available dictionary sources.
411  *
412  * Return value: the newly created #GdictSourceChooser widget.
413  *
414  * Since: 0.12
415  */
416 GtkWidget *
gdict_source_chooser_new_with_loader(GdictSourceLoader * loader)417 gdict_source_chooser_new_with_loader (GdictSourceLoader *loader)
418 {
419   g_return_val_if_fail (GDICT_IS_SOURCE_LOADER (loader), NULL);
420 
421   return g_object_new (GDICT_TYPE_SOURCE_CHOOSER, "loader", loader, NULL);
422 }
423 
424 /**
425  * gdict_source_chooser_set_loader:
426  * @chooser: a #GdictSourceChooser
427  * @loader: (nullable): a #GdictSourceLoader or %NULL to unset it
428  *
429  * Sets the #GdictSourceLoader to be used by the source chooser
430  * widget.
431  *
432  * Since: 0.12
433  */
434 void
gdict_source_chooser_set_loader(GdictSourceChooser * chooser,GdictSourceLoader * loader)435 gdict_source_chooser_set_loader (GdictSourceChooser *chooser,
436                                  GdictSourceLoader  *loader)
437 {
438   GdictSourceChooserPrivate *priv;
439 
440   g_return_if_fail (GDICT_IS_SOURCE_CHOOSER (chooser));
441   g_return_if_fail (loader == NULL || GDICT_IS_SOURCE_LOADER (loader));
442 
443   priv = chooser->priv;
444 
445   if (priv->loader != loader)
446     {
447       if (priv->loader)
448         g_object_unref (priv->loader);
449 
450       if (loader)
451         {
452           priv->loader = g_object_ref (loader);
453           gdict_source_chooser_refresh (chooser);
454         }
455 
456       g_object_notify (G_OBJECT (chooser), "loader");
457     }
458 }
459 
460 /**
461  * gdict_source_chooser_get_loader:
462  * @chooser: a #GdictSourceChooser
463  *
464  * Retrieves the #GdictSourceLoader used by @chooser.
465  *
466  * Return value: (transfer none): a #GdictSourceLoader or %NULL is none is set
467  *
468  * Since: 0.12
469  */
470 GdictSourceLoader *
gdict_source_chooser_get_loader(GdictSourceChooser * chooser)471 gdict_source_chooser_get_loader (GdictSourceChooser *chooser)
472 {
473   g_return_val_if_fail (GDICT_IS_SOURCE_CHOOSER (chooser), NULL);
474 
475   return chooser->priv->loader;
476 }
477 
478 typedef struct
479 {
480   gchar *source_name;
481   GdictSourceChooser *chooser;
482 
483   guint found       : 1;
484   guint do_select   : 1;
485   guint do_activate : 1;
486 } SelectData;
487 
488 static gboolean
scan_for_source_name(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer user_data)489 scan_for_source_name (GtkTreeModel *model,
490                       GtkTreePath  *path,
491                       GtkTreeIter  *iter,
492                       gpointer      user_data)
493 {
494   SelectData *select_data = user_data;
495   gchar *source_name = NULL;
496 
497   if (!select_data)
498     return TRUE;
499 
500   gtk_tree_model_get (model, iter, SOURCE_NAME, &source_name, -1);
501   if (!source_name)
502     return FALSE;
503 
504   if (strcmp (source_name, select_data->source_name) == 0)
505     {
506       GtkTreeView *tree_view;
507       GtkTreeSelection *selection;
508 
509       select_data->found = TRUE;
510 
511       tree_view = GTK_TREE_VIEW (select_data->chooser->priv->treeview);
512 
513       if (select_data->do_activate)
514         {
515           GtkTreeViewColumn *column;
516 
517           column = gtk_tree_view_get_column (tree_view, 2);
518 
519           gtk_list_store_set (GTK_LIST_STORE (model), iter,
520                               SOURCE_CURRENT, PANGO_WEIGHT_BOLD,
521                               -1);
522 
523           gtk_tree_view_row_activated (tree_view, path, column);
524         }
525 
526       selection = gtk_tree_view_get_selection (tree_view);
527       if (select_data->do_select)
528         gtk_tree_selection_select_path (selection, path);
529       else
530         gtk_tree_selection_unselect_path (selection, path);
531     }
532   else
533     {
534       gtk_list_store_set (GTK_LIST_STORE (model), iter,
535                           SOURCE_CURRENT, PANGO_WEIGHT_NORMAL,
536                           -1);
537     }
538 
539   g_free (source_name);
540 
541   return FALSE;
542 }
543 
544 /**
545  * gdict_source_chooser_select_source:
546  * @chooser: a #GdictSourceChooser
547  * @source_name: the name of a dictionary source
548  *
549  * Selects the dictionary source named @source_name inside @chooser.
550  * The selection is moved but the row containing the dictionary source
551  * is not activated.
552  *
553  * Return value: %TRUE if the source was found and selected
554  *
555  * Since: 0.12
556  */
557 gboolean
gdict_source_chooser_select_source(GdictSourceChooser * chooser,const gchar * source_name)558 gdict_source_chooser_select_source (GdictSourceChooser *chooser,
559                                     const gchar        *source_name)
560 {
561   GdictSourceChooserPrivate *priv;
562   SelectData data;
563   gboolean retval;
564 
565   g_return_val_if_fail (GDICT_IS_SOURCE_CHOOSER (chooser), FALSE);
566   g_return_val_if_fail (source_name != NULL, FALSE);
567 
568   priv = chooser->priv;
569 
570   data.source_name = g_strdup (source_name);
571   data.chooser = chooser;
572   data.found = FALSE;
573   data.do_select = TRUE;
574   data.do_activate = FALSE;
575 
576   gtk_tree_model_foreach (GTK_TREE_MODEL (priv->store),
577                           scan_for_source_name,
578                           &data);
579 
580   retval = data.found;
581 
582   g_free (data.source_name);
583 
584   return retval;
585 }
586 
587 /**
588  * gdict_source_chooser_unselect_source:
589  * @chooser: a #GdictSourceChooser
590  * @source_name: the name of a dictionary source
591  *
592  * Unselects @source_name inside @chooser.
593  *
594  * Return value: %TRUE if the source was found and unselected
595  *
596  * Since: 0.12
597  */
598 gboolean
gdict_source_chooser_unselect_source(GdictSourceChooser * chooser,const gchar * source_name)599 gdict_source_chooser_unselect_source (GdictSourceChooser *chooser,
600                                       const gchar        *source_name)
601 {
602   GdictSourceChooserPrivate *priv;
603   SelectData data;
604   gboolean retval;
605 
606   g_return_val_if_fail (GDICT_IS_SOURCE_CHOOSER (chooser), FALSE);
607   g_return_val_if_fail (source_name != NULL, FALSE);
608 
609   priv = chooser->priv;
610 
611   data.source_name = g_strdup (source_name);
612   data.chooser = chooser;
613   data.found = FALSE;
614   data.do_select = FALSE;
615   data.do_activate = FALSE;
616 
617   gtk_tree_model_foreach (GTK_TREE_MODEL (priv->store),
618                           scan_for_source_name,
619                           &data);
620 
621   retval = data.found;
622 
623   g_free (data.source_name);
624 
625   return retval;
626 }
627 
628 /**
629  * gdict_source_chooser_set_current_source:
630  * @chooser: a #GdictSourceChooser
631  * @source_name: the name of a dictionary source
632  *
633  * Sets the current dictionary source named @source_name. The row
634  * of the source, if found, will be selected and activated.
635  *
636  * Return value: %TRUE if the source was found
637  *
638  * Since: 0.12
639  */
640 gboolean
gdict_source_chooser_set_current_source(GdictSourceChooser * chooser,const gchar * source_name)641 gdict_source_chooser_set_current_source (GdictSourceChooser *chooser,
642                                          const gchar        *source_name)
643 {
644   GdictSourceChooserPrivate *priv;
645   SelectData data;
646   gboolean retval;
647 
648   g_return_val_if_fail (GDICT_IS_SOURCE_CHOOSER (chooser), FALSE);
649   g_return_val_if_fail (source_name != NULL, FALSE);
650 
651   priv = chooser->priv;
652 
653   if (priv->current_source && !strcmp (priv->current_source, source_name))
654     return TRUE;
655 
656   data.source_name = g_strdup (source_name);
657   data.chooser = chooser;
658   data.found = FALSE;
659   data.do_select = TRUE;
660   data.do_activate = TRUE;
661 
662   gtk_tree_model_foreach (GTK_TREE_MODEL (priv->store),
663                           scan_for_source_name,
664                           &data);
665 
666   retval = data.found;
667 
668   GDICT_NOTE (CHOOSER, "%s current source: %s",
669               data.found ? "set" : "not set",
670               data.source_name);
671 
672   if (data.found)
673     {
674       g_free (priv->current_source);
675       priv->current_source = data.source_name;
676     }
677   else
678     g_free (data.source_name);
679 
680   return retval;
681 }
682 
683 /**
684  * gdict_source_chooser_get_current_source:
685  * @chooser: a #GdictSourceChooser
686  *
687  * Retrieves the currently selected source.
688  *
689  * Return value: a newly allocated string containing the name of
690  *   the currently selected source. Use g_free() when done using it
691  *
692  * Since: 0.12
693  */
694 gchar *
gdict_source_chooser_get_current_source(GdictSourceChooser * chooser)695 gdict_source_chooser_get_current_source (GdictSourceChooser *chooser)
696 {
697   GdictSourceChooserPrivate *priv;
698   GtkTreeSelection *selection;
699   GtkTreeModel *model;
700   GtkTreeIter iter;
701   gchar *retval = NULL;
702 
703   g_return_val_if_fail (GDICT_IS_SOURCE_CHOOSER (chooser), NULL);
704 
705   priv = chooser->priv;
706 
707   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
708   if (!gtk_tree_selection_get_selected (selection, &model, &iter))
709     return NULL;
710 
711   gtk_tree_model_get (model, &iter, SOURCE_NAME, &retval, -1);
712 
713   g_free (priv->current_source);
714   priv->current_source = g_strdup (retval);
715 
716   return retval;
717 }
718 
719 /**
720  * gdict_source_chooser_get_sources:
721  * @chooser: a #GdictSouceChooser
722  * @length: return location for the length of the returned vector
723  *
724  * Retrieves the names of the available dictionary sources.
725  *
726  * Return value: (transfer full): a newly allocated, %NULL terminated
727  *   string vector containing the names of the available sources.
728  *   Use g_strfreev() when done using it.
729  *
730  * Since: 0.12
731  */
732 gchar **
gdict_source_chooser_get_sources(GdictSourceChooser * chooser,gsize * length)733 gdict_source_chooser_get_sources (GdictSourceChooser *chooser,
734                                   gsize              *length)
735 {
736   GdictSourceChooserPrivate *priv;
737   gchar **retval;
738   gsize retval_len;
739 
740   g_return_val_if_fail (GDICT_IS_SOURCE_CHOOSER (chooser), NULL);
741 
742   priv = chooser->priv;
743 
744   if (!priv->loader)
745     return NULL;
746 
747   retval = gdict_source_loader_get_names (priv->loader, &retval_len);
748   if (length)
749     *length = retval_len;
750 
751   return retval;
752 }
753 
754 /**
755  * gdict_source_chooser_count_sources:
756  * @chooser: a #GdictSourceChooser
757  *
758  * Retrieve the number of available dictionary sources.
759  *
760  * Return value: the number of available sources, or -1 if no
761  *   #GdictSourceLoader has been set
762  *
763  * Since: 0.12
764  */
765 gint
gdict_source_chooser_count_sources(GdictSourceChooser * chooser)766 gdict_source_chooser_count_sources (GdictSourceChooser *chooser)
767 {
768   g_return_val_if_fail (GDICT_IS_SOURCE_CHOOSER (chooser), -1);
769 
770   return chooser->priv->n_sources;
771 }
772 
773 /**
774  * gdict_source_chooser_has_source:
775  * @chooser: a #GdictSourceChooser
776  * @source_name: the name of a dictionary source
777  *
778  * Checks whether @chooser has a dictionary source named @source_name.
779  *
780  * Return value: %TRUE if the dictionary source was found
781  *
782  * Since: 0.12
783  */
784 gboolean
gdict_source_chooser_has_source(GdictSourceChooser * chooser,const gchar * source_name)785 gdict_source_chooser_has_source (GdictSourceChooser *chooser,
786                                  const gchar        *source_name)
787 {
788   GdictSourceChooserPrivate *priv;
789 
790   g_return_val_if_fail (GDICT_IS_SOURCE_CHOOSER (chooser), FALSE);
791   g_return_val_if_fail (source_name != NULL, FALSE);
792 
793   priv = chooser->priv;
794 
795   if (!priv->loader)
796     return FALSE;
797 
798   return gdict_source_loader_has_source (priv->loader, source_name);
799 }
800 
801 /**
802  * gdict_source_chooser_refresh:
803  * @chooser: a #GdictSourceChooser
804  *
805  * Forces a refresh on the contents of the source chooser widget
806  *
807  * Since: 0.12
808  */
809 void
gdict_source_chooser_refresh(GdictSourceChooser * chooser)810 gdict_source_chooser_refresh (GdictSourceChooser *chooser)
811 {
812   GdictSourceChooserPrivate *priv;
813 
814   g_return_if_fail (GDICT_IS_SOURCE_CHOOSER (chooser));
815 
816   priv = chooser->priv;
817 
818   if (priv->loader)
819     {
820       const GSList *sources, *l;
821 
822       if (priv->treeview)
823         gtk_tree_view_set_model (GTK_TREE_VIEW (priv->treeview), NULL);
824 
825       gtk_list_store_clear (priv->store);
826 
827       sources = gdict_source_loader_get_sources (priv->loader);
828       for (l = sources; l != NULL; l = l->next)
829         {
830           GdictSource *source = l->data;
831           const gchar *name, *description;
832           GdictSourceTransport transport;
833           gint weight;
834 
835           transport = gdict_source_get_transport (source);
836           name = gdict_source_get_name (source);
837           description = gdict_source_get_description (source);
838           weight = PANGO_WEIGHT_NORMAL;
839 
840           if (priv->current_source && !strcmp (priv->current_source, name))
841             weight = PANGO_WEIGHT_BOLD;
842 
843           gtk_list_store_insert_with_values (priv->store, NULL, -1,
844                                              SOURCE_TRANSPORT, transport,
845                                              SOURCE_NAME, name,
846                                              SOURCE_DESCRIPTION, description,
847                                              SOURCE_CURRENT, weight,
848                                              -1);
849         }
850 
851       if (priv->treeview)
852         gtk_tree_view_set_model (GTK_TREE_VIEW (priv->treeview),
853                                  GTK_TREE_MODEL (priv->store));
854     }
855 }
856 
857 /**
858  * gdict_source_chooser_add_button:
859  * @chooser: a #GdictSourceChooser
860  * @button_text: text of the button
861  *
862  * Adds a #GtkButton with @button_text to the button area on
863  * the bottom of @chooser.
864  *
865  * Return value: (transfer none): the newly packed button.
866  *
867  * Since: 0.12
868  */
869 GtkWidget *
gdict_source_chooser_add_button(GdictSourceChooser * chooser,const gchar * button_text)870 gdict_source_chooser_add_button (GdictSourceChooser *chooser,
871                                  const gchar        *button_text)
872 {
873   GdictSourceChooserPrivate *priv;
874   GtkWidget *button;
875 
876   g_return_val_if_fail (GDICT_IS_SOURCE_CHOOSER (chooser), NULL);
877   g_return_val_if_fail (button_text != NULL, NULL);
878 
879   priv = chooser->priv;
880 
881   button = gtk_button_new_with_label (button_text);
882 
883   gtk_widget_set_can_default (button, TRUE);
884 
885   gtk_widget_show (button);
886 
887   gtk_box_pack_end (GTK_BOX (priv->buttons_box), button, FALSE, TRUE, 0);
888 
889   return button;
890 }
891 
892