1#include <gtk/gtk.h>
2
3#include "exampleapp.h"
4#include "exampleappwin.h"
5
6struct _ExampleAppWindow
7{
8 GtkApplicationWindow parent;
9
10 GSettings *settings;
11 GtkWidget *stack;
12 GtkWidget *gears;
13 GtkWidget *search;
14 GtkWidget *searchbar;
15 GtkWidget *searchentry;
16 GtkWidget *sidebar;
17 GtkWidget *words;
18 GtkWidget *lines;
19 GtkWidget *lines_label;
20};
21
22G_DEFINE_TYPE (ExampleAppWindow, example_app_window, GTK_TYPE_APPLICATION_WINDOW)
23
24static void
25search_text_changed (GtkEntry *entry,
26 ExampleAppWindow *win)
27{
28 const char *text;
29 GtkWidget *tab;
30 GtkWidget *view;
31 GtkTextBuffer *buffer;
32 GtkTextIter start, match_start, match_end;
33
34 text = gtk_editable_get_text (GTK_EDITABLE (entry));
35
36 if (text[0] == '\0')
37 return;
38
39 tab = gtk_stack_get_visible_child (GTK_STACK (win->stack));
40 view = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (tab));
41 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
42
43 /* Very simple-minded search implementation */
44 gtk_text_buffer_get_start_iter (buffer, iter: &start);
45 if (gtk_text_iter_forward_search (iter: &start, str: text, flags: GTK_TEXT_SEARCH_CASE_INSENSITIVE,
46 match_start: &match_start, match_end: &match_end, NULL))
47 {
48 gtk_text_buffer_select_range (buffer, ins: &match_start, bound: &match_end);
49 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (view), iter: &match_start,
50 within_margin: 0.0, FALSE, xalign: 0.0, yalign: 0.0);
51 }
52}
53
54static void
55find_word (GtkButton *button,
56 ExampleAppWindow *win)
57{
58 const char *word;
59
60 word = gtk_button_get_label (button);
61 gtk_editable_set_text (GTK_EDITABLE (win->searchentry), text: word);
62}
63
64static void
65update_words (ExampleAppWindow *win)
66{
67 GHashTable *strings;
68 GHashTableIter iter;
69 GtkWidget *tab, *view, *row;
70 GtkTextBuffer *buffer;
71 GtkTextIter start, end;
72 char *word, *key;
73 GtkWidget *child;
74
75 tab = gtk_stack_get_visible_child (GTK_STACK (win->stack));
76
77 if (tab == NULL)
78 return;
79
80 view = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (tab));
81 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
82
83 strings = g_hash_table_new_full (hash_func: g_str_hash, key_equal_func: g_str_equal, key_destroy_func: g_free, NULL);
84
85 gtk_text_buffer_get_start_iter (buffer, iter: &start);
86 while (!gtk_text_iter_is_end (iter: &start))
87 {
88 while (!gtk_text_iter_starts_word (iter: &start))
89 {
90 if (!gtk_text_iter_forward_char (iter: &start))
91 goto done;
92 }
93 end = start;
94 if (!gtk_text_iter_forward_word_end (iter: &end))
95 goto done;
96 word = gtk_text_buffer_get_text (buffer, start: &start, end: &end, FALSE);
97 g_hash_table_add (hash_table: strings, key: g_utf8_strdown (str: word, len: -1));
98 g_free (mem: word);
99 start = end;
100 }
101
102done:
103 while ((child = gtk_widget_get_first_child (widget: win->words)))
104 gtk_list_box_remove (GTK_LIST_BOX (win->words), child);
105
106 g_hash_table_iter_init (iter: &iter, hash_table: strings);
107 while (g_hash_table_iter_next (iter: &iter, key: (gpointer *)&key, NULL))
108 {
109 row = gtk_button_new_with_label (label: key);
110 g_signal_connect (row, "clicked",
111 G_CALLBACK (find_word), win);
112 gtk_list_box_insert (GTK_LIST_BOX (win->words), child: row, position: -1);
113 }
114
115 g_hash_table_unref (hash_table: strings);
116}
117
118static void
119update_lines (ExampleAppWindow *win)
120{
121 GtkWidget *tab, *view;
122 GtkTextBuffer *buffer;
123 int count;
124 char *lines;
125
126 tab = gtk_stack_get_visible_child (GTK_STACK (win->stack));
127
128 if (tab == NULL)
129 return;
130
131 view = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (tab));
132 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
133
134 count = gtk_text_buffer_get_line_count (buffer);
135 lines = g_strdup_printf (format: "%d", count);
136 gtk_label_set_text (GTK_LABEL (win->lines), str: lines);
137 g_free (mem: lines);
138}
139
140static void
141visible_child_changed (GObject *stack,
142 GParamSpec *pspec,
143 ExampleAppWindow *win)
144{
145 if (gtk_widget_in_destruction (GTK_WIDGET (stack)))
146 return;
147
148 gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (win->searchbar), FALSE);
149 update_words (win);
150 update_lines (win);
151}
152
153static void
154words_changed (GObject *sidebar,
155 GParamSpec *pspec,
156 ExampleAppWindow *win)
157{
158 update_words (win);
159}
160
161static void
162example_app_window_init (ExampleAppWindow *win)
163{
164 GtkBuilder *builder;
165 GMenuModel *menu;
166 GAction *action;
167
168 gtk_widget_init_template (GTK_WIDGET (win));
169
170 builder = gtk_builder_new_from_resource (resource_path: "/org/gtk/exampleapp/gears-menu.ui");
171 menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu"));
172 gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (win->gears), menu_model: menu);
173 g_object_unref (object: builder);
174
175 win->settings = g_settings_new (schema_id: "org.gtk.exampleapp");
176
177 g_settings_bind (settings: win->settings, key: "transition",
178 object: win->stack, property: "transition-type",
179 flags: G_SETTINGS_BIND_DEFAULT);
180
181 g_settings_bind (settings: win->settings, key: "show-words",
182 object: win->sidebar, property: "reveal-child",
183 flags: G_SETTINGS_BIND_DEFAULT);
184
185 g_object_bind_property (source: win->search, source_property: "active",
186 target: win->searchbar, target_property: "search-mode-enabled",
187 flags: G_BINDING_BIDIRECTIONAL);
188
189 g_signal_connect (win->sidebar, "notify::reveal-child",
190 G_CALLBACK (words_changed), win);
191
192 action = g_settings_create_action (settings: win->settings, key: "show-words");
193 g_action_map_add_action (G_ACTION_MAP (win), action);
194 g_object_unref (object: action);
195
196 action = (GAction*) g_property_action_new (name: "show-lines", object: win->lines, property_name: "visible");
197 g_action_map_add_action (G_ACTION_MAP (win), action);
198 g_object_unref (object: action);
199
200 g_object_bind_property (source: win->lines, source_property: "visible",
201 target: win->lines_label, target_property: "visible",
202 flags: G_BINDING_DEFAULT);
203}
204
205static void
206example_app_window_dispose (GObject *object)
207{
208 ExampleAppWindow *win;
209
210 win = EXAMPLE_APP_WINDOW (ptr: object);
211
212 g_clear_object (&win->settings);
213
214 G_OBJECT_CLASS (example_app_window_parent_class)->dispose (object);
215}
216
217static void
218example_app_window_class_init (ExampleAppWindowClass *class)
219{
220 G_OBJECT_CLASS (class)->dispose = example_app_window_dispose;
221
222 gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
223 resource_name: "/org/gtk/exampleapp/window.ui");
224
225 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, stack);
226 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, gears);
227 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, search);
228 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, searchbar);
229 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, searchentry);
230 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, words);
231 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, sidebar);
232 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, lines);
233 gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, lines_label);
234
235 gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), search_text_changed);
236 gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), visible_child_changed);
237}
238
239ExampleAppWindow *
240example_app_window_new (ExampleApp *app)
241{
242 return g_object_new (EXAMPLE_APP_WINDOW_TYPE, first_property_name: "application", app, NULL);
243}
244
245void
246example_app_window_open (ExampleAppWindow *win,
247 GFile *file)
248{
249 char *basename;
250 GtkWidget *scrolled, *view;
251 char *contents;
252 gsize length;
253 GtkTextBuffer *buffer;
254 GtkTextTag *tag;
255 GtkTextIter start_iter, end_iter;
256
257 basename = g_file_get_basename (file);
258
259 scrolled = gtk_scrolled_window_new ();
260 gtk_widget_set_hexpand (widget: scrolled, TRUE);
261 gtk_widget_set_vexpand (widget: scrolled, TRUE);
262 view = gtk_text_view_new ();
263 gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
264 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
265 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled), child: view);
266 gtk_stack_add_titled (GTK_STACK (win->stack), child: scrolled, name: basename, title: basename);
267
268 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
269
270 if (g_file_load_contents (file, NULL, contents: &contents, length: &length, NULL, NULL))
271 {
272 gtk_text_buffer_set_text (buffer, text: contents, len: length);
273 g_free (mem: contents);
274 }
275
276 tag = gtk_text_buffer_create_tag (buffer, NULL, NULL);
277 g_settings_bind (settings: win->settings, key: "font",
278 object: tag, property: "font",
279 flags: G_SETTINGS_BIND_DEFAULT);
280
281 gtk_text_buffer_get_start_iter (buffer, iter: &start_iter);
282 gtk_text_buffer_get_end_iter (buffer, iter: &end_iter);
283 gtk_text_buffer_apply_tag (buffer, tag, start: &start_iter, end: &end_iter);
284
285 g_free (mem: basename);
286
287 gtk_widget_set_sensitive (widget: win->search, TRUE);
288
289 update_words (win);
290 update_lines (win);
291}
292

source code of gtk/examples/application9/exampleappwin.c