1 /*
2 * xed-highlight-mode-selector.c
3 * This file is part of xed
4 *
5 * Copyright (C) 2013 - Ignacio Casal Quinteiro
6 *
7 * xed is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * xed is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with xed. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "xed-highlight-mode-selector.h"
22
23 #include <gdk/gdkkeysyms.h>
24 #include <glib/gi18n.h>
25 #include <string.h>
26
27 enum
28 {
29 COLUMN_NAME,
30 COLUMN_LANG,
31 N_COLUMNS
32 };
33
34 struct _XedHighlightModeSelector
35 {
36 GtkGrid parent_instance;
37
38 GtkWidget *treeview;
39 GtkWidget *entry;
40 GtkListStore *liststore;
41 GtkTreeModelFilter *treemodelfilter;
42 GtkTreeSelection *treeview_selection;
43 };
44
45 /* Signals */
46 enum
47 {
48 LANGUAGE_SELECTED,
49 CANCELLED,
50 LAST_SIGNAL
51 };
52
53 static guint signals[LAST_SIGNAL] = { 0 };
54
G_DEFINE_TYPE(XedHighlightModeSelector,xed_highlight_mode_selector,GTK_TYPE_GRID)55 G_DEFINE_TYPE (XedHighlightModeSelector, xed_highlight_mode_selector, GTK_TYPE_GRID)
56
57 static void
58 xed_highlight_mode_selector_language_selected (XedHighlightModeSelector *widget,
59 GtkSourceLanguage *language)
60 {
61 }
62
63 static void
xed_highlight_mode_selector_class_init(XedHighlightModeSelectorClass * klass)64 xed_highlight_mode_selector_class_init (XedHighlightModeSelectorClass *klass)
65 {
66 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
67
68 signals[LANGUAGE_SELECTED] =
69 g_signal_new_class_handler ("language-selected",
70 G_TYPE_FROM_CLASS (klass),
71 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
72 G_CALLBACK (xed_highlight_mode_selector_language_selected),
73 NULL, NULL, NULL,
74 G_TYPE_NONE,
75 1,
76 GTK_SOURCE_TYPE_LANGUAGE);
77
78 signals[CANCELLED] =
79 g_signal_new_class_handler ("cancelled",
80 G_TYPE_FROM_CLASS (klass),
81 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
82 NULL, NULL, NULL, NULL,
83 G_TYPE_NONE, 0);
84
85 /* Bind class to template */
86 gtk_widget_class_set_template_from_resource (widget_class,
87 "/org/x/editor/ui/xed-highlight-mode-selector.ui");
88 gtk_widget_class_bind_template_child (widget_class, XedHighlightModeSelector, treeview);
89 gtk_widget_class_bind_template_child (widget_class, XedHighlightModeSelector, entry);
90 gtk_widget_class_bind_template_child (widget_class, XedHighlightModeSelector, liststore);
91 gtk_widget_class_bind_template_child (widget_class, XedHighlightModeSelector, treemodelfilter);
92 gtk_widget_class_bind_template_child (widget_class, XedHighlightModeSelector, treeview_selection);
93 }
94
95 static gboolean
visible_func(GtkTreeModel * model,GtkTreeIter * iter,XedHighlightModeSelector * selector)96 visible_func (GtkTreeModel *model,
97 GtkTreeIter *iter,
98 XedHighlightModeSelector *selector)
99 {
100 const gchar *entry_text;
101 gchar *name;
102 gchar *name_normalized;
103 gchar *name_casefolded;
104 gchar *text_normalized;
105 gchar *text_casefolded;
106 gboolean visible = FALSE;
107
108 entry_text = gtk_entry_get_text (GTK_ENTRY (selector->entry));
109
110 if (*entry_text == '\0')
111 {
112 return TRUE;
113 }
114
115 gtk_tree_model_get (model, iter, COLUMN_NAME, &name, -1);
116
117 name_normalized = g_utf8_normalize (name, -1, G_NORMALIZE_ALL);
118 g_free (name);
119
120 name_casefolded = g_utf8_casefold (name_normalized, -1);
121 g_free (name_normalized);
122
123 text_normalized = g_utf8_normalize (entry_text, -1, G_NORMALIZE_ALL);
124 text_casefolded = g_utf8_casefold (text_normalized, -1);
125 g_free (text_normalized);
126
127 if (strstr (name_casefolded, text_casefolded) != NULL)
128 {
129 visible = TRUE;
130 }
131
132 g_free (name_casefolded);
133 g_free (text_casefolded);
134
135 return visible;
136 }
137
138 static void
on_entry_activate(GtkEntry * entry,XedHighlightModeSelector * selector)139 on_entry_activate (GtkEntry *entry,
140 XedHighlightModeSelector *selector)
141 {
142 xed_highlight_mode_selector_activate_selected_language (selector);
143 }
144
145 static void
on_entry_changed(GtkEntry * entry,XedHighlightModeSelector * selector)146 on_entry_changed (GtkEntry *entry,
147 XedHighlightModeSelector *selector)
148 {
149 GtkTreeIter iter;
150
151 gtk_tree_model_filter_refilter (selector->treemodelfilter);
152
153 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (selector->treemodelfilter), &iter))
154 {
155 gtk_tree_selection_select_iter (selector->treeview_selection, &iter);
156 }
157 }
158
159 static gboolean
move_selection(XedHighlightModeSelector * selector,gint howmany)160 move_selection (XedHighlightModeSelector *selector,
161 gint howmany)
162 {
163 GtkTreeIter iter;
164 GtkTreePath *path;
165 gint *indices;
166 gint ret = FALSE;
167
168 if (!gtk_tree_selection_get_selected (selector->treeview_selection, NULL, &iter) &&
169 !gtk_tree_model_get_iter_first (GTK_TREE_MODEL (selector->treemodelfilter), &iter))
170 {
171 return FALSE;
172 }
173
174 path = gtk_tree_model_get_path (GTK_TREE_MODEL (selector->treemodelfilter), &iter);
175 indices = gtk_tree_path_get_indices (path);
176
177 if (indices)
178 {
179 gint num;
180 gint idx;
181 GtkTreePath *new_path;
182
183 idx = indices[0];
184 num = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (selector->treemodelfilter), NULL);
185
186 if ((idx + howmany) < 0)
187 {
188 idx = 0;
189 }
190 else if ((idx + howmany) >= num)
191 {
192 idx = num - 1;
193 }
194 else
195 {
196 idx = idx + howmany;
197 }
198
199 new_path = gtk_tree_path_new_from_indices (idx, -1);
200 gtk_tree_selection_select_path (selector->treeview_selection, new_path);
201 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (selector->treeview),
202 new_path, NULL, TRUE, 0.5, 0);
203 gtk_tree_path_free (new_path);
204
205 ret = TRUE;
206 }
207
208 gtk_tree_path_free (path);
209
210 return ret;
211 }
212
213 static gboolean
on_entry_key_press_event(GtkWidget * entry,GdkEventKey * event,XedHighlightModeSelector * selector)214 on_entry_key_press_event (GtkWidget *entry,
215 GdkEventKey *event,
216 XedHighlightModeSelector *selector)
217 {
218 if (event->keyval == GDK_KEY_Down)
219 {
220 return move_selection (selector, 1);
221 }
222 else if (event->keyval == GDK_KEY_Up)
223 {
224 return move_selection (selector, -1);
225 }
226 else if (event->keyval == GDK_KEY_Page_Down)
227 {
228 return move_selection (selector, 5);
229 }
230 else if (event->keyval == GDK_KEY_Page_Up)
231 {
232 return move_selection (selector, -5);
233 }
234 else if (event->keyval == GDK_KEY_Escape)
235 {
236 g_signal_emit (G_OBJECT (selector), signals[CANCELLED], 0);
237 return FALSE;
238 }
239
240 return FALSE;
241 }
242
243 static void
on_entry_realized(GtkWidget * entry,XedHighlightModeSelector * selector)244 on_entry_realized (GtkWidget *entry,
245 XedHighlightModeSelector *selector)
246 {
247 if (gtk_widget_is_focus (GTK_WIDGET (selector)))
248 {
249 gtk_widget_grab_focus (entry);
250 }
251 else
252 {
253 gtk_widget_grab_focus (GTK_WIDGET (selector));
254 }
255 }
256
257 static void
on_row_activated(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,XedHighlightModeSelector * selector)258 on_row_activated (GtkTreeView *tree_view,
259 GtkTreePath *path,
260 GtkTreeViewColumn *column,
261 XedHighlightModeSelector *selector)
262 {
263 xed_highlight_mode_selector_activate_selected_language (selector);
264 }
265
266 static void
xed_highlight_mode_selector_init(XedHighlightModeSelector * selector)267 xed_highlight_mode_selector_init (XedHighlightModeSelector *selector)
268 {
269 GtkSourceLanguageManager *lm;
270 const gchar * const *ids;
271 gint i;
272 GtkTreeIter iter;
273
274 selector = xed_highlight_mode_selector_get_instance_private (selector);
275
276 gtk_widget_init_template (GTK_WIDGET (selector));
277
278 gtk_tree_model_filter_set_visible_func (selector->treemodelfilter,
279 (GtkTreeModelFilterVisibleFunc)visible_func,
280 selector,
281 NULL);
282
283 g_signal_connect (selector->entry, "activate",
284 G_CALLBACK (on_entry_activate), selector);
285 g_signal_connect (selector->entry, "changed",
286 G_CALLBACK (on_entry_changed), selector);
287 g_signal_connect (selector->entry, "key-press-event",
288 G_CALLBACK (on_entry_key_press_event), selector);
289 g_signal_connect (selector->entry, "realize",
290 G_CALLBACK (on_entry_realized), selector);
291 g_signal_connect (selector->treeview, "row-activated",
292 G_CALLBACK (on_row_activated), selector);
293
294 /* Populate tree model */
295 gtk_list_store_append (selector->liststore, &iter);
296 gtk_list_store_set (selector->liststore, &iter,
297 COLUMN_NAME, _("Plain Text"),
298 COLUMN_LANG, NULL,
299 -1);
300
301 lm = gtk_source_language_manager_get_default ();
302 ids = gtk_source_language_manager_get_language_ids (lm);
303
304 for (i = 0; ids[i] != NULL; i++)
305 {
306 GtkSourceLanguage *lang;
307
308 lang = gtk_source_language_manager_get_language (lm, ids[i]);
309
310 if (!gtk_source_language_get_hidden (lang))
311 {
312 gtk_list_store_append (selector->liststore, &iter);
313 gtk_list_store_set (selector->liststore, &iter,
314 COLUMN_NAME, gtk_source_language_get_name (lang),
315 COLUMN_LANG, lang,
316 -1);
317 }
318 }
319
320 /* select first item */
321 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (selector->treemodelfilter), &iter))
322 {
323 gtk_tree_selection_select_iter (selector->treeview_selection, &iter);
324 }
325 }
326
327 XedHighlightModeSelector *
xed_highlight_mode_selector_new()328 xed_highlight_mode_selector_new ()
329 {
330 return g_object_new (XED_TYPE_HIGHLIGHT_MODE_SELECTOR, NULL);
331 }
332
333 void
xed_highlight_mode_selector_select_language(XedHighlightModeSelector * selector,GtkSourceLanguage * language)334 xed_highlight_mode_selector_select_language (XedHighlightModeSelector *selector,
335 GtkSourceLanguage *language)
336 {
337 GtkTreeIter iter;
338
339 g_return_if_fail (XED_IS_HIGHLIGHT_MODE_SELECTOR (selector));
340
341 if (language == NULL)
342 {
343 return;
344 }
345
346 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (selector->treemodelfilter), &iter))
347 {
348 do
349 {
350 GtkSourceLanguage *lang;
351
352 gtk_tree_model_get (GTK_TREE_MODEL (selector->treemodelfilter),
353 &iter,
354 COLUMN_LANG, &lang,
355 -1);
356
357 if (lang != NULL)
358 {
359 gboolean equal = (lang == language);
360
361 g_object_unref (lang);
362
363 if (equal)
364 {
365 GtkTreePath *path;
366
367 path = gtk_tree_model_get_path (GTK_TREE_MODEL (selector->treemodelfilter), &iter);
368
369 gtk_tree_selection_select_iter (selector->treeview_selection, &iter);
370 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (selector->treeview),
371 path, NULL, TRUE, 0.5, 0);
372 gtk_tree_path_free (path);
373 break;
374 }
375 }
376 }
377 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (selector->treemodelfilter), &iter));
378 }
379 }
380
381 void
xed_highlight_mode_selector_activate_selected_language(XedHighlightModeSelector * selector)382 xed_highlight_mode_selector_activate_selected_language (XedHighlightModeSelector *selector)
383 {
384 GtkSourceLanguage *lang;
385 GtkTreeIter iter;
386
387 g_return_if_fail (XED_IS_HIGHLIGHT_MODE_SELECTOR (selector));
388
389 if (!gtk_tree_selection_get_selected (selector->treeview_selection, NULL, &iter))
390 {
391 return;
392 }
393
394 gtk_tree_model_get (GTK_TREE_MODEL (selector->treemodelfilter), &iter,
395 COLUMN_LANG, &lang,
396 -1);
397
398 g_signal_emit (G_OBJECT (selector), signals[LANGUAGE_SELECTED], 0, lang);
399
400 if (lang != NULL)
401 {
402 g_object_unref (lang);
403 }
404 }
405