Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-3.0-or-later
2 : : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
3 : :
4 : : #define G_LOG_DOMAIN "valent-device-preferences-dialog"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <glib/gi18n-lib.h>
9 : : #include <adwaita.h>
10 : : #include <gtk/gtk.h>
11 : : #include <valent.h>
12 : :
13 : : #include "valent-preferences-command-editor.h"
14 : :
15 : : #include "valent-preferences-other-page.h"
16 : :
17 : :
18 : : struct _ValentPreferencesOtherPage
19 : : {
20 : : ValentPreferencesPage parent_instance;
21 : :
22 : : /* template */
23 : : GtkListBox *command_list;
24 : : GtkLabel *download_folder_label;
25 : : };
26 : :
27 [ + + + - ]: 42 : G_DEFINE_FINAL_TYPE (ValentPreferencesOtherPage, valent_preferences_other_page, VALENT_TYPE_PREFERENCES_PAGE)
28 : :
29 : : /*
30 : : * Commands
31 : : */
32 : : static void
33 : 3 : valent_runcommand_preferences_populate (ValentPreferencesOtherPage *self)
34 : : {
35 : 3 : ValentPreferencesPage *page = VALENT_PREFERENCES_PAGE (self);
36 : 3 : GSettings *settings;
37 : 3 : GtkWidget *child;
38 : 6 : g_autoptr (GVariant) commands = NULL;
39 : 3 : GVariantIter iter;
40 : 3 : char *uuid;
41 : 3 : GVariant *item;
42 : :
43 [ + - ]: 3 : g_assert (VALENT_IS_PREFERENCES_OTHER_PAGE (self));
44 : :
45 : 3 : child = gtk_widget_get_first_child (GTK_WIDGET (self->command_list));
46 [ + + ]: 6 : while (child != NULL)
47 : : {
48 : 3 : GtkWidget *current = child;
49 : :
50 : 3 : child = gtk_widget_get_next_sibling (current);
51 [ - + ]: 3 : if (ADW_IS_ACTION_ROW (current))
52 : 0 : gtk_list_box_remove (self->command_list, current);
53 : : }
54 : :
55 : 3 : settings = valent_preferences_page_get_settings (page, "runcommand");
56 : 3 : commands = g_settings_get_value (settings, "commands");
57 : :
58 : 3 : g_variant_iter_init (&iter, commands);
59 [ - + ]: 3 : while (g_variant_iter_loop (&iter, "{sv}", &uuid, &item))
60 : : {
61 : 0 : const char *name = NULL;
62 : 0 : const char *command = NULL;
63 : :
64 [ # # # # ]: 0 : if (g_variant_lookup (item, "name", "&s", &name) &&
65 : 0 : g_variant_lookup (item, "command", "&s", &command))
66 : : {
67 : 0 : GtkWidget *row;
68 : 0 : GtkWidget *icon;
69 : 0 : g_autofree char *subtitle = NULL;
70 : :
71 : 0 : subtitle = g_markup_printf_escaped ("<tt>%s</tt>", command);
72 : 0 : row = g_object_new (ADW_TYPE_ACTION_ROW,
73 : : "name", uuid,
74 : : "title", name,
75 : : "subtitle", subtitle,
76 : : "activatable", TRUE,
77 : : "selectable", FALSE,
78 : : "action-target", g_variant_new_string (uuid),
79 : : "action-name", "preferences.edit-command",
80 : : NULL);
81 : :
82 : 0 : icon = g_object_new (GTK_TYPE_IMAGE,
83 : : "icon-name", "document-edit-symbolic",
84 : 0 : "tooltip-text", _("Edit Command"),
85 : : NULL);
86 : 0 : adw_action_row_add_suffix (ADW_ACTION_ROW (row), icon);
87 : :
88 : : /* a11y: an activatable widget would change the label and description,
89 : : * but a button is unnecessary and the label should be unchanged. */
90 : 0 : gtk_accessible_update_relation (GTK_ACCESSIBLE (row),
91 : : GTK_ACCESSIBLE_RELATION_DESCRIBED_BY,
92 : : icon, NULL,
93 : : -1);
94 : :
95 : 0 : gtk_list_box_append (self->command_list, row);
96 : : }
97 : : }
98 : 3 : }
99 : :
100 : : static int
101 : 0 : sort_commands (GtkListBoxRow *row1,
102 : : GtkListBoxRow *row2,
103 : : gpointer user_data)
104 : : {
105 : 0 : const char *title1;
106 : 0 : const char *title2;
107 : :
108 : 0 : title1 = adw_preferences_row_get_title (ADW_PREFERENCES_ROW (row1));
109 : 0 : title2 = adw_preferences_row_get_title (ADW_PREFERENCES_ROW (row2));
110 : :
111 : 0 : return g_utf8_collate (title1, title2);
112 : : }
113 : :
114 : : /*
115 : : * GAction
116 : : */
117 : : static void
118 : 0 : on_command_changed (ValentPreferencesCommandEditor *editor,
119 : : GParamSpec *pspec,
120 : : ValentPreferencesOtherPage *self)
121 : : {
122 : 0 : ValentPreferencesPage *page = VALENT_PREFERENCES_PAGE (self);
123 : 0 : GSettings *settings;
124 : 0 : g_autoptr (GVariant) commands = NULL;
125 : 0 : const char *uuid;
126 : 0 : GVariant *command;
127 : 0 : GVariantDict dict;
128 : :
129 [ # # ]: 0 : g_assert (VALENT_IS_PREFERENCES_COMMAND_EDITOR (editor));
130 [ # # ]: 0 : g_assert (VALENT_IS_PREFERENCES_OTHER_PAGE (self));
131 : :
132 : 0 : settings = valent_preferences_page_get_settings (page, "runcommand");
133 : 0 : commands = g_settings_get_value (settings, "commands");
134 : :
135 : 0 : uuid = valent_preferences_command_editor_get_uuid (editor);
136 : 0 : command = valent_preferences_command_editor_get_command (editor);
137 [ # # ]: 0 : if (command != NULL)
138 : : {
139 : 0 : g_variant_dict_init (&dict, commands);
140 : 0 : g_variant_dict_insert_value (&dict, uuid, command);
141 : 0 : g_settings_set_value (settings, "commands", g_variant_dict_end (&dict));
142 : : }
143 : : else
144 : : {
145 : 0 : g_variant_dict_init (&dict, commands);
146 : 0 : g_variant_dict_remove (&dict, uuid);
147 : 0 : g_settings_set_value (settings, "commands", g_variant_dict_end (&dict));
148 : : }
149 : :
150 [ # # ]: 0 : adw_dialog_close (ADW_DIALOG (editor));
151 : 0 : }
152 : :
153 : : static void
154 : 0 : add_command_action (GtkWidget *widget,
155 : : const char *action_name,
156 : : GVariant *parameter)
157 : : {
158 : 0 : g_autofree char *uuid = NULL;
159 : :
160 [ # # ]: 0 : g_assert (VALENT_IS_PREFERENCES_OTHER_PAGE (widget));
161 : :
162 : 0 : uuid = g_uuid_string_random ();
163 : 0 : gtk_widget_activate_action (widget, "preferences.edit-command", "s", uuid);
164 : 0 : }
165 : :
166 : : static void
167 : 0 : edit_command_action (GtkWidget *widget,
168 : : const char *action_name,
169 : : GVariant *parameter)
170 : : {
171 : 0 : ValentPreferencesOtherPage *self = VALENT_PREFERENCES_OTHER_PAGE (widget);
172 : 0 : ValentPreferencesPage *page = VALENT_PREFERENCES_PAGE (self);
173 : 0 : AdwDialog *editor = NULL;
174 : 0 : const char *uuid = NULL;
175 : 0 : GSettings *settings;
176 : 0 : g_autoptr (GVariant) commands = NULL;
177 [ # # ]: 0 : g_autoptr (GVariant) command = NULL;
178 : :
179 [ # # ]: 0 : g_assert (VALENT_IS_PREFERENCES_OTHER_PAGE (self));
180 : :
181 : 0 : uuid = g_variant_get_string (parameter, NULL);
182 : 0 : settings = valent_preferences_page_get_settings (page, "runcommand");
183 : 0 : commands = g_settings_get_value (settings, "commands");
184 : 0 : g_variant_lookup (commands, uuid, "@a{sv}", &command);
185 : :
186 : 0 : editor = g_object_new (VALENT_TYPE_PREFERENCES_COMMAND_EDITOR,
187 : : "uuid", uuid,
188 : : "command", command,
189 : : NULL);
190 : 0 : g_signal_connect_object (editor,
191 : : "notify::command",
192 : : G_CALLBACK (on_command_changed),
193 : : self,
194 : : G_CONNECT_DEFAULT);
195 [ # # ]: 0 : adw_dialog_present (editor, widget);
196 : 0 : }
197 : :
198 : : /*
199 : : * Share
200 : : */
201 : : static gboolean
202 : 3 : on_download_folder_changed (GValue *value,
203 : : GVariant *variant,
204 : : gpointer user_data)
205 : : {
206 : 3 : const char *label;
207 : :
208 : 3 : label = g_variant_get_string (variant, NULL);
209 : 3 : g_value_take_string (value, g_path_get_basename (label));
210 : :
211 : 3 : return TRUE;
212 : : }
213 : :
214 : : static void
215 : 0 : gtk_file_dialog_select_folder_cb (GtkFileDialog *dialog,
216 : : GAsyncResult *result,
217 : : ValentPreferencesPage *page)
218 : : {
219 : 0 : g_autoptr (GFile) file = NULL;
220 : 0 : g_autoptr (GError) error = NULL;
221 : 0 : GSettings *settings = NULL;
222 : :
223 [ # # ]: 0 : g_assert (VALENT_IS_PREFERENCES_PAGE (page));
224 : :
225 : 0 : file = gtk_file_dialog_select_folder_finish (dialog, result, &error);
226 [ # # ]: 0 : if (file == NULL)
227 : : {
228 [ # # # # ]: 0 : if (!g_error_matches (error, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_CANCELLED) &&
229 : 0 : !g_error_matches (error, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_DISMISSED))
230 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
231 : :
232 [ # # ]: 0 : return;
233 : : }
234 : :
235 : 0 : settings = valent_preferences_page_get_settings (page, "share");
236 [ # # ]: 0 : g_settings_set_string (settings, "download-folder", g_file_peek_path (file));
237 : : }
238 : :
239 : : static void
240 : 0 : select_download_folder_action (GtkWidget *widget,
241 : : const char *action_name,
242 : : GVariant *parameter)
243 : : {
244 : 0 : ValentPreferencesPage *page = VALENT_PREFERENCES_PAGE (widget);
245 : 0 : g_autoptr (GtkFileDialog) dialog = NULL;
246 : 0 : GSettings *settings;
247 [ # # ]: 0 : g_autofree char *path = NULL;
248 : :
249 : 0 : dialog = g_object_new (GTK_TYPE_FILE_DIALOG,
250 : 0 : "title", _("Select download folder"),
251 : 0 : "accept-label", _("Open"),
252 : : "modal", TRUE,
253 : : NULL);
254 : :
255 : 0 : settings = valent_preferences_page_get_settings (page, "share");
256 : 0 : path = g_settings_get_string (settings, "download-folder");
257 [ # # # # ]: 0 : if (path != NULL && *path != '\0')
258 : : {
259 : 0 : g_autoptr (GFile) file = NULL;
260 : :
261 : 0 : file = g_file_new_for_path (path);
262 [ # # ]: 0 : gtk_file_dialog_set_initial_folder (dialog, file);
263 : : }
264 : :
265 : 0 : gtk_file_dialog_select_folder (dialog,
266 : 0 : GTK_WINDOW (gtk_widget_get_root (widget)),
267 : : NULL,
268 : : (GAsyncReadyCallback)gtk_file_dialog_select_folder_cb,
269 : : widget);
270 : 0 : }
271 : :
272 : : /*
273 : : * ValentPreferencesPage
274 : : */
275 : : static inline void
276 : 3 : valent_preferences_other_page_bind_context (ValentPreferencesOtherPage *self)
277 : : {
278 : 3 : ValentPreferencesPage *page = VALENT_PREFERENCES_PAGE (self);
279 : 6 : g_autofree char *download_folder = NULL;
280 : 3 : GSettings *settings = NULL;
281 : :
282 : : /* Commands
283 : : */
284 : 3 : settings = valent_preferences_page_get_settings (page, "runcommand");
285 : 3 : g_signal_connect_object (settings,
286 : : "changed::commands",
287 : : G_CALLBACK (valent_runcommand_preferences_populate),
288 : : self,
289 : : G_CONNECT_SWAPPED);
290 : 3 : valent_runcommand_preferences_populate (self);
291 : :
292 : : /* Share
293 : : */
294 : 3 : settings = valent_preferences_page_get_settings (page, "share");
295 : 3 : download_folder = g_settings_get_string (settings, "download-folder");
296 [ + - + - ]: 3 : if (download_folder == NULL || *download_folder == '\0')
297 : : {
298 : 3 : const char *user_download = NULL;
299 : :
300 : 3 : user_download = valent_get_user_directory (G_USER_DIRECTORY_DOWNLOAD);
301 : 3 : g_set_str (&download_folder, user_download);
302 : 3 : g_settings_set_string (settings, "download-folder", download_folder);
303 : : }
304 : :
305 : 3 : g_settings_bind_with_mapping (settings, "download-folder",
306 : 3 : self->download_folder_label, "label",
307 : : G_SETTINGS_BIND_GET,
308 : : on_download_folder_changed,
309 : : NULL,
310 : : NULL, NULL);
311 : 3 : }
312 : :
313 : : /*
314 : : * GObject
315 : : */
316 : : static void
317 : 3 : valent_preferences_other_page_dispose (GObject *object)
318 : : {
319 : 3 : GtkWidget *widget = GTK_WIDGET (object);
320 : :
321 : 3 : gtk_widget_dispose_template (widget, VALENT_TYPE_PREFERENCES_OTHER_PAGE);
322 : :
323 : 3 : G_OBJECT_CLASS (valent_preferences_other_page_parent_class)->dispose (object);
324 : 3 : }
325 : :
326 : : static void
327 : 27 : valent_preferences_other_page_notify (GObject *object,
328 : : GParamSpec *pspec)
329 : : {
330 : 27 : ValentPreferencesPage *page = VALENT_PREFERENCES_PAGE (object);
331 : 27 : ValentPreferencesOtherPage *self = VALENT_PREFERENCES_OTHER_PAGE (object);
332 : :
333 [ + + ]: 27 : if (g_strcmp0 (pspec->name, "context") == 0)
334 : : {
335 [ + - ]: 3 : if (valent_preferences_page_get_context (page) != NULL)
336 : 3 : valent_preferences_other_page_bind_context (self);
337 : : }
338 : :
339 [ - + ]: 27 : if (G_OBJECT_CLASS (valent_preferences_other_page_parent_class)->notify)
340 : 0 : G_OBJECT_CLASS (valent_preferences_other_page_parent_class)->notify (object,
341 : : pspec);
342 : 27 : }
343 : :
344 : : static void
345 : 2 : valent_preferences_other_page_class_init (ValentPreferencesOtherPageClass *klass)
346 : : {
347 : 2 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
348 : 2 : GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
349 : :
350 : 2 : object_class->dispose = valent_preferences_other_page_dispose;
351 : 2 : object_class->notify = valent_preferences_other_page_notify;
352 : :
353 : 2 : gtk_widget_class_set_template_from_resource (widget_class, "/plugins/gnome/valent-preferences-other-page.ui");
354 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentPreferencesOtherPage, command_list);
355 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentPreferencesOtherPage, download_folder_label);
356 : 2 : gtk_widget_class_install_action (widget_class, "preferences.add-command", NULL, add_command_action);
357 : 2 : gtk_widget_class_install_action (widget_class, "preferences.edit-command", "s", edit_command_action);
358 : 2 : gtk_widget_class_install_action (widget_class, "preferences.select-download-folder", NULL, select_download_folder_action);
359 : 2 : }
360 : :
361 : : static void
362 : 3 : valent_preferences_other_page_init (ValentPreferencesOtherPage *self)
363 : : {
364 : 3 : gtk_widget_init_template (GTK_WIDGET (self));
365 : 3 : gtk_list_box_set_sort_func (self->command_list, sort_commands, self, NULL);
366 : 3 : }
367 : :
|