Skip to content
API Documentation
BastionGuard™
SettingsWindow.vala
Go to the documentation of this file.
1/*
2 * SettingsWindow.vala
3 *
4 * Copyright 2012-2018 Tony George <teejeetech@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 *
21 */
22
23using Gtk;
24using Gee;
25
26using TeeJee.Logging;
31using TeeJee.System;
32using TeeJee.Misc;
33
34class SettingsWindow : Gtk.Window {
35
36 public signal void request_close();
37
38 private Gtk.Box root_box;
39 private Gtk.Box sidebar;
40 private Gtk.Box content_box;
41 private Gtk.Box content_header_box;
42 private Gtk.Box content_body_box;
43 private Gtk.Box bottom_bar;
44
45 private Gtk.Stack stack;
46
53
54 private Gtk.Button btn_type;
55 private Gtk.Button btn_location;
56 private Gtk.Button btn_schedule;
57 private Gtk.Button btn_users;
58 private Gtk.Button btn_filters;
59 private Gtk.Button btn_misc;
60 private Gtk.Button btn_close;
61 private Gtk.Button btn_prev;
62 private Gtk.Button btn_next;
63
64 private Gtk.Label lbl_page_title;
65
66 private Gee.ArrayList<Gtk.Button> nav_buttons;
67
68 private uint tmr_init;
69 private int def_width = 1100;
70 private int def_height = 760;
71 private bool embedded_mode = false;
72
73 // Icon reload tracking for theme changes
74 private Gee.ArrayList<Gtk.Image> themed_img_list = new Gee.ArrayList<Gtk.Image>();
75 private Gee.ArrayList<string> themed_img_name = new Gee.ArrayList<string>();
76 private Gee.ArrayList<int> themed_img_size = new Gee.ArrayList<int>();
77
78 public SettingsWindow(bool embedded = false) {
79 embedded_mode = embedded;
80
81 log_debug("SettingsWindow: SettingsWindow()");
82
83 this.title = _("Settings");
84 if (!embedded_mode) {
85 this.modal = true;
86 }
87 this.set_icon_name("bastionguard-backup");
88 this.set_default_size(def_width, def_height);
89 this.set_default_size(def_width, def_height);
90 this.set_titlebar(HeaderFactory.create_main_headerbar(this, 230));
91 if (!embedded_mode)
92 this.close_request.connect(on_close_request);
93
94 nav_buttons = new Gee.ArrayList<Gtk.Button>();
95
96 build_ui();
99
100 if (!embedded_mode)
101 show();
102
103 activate_tab("type", btn_type, _("Type"));
104
105 tmr_init = Timeout.add(100, init_delayed);
106
107 log_debug("SettingsWindow: SettingsWindow(): exit");
108 }
109
110 private void build_ui() {
111
112 root_box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
113 root_box.hexpand = true;
114 root_box.vexpand = true;
115 root_box.halign = Gtk.Align.FILL;
116 root_box.valign = Gtk.Align.FILL;
117 set_child(root_box);
118
121
122 root_box.append(sidebar);
123 root_box.append(content_box);
124 }
125
126 private void build_sidebar() {
127
128 sidebar = new Gtk.Box(Gtk.Orientation.VERTICAL, 12);
129 sidebar.set_size_request(230, -1);
130 sidebar.hexpand = false;
131 sidebar.vexpand = true;
132 sidebar.halign = Gtk.Align.FILL;
133 sidebar.valign = Gtk.Align.FILL;
134 sidebar.get_style_context().add_class("sidebar");
135
136 var sidebar_header = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 8);
137 sidebar_header.margin_start = 12;
138 sidebar_header.margin_end = 12;
139 sidebar_header.margin_top = 12;
140 sidebar_header.margin_bottom = 12;
141 sidebar_header.get_style_context().add_class("sidebar-header");
142
143 Gtk.Widget logo_widget;
144 try {
145 logo_widget = new Gtk.Image.from_pixbuf(IconManager.lookup("bastionguard-backup", 48));
146 }
147 catch (Error e) {
148 logo_widget = themed_icon("preferences-system-symbolic", 48);
149 }
150
151 var title = new Gtk.Label("BastionGuard™\nSettings");
152 title.xalign = 0.0f;
153 title.yalign = 0.5f;
154 title.wrap = true;
155 title.max_width_chars = 14;
156 title.get_style_context().add_class("sidebar-title");
157
158 sidebar_header.append(logo_widget);
159 sidebar_header.append(title);
160
161 btn_type = create_nav_button("document-properties-symbolic", _("Type"));
162 btn_location = create_nav_button("drive-harddisk-symbolic", _("Location"));
163 btn_schedule = create_nav_button("x-office-calendar-symbolic", _("Schedule"));
164 btn_users = create_nav_button("system-users-symbolic", _("Users"));
165 btn_filters = create_nav_button("view-filter-symbolic", _("Filters"));
166 btn_misc = create_nav_button("preferences-other-symbolic", _("Misc"));
167 btn_close = create_nav_button("dialog-information-symbolic", _("Close"));
168
169 sidebar.append(sidebar_header);
170 sidebar.append(btn_type);
171 sidebar.append(btn_location);
172 sidebar.append(btn_schedule);
173 sidebar.append(btn_users);
174 sidebar.append(btn_filters);
175 sidebar.append(btn_misc);
176
177 var spacer = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
178 spacer.hexpand = true;
179 spacer.vexpand = true;
180 spacer.halign = Gtk.Align.FILL;
181 spacer.valign = Gtk.Align.FILL;
182 sidebar.append(spacer);
183
184 btn_close.margin_bottom = 12;
185 btn_close.margin_start = 8;
186 btn_close.margin_end = 8;
187 sidebar.append(btn_close);
188 }
189
190 private void build_content() {
191
192 content_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
193 content_box.hexpand = true;
194 content_box.vexpand = true;
195 content_box.halign = Gtk.Align.FILL;
196 content_box.valign = Gtk.Align.FILL;
197 content_box.get_style_context().add_class("content");
198
199 content_header_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
200 content_header_box.margin_start = 20;
201 content_header_box.margin_end = 20;
202 content_header_box.margin_top = 20;
203 content_header_box.margin_bottom = 20;
204 content_header_box.margin_bottom = 8;
205
206 lbl_page_title = new Gtk.Label(_("Settings"));
207 lbl_page_title.xalign = 0.0f;
208 lbl_page_title.get_style_context().add_class("title");
209
211
212 content_body_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
213 content_body_box.hexpand = true;
214 content_body_box.vexpand = true;
215 content_body_box.halign = Gtk.Align.FILL;
216 content_body_box.valign = Gtk.Align.FILL;
217 content_body_box.margin_start = 20;
218 content_body_box.margin_end = 20;
219 content_body_box.margin_bottom = 12;
220
221 stack = new Gtk.Stack();
222 stack.hexpand = true;
223 stack.vexpand = true;
224 stack.halign = Gtk.Align.FILL;
225 stack.valign = Gtk.Align.FILL;
226 stack.set_transition_duration(120);
227 stack.set_transition_type(Gtk.StackTransitionType.SLIDE_UP_DOWN);
228
229 content_body_box.append(stack);
230
231 bottom_bar = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 8);
232 bottom_bar.margin_start = 20;
233 bottom_bar.margin_end = 20;
234 bottom_bar.margin_bottom = 20;
235 bottom_bar.halign = Gtk.Align.END;
236
237 var btn_cancel = new Gtk.Button.with_label(_("Cancel"));
238 btn_cancel.set_size_request(110, -1);
239 btn_cancel.get_style_context().add_class("btn-cancel");
240
241 btn_prev = new Gtk.Button.with_label(_("Previous"));
242 btn_prev.set_size_request(110, -1);
243 btn_prev.get_style_context().add_class("btn-back");
244
245 btn_next = new Gtk.Button.with_label(_("Next"));
246 btn_next.set_size_request(110, -1);
247 btn_next.get_style_context().add_class("btn-next");
248
249 var btn_ok = new Gtk.Button.with_label(_("OK"));
250 btn_ok.set_size_request(110, -1);
251 btn_ok.get_style_context().add_class("btn-finish");
252 btn_ok.get_style_context().add_class("suggested-action");
253
254 bottom_bar.append(btn_cancel);
255 bottom_bar.append(btn_prev);
256 bottom_bar.append(btn_next);
257 bottom_bar.append(btn_ok);
258
259 btn_cancel.clicked.connect(() => {
261 else this.destroy();
262 });
263
264 btn_prev.clicked.connect(() => {
266 });
267
268 btn_next.clicked.connect(() => {
270 });
271
272 btn_ok.clicked.connect(() => {
273 save_changes();
275 else this.destroy();
276 });
277
280 content_box.append(bottom_bar);
281 }
282
283 private void build_pages() {
284
286 stack.add_named(backend_box, "type");
287
289 stack.add_named(backup_dev_box, "location");
290
291 schedule_box = new ScheduleBox(this);
292 stack.add_named(schedule_box, "schedule");
293
294 exclude_box = new ExcludeBox(this);
295 users_box = new UsersBox(this, exclude_box, false);
297
298 misc_box = new MiscBox(this, false);
299
300 stack.add_named(users_box, "users");
301 stack.add_named(exclude_box, "filters");
302 stack.add_named(misc_box, "misc");
303 }
304
305 private void connect_signals() {
306
307 btn_type.clicked.connect(() => {
308 activate_tab("type", btn_type, _("Type"));
309 });
310
311 btn_location.clicked.connect(() => {
312 activate_tab("location", btn_location, _("Location"));
313 });
314
315 btn_schedule.clicked.connect(() => {
316 activate_tab("schedule", btn_schedule, _("Schedule"));
317 });
318
319 btn_users.clicked.connect(() => {
320 activate_tab("users", btn_users, _("Users"));
321 });
322
323 btn_filters.clicked.connect(() => {
324 activate_tab("filters", btn_filters, _("Filters"));
325 });
326
327 btn_misc.clicked.connect(() => {
328 activate_tab("misc", btn_misc, _("Misc"));
329 });
330
331 btn_close.clicked.connect(() => {
333 else this.destroy();
334 });
335
336 backend_box.type_changed.connect(() => {
337 exclude_box.visible = !App.btrfs_mode;
340
341 if (App.btrfs_mode && stack.get_visible_child_name() == "filters") {
342 activate_tab("type", btn_type, _("Type"));
343 }
344
346 });
347 }
348
349 private Gtk.Button create_nav_button(string icon_name, string text) {
350
351 var btn = new Gtk.Button();
352 btn.hexpand = true;
353 btn.halign = Gtk.Align.FILL;
354 btn.margin_start = 8;
355 btn.margin_end = 8;
356 btn.get_style_context().add_class("sidebar-button");
357
358 var row = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 10);
359 row.margin_top = 8;
360 row.margin_bottom = 8;
361 row.margin_start = 10;
362 row.margin_end = 10;
363
364 var img = themed_icon(icon_name, 18);
365 var lbl = new Gtk.Label(text);
366 lbl.xalign = 0.0f;
367 lbl.hexpand = true;
368
369 row.append(img);
370 row.append(lbl);
371
372 btn.set_child(row);
373
374 nav_buttons.add(btn);
375
376 return btn;
377 }
378
379 private Gee.ArrayList<string> get_tab_order() {
380 var order = new Gee.ArrayList<string>();
381 order.add("type");
382 order.add("location");
383 order.add("schedule");
384 order.add("users");
385 if (!App.btrfs_mode)
386 order.add("filters");
387 order.add("misc");
388 return order;
389 }
390
391 private int get_current_tab_index() {
392 var order = get_tab_order();
393 var current = stack.get_visible_child_name();
394 for (int i = 0; i < order.size; i++) {
395 if (order[i] == current)
396 return i;
397 }
398 return 0;
399 }
400
401 private void activate_tab_by_name(string name) {
402 switch (name) {
403 case "type":
404 activate_tab("type", btn_type, _("Type"));
405 break;
406 case "location":
407 activate_tab("location", btn_location, _("Location"));
408 break;
409 case "schedule":
410 activate_tab("schedule", btn_schedule, _("Schedule"));
411 break;
412 case "users":
413 activate_tab("users", btn_users, _("Users"));
414 break;
415 case "filters":
416 activate_tab("filters", btn_filters, _("Filters"));
417 break;
418 case "misc":
419 activate_tab("misc", btn_misc, _("Misc"));
420 break;
421 }
422 }
423
424 private void activate_relative_tab(int delta) {
425 var order = get_tab_order();
426 int index = get_current_tab_index();
427 int target = index + delta;
428 if (target < 0 || target >= order.size)
429 return;
430 activate_tab_by_name(order[target]);
431 }
432
434 int index = get_current_tab_index();
435 int last = get_tab_order().size - 1;
436 btn_prev.sensitive = index > 0;
437 btn_next.sensitive = index < last;
438 }
439
440 private void activate_tab(string name, Gtk.Button active_button, string title_text) {
441
443
444 active_button.get_style_context().add_class("active-sidebar-button");
445 lbl_page_title.label = title_text;
446
447 if (stack != null) {
448 stack.set_visible_child_name(name);
449 }
450
452 }
453
454 private void clear_nav_selection() {
455 foreach (var btn in nav_buttons) {
456 btn.get_style_context().remove_class("active-sidebar-button");
457 }
458 }
459
460 private bool init_delayed() {
461
462 if (tmr_init > 0) {
463 Source.remove(tmr_init);
464 tmr_init = 0;
465 }
466
468 stack.set_visible_child_name("type");
469 activate_tab("type", btn_type, _("Type"));
470
471 this.set_default_size(def_width, def_height);
472
473 return false;
474 }
475
476 private bool on_close_request() {
477
478 save_changes();
479 return false;
480 }
481
482 public Gtk.Widget detach_root_widget() {
483 set_child(null);
484 return root_box;
485 }
486
487 private void save_changes() {
488
491 }
492
493 public enum Tabs {
494 BACKUP_TYPE = 0,
495 BACKUP_DEVICE = 1,
496 SCHEDULE = 2,
497 EXCLUDE = 3
498 }
499
500 // ── Icon theme support ──────────────────────────────────────────────
501 private Gtk.Image themed_icon(string icon_name, int size) {
502 var img = IconManager.lookup_image(icon_name, size);
503 themed_img_list.add(img);
504 themed_img_name.add(icon_name);
505 themed_img_size.add(size);
506 return img;
507 }
508
509 public void reload_themed_icons() {
510 for (int i = 0; i < themed_img_list.size; i++) {
511 var img = themed_img_list[i];
512 var name = themed_img_name[i];
513 var sz = themed_img_size[i];
514 var pix = IconManager.lookup(name, sz);
515 if (pix != null) {
516 img.set_from_pixbuf(pix);
517 } else {
518 img.set_from_icon_name(name);
519 }
520 }
521 }
522
523
524}
Main App
#define _(s)
BackupDeviceBox(Gtk.Window _parent_window)
void save_changes()
ExcludeBox(Gtk.Window _parent_window)
void set_users_box(UsersBox _users_box)
static Gtk.HeaderBar create_main_headerbar(Gtk.Window win, int left_width=215)
static Gdk.? Pixbuf lookup(string icon_name, int icon_size, bool symbolic=false, bool use_hardcoded=false, int scale=1)
static Gtk.Image lookup_image(string icon_name, int icon_size, bool symbolic=false, bool use_hardcoded=false)
bool btrfs_mode
Definition Main.vala:52
void cron_job_update()
Definition Main.vala:4463
MiscBox(Gtk.Window _parent_window, bool _restore_mode)
Definition MiscBox.vala:21
ScheduleBox(Gtk.Window _parent_window)
Gtk.Widget detach_root_widget()
BackupDeviceBox backup_dev_box
Gtk.Button btn_next
Gee.ArrayList< int > themed_img_size
Gtk.Button btn_type
ScheduleBox schedule_box
ExcludeBox exclude_box
signal void request_close()
Gtk.Button btn_schedule
Gtk.Button btn_filters
SettingsWindow(bool embedded=false)
void activate_tab_by_name(string name)
Gee.ArrayList< string > get_tab_order()
void activate_tab(string name, Gtk.Button active_button, string title_text)
Gtk.Image themed_icon(string icon_name, int size)
Gtk.Button btn_users
Gee.ArrayList< string > themed_img_name
Gtk.Button create_nav_button(string icon_name, string text)
void build_sidebar(ClamdConfig &config)
Gtk.Box content_header_box
Gee.ArrayList< Gtk.Image > themed_img_list
Gtk.Button btn_location
Gtk.Button btn_prev
SnapshotBackendBox backend_box
void activate_relative_tab(int delta)
Gtk.Button btn_misc
Gtk.Label lbl_page_title
void update_bottom_navigation()
Gee.ArrayList< Gtk.Button > nav_buttons
Gtk.Button btn_close
SnapshotBackendBox(Gtk.Window _parent_window)
signal void type_changed()
UsersBox(Gtk.Window _parent_window, ExcludeBox _exclude_box, bool _restore_mode)
Definition UsersBox.vala:26
void refresh()
void log_debug(string message)