94 private Gee.ArrayList<Gtk.Image>
themed_img_list =
new Gee.ArrayList<Gtk.Image>();
101 log_debug(
"SetupWizardWindow: SetupWizardWindow()");
103 this.title =
_(
"Setup Wizard");
107 this.set_icon_name(
"bastionguard-backup");
116 App.schedule_boot =
false;
117 App.schedule_hourly =
false;
118 App.schedule_daily =
true;
119 log_debug(
"Setting schedule_daily for first run");
120 App.schedule_weekly =
false;
121 App.schedule_monthly =
false;
133 log_debug(
"SetupWizardWindow: SetupWizardWindow(): exit");
141 root_box =
new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
142 root_box.hexpand =
true;
143 root_box.vexpand =
true;
144 root_box.halign = Gtk.Align.FILL;
145 root_box.valign = Gtk.Align.FILL;
157 sidebar =
new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
158 sidebar.set_size_request(220, -1);
159 sidebar.hexpand =
false;
160 sidebar.vexpand =
true;
161 sidebar.halign = Gtk.Align.FILL;
162 sidebar.valign = Gtk.Align.FILL;
163 sidebar.get_style_context().add_class(
"sidebar");
165 var sidebar_header =
new Gtk.Box(Gtk.Orientation.HORIZONTAL, 8);
166 sidebar_header.get_style_context().add_class(
"sidebar-header");
167 sidebar.append(sidebar_header);
169 Gtk.Widget logo_widget;
171 logo_widget =
new Gtk.Image.from_pixbuf(
IconManager.
lookup(
"bastionguard-backup", 48));
174 logo_widget =
themed_icon(
"emblem-default-symbolic", 48);
177 var title =
new Gtk.Label(
"BastionGuard™\nWizard");
181 title.max_width_chars = 14;
182 title.get_style_context().add_class(
"sidebar-title");
184 sidebar_header.append(logo_widget);
185 sidebar_header.append(title);
187 sidebar.append(
new Gtk.Box(Gtk.Orientation.VERTICAL, 0));
197 btn_nav_import.sensitive =
false;
198 btn_nav_backend.sensitive =
false;
199 btn_nav_estimate.sensitive =
false;
200 btn_nav_location.sensitive =
false;
201 btn_nav_schedule.sensitive =
false;
202 btn_nav_users.sensitive =
false;
203 btn_nav_finish.sensitive =
false;
205 var spacer =
new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
206 spacer.hexpand =
true;
207 spacer.vexpand =
true;
208 spacer.halign = Gtk.Align.FILL;
209 spacer.valign = Gtk.Align.FILL;
215 var btn =
new Gtk.Button();
216 btn.get_style_context().add_class(
"sidebar-button");
218 btn.margin_start = 8;
221 btn.margin_bottom = 2;
223 var row =
new Gtk.Box(Gtk.Orientation.HORIZONTAL, 10);
224 row.margin_start = 8;
227 row.margin_bottom = 8;
230 var lbl =
new Gtk.Label(label_text);
244 content_box =
new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
245 content_box.get_style_context().add_class(
"content");
246 content_box.hexpand =
true;
247 content_box.vexpand =
true;
248 content_box.halign = Gtk.Align.FILL;
249 content_box.valign = Gtk.Align.FILL;
251 header_box =
new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
252 header_box.margin_start = 20;
253 header_box.margin_end = 20;
254 header_box.margin_top = 20;
255 header_box.margin_bottom = 10;
258 lbl_page_title.xalign = 0.0f;
262 body_box =
new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
263 body_box.margin_start = 14;
264 body_box.margin_end = 14;
265 body_box.margin_bottom = 12;
266 body_box.hexpand =
true;
267 body_box.vexpand =
true;
268 body_box.halign = Gtk.Align.FILL;
269 body_box.valign = Gtk.Align.FILL;
271 stack =
new Gtk.Stack();
272 stack.transition_type = Gtk.StackTransitionType.CROSSFADE;
273 stack.transition_duration = 140;
274 stack.hexpand =
true;
275 stack.vexpand =
true;
276 stack.halign = Gtk.Align.FILL;
277 stack.valign = Gtk.Align.FILL;
290 backend_box.margin_start = 12;
291 backend_box.margin_end = 12;
292 backend_box.margin_top = 12;
293 backend_box.margin_bottom = 12;
296 estimate_box.margin_start = 12;
297 estimate_box.margin_end = 12;
298 estimate_box.margin_top = 12;
299 estimate_box.margin_bottom = 12;
302 backup_dev_box.margin_start = 12;
303 backup_dev_box.margin_end = 12;
304 backup_dev_box.margin_top = 12;
305 backup_dev_box.margin_bottom = 12;
308 schedule_box.margin_start = 12;
309 schedule_box.margin_end = 12;
310 schedule_box.margin_top = 12;
311 schedule_box.margin_bottom = 12;
315 users_box.margin_start = 12;
316 users_box.margin_end = 12;
317 users_box.margin_top = 12;
318 users_box.margin_bottom = 12;
321 finish_box.margin_start = 12;
322 finish_box.margin_end = 12;
323 finish_box.margin_top = 12;
324 finish_box.margin_bottom = 12;
334 stack.add_named(page_import,
"import");
335 stack.add_named(page_backend,
"backend");
336 stack.add_named(page_estimate,
"estimate");
337 stack.add_named(page_location,
"location");
338 stack.add_named(page_schedule,
"schedule");
339 stack.add_named(page_users,
"users");
340 stack.add_named(page_finish,
"finish");
346 timeshift_page_box.margin_start = 18;
347 timeshift_page_box.margin_end = 18;
348 timeshift_page_box.margin_top = 18;
349 timeshift_page_box.margin_bottom = 18;
350 timeshift_page_box.hexpand =
true;
351 timeshift_page_box.vexpand =
true;
354 lbl_timeshift_title.xalign = 0.0f;
358 _(
"If a Timeshift configuration is present on this system, BastionGuard can import compatible settings and detect existing backups without modifying or deleting the original data.")
360 lbl_timeshift_desc.xalign = 0.0f;
361 lbl_timeshift_desc.wrap =
true;
362 lbl_timeshift_desc.max_width_chars = 80;
365 lbl_timeshift_found.xalign = 0.0f;
366 lbl_timeshift_found.wrap =
true;
369 lbl_timeshift_path.xalign = 0.0f;
370 lbl_timeshift_path.wrap =
true;
371 lbl_timeshift_path.selectable =
true;
373 radio_import_yes =
new Gtk.CheckButton.with_label(
_(
"Yes, import from Timeshift"));
374 radio_import_no =
new Gtk.CheckButton.with_label(
_(
"No, configure manually"));
378 _(
"Import copies only compatible settings into BastionGuard. Original Timeshift files are not modified.")
380 lbl_timeshift_note.xalign = 0.0f;
381 lbl_timeshift_note.wrap =
true;
382 lbl_timeshift_note.max_width_chars = 80;
397 var card =
new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
398 card.get_style_context().add_class(
"card");
401 card.margin_start = 6;
404 card.margin_bottom = 6;
418 string[] candidate_paths = {
419 "/etc/timeshift/timeshift.json",
420 "/etc/timeshift.json"
423 foreach (
string path
in candidate_paths) {
447 foreach (var dev
in all_devices) {
449 if (dev.uuid.length == 0)
continue;
450 if (dev.fstype !=
"ext4" && dev.fstype !=
"ext3"
451 && dev.fstype !=
"btrfs" && dev.fstype !=
"xfs")
continue;
454 if (tmp_repo ==
null)
continue;
455 if (tmp_repo.mount_path.length == 0)
continue;
457 string[] snap_dirs = {
458 path_combine(tmp_repo.mount_path,
"timeshift/snapshots"),
459 path_combine(tmp_repo.mount_path,
"timeshift-btrfs/snapshots"),
460 path_combine(tmp_repo.mount_path,
"bastionguard-backup/snapshots"),
461 path_combine(tmp_repo.mount_path,
"bastionguard-backup-btrfs/snapshots")
464 foreach (var snap_dir
in snap_dirs) {
468 var dir = File.new_for_path(snap_dir);
469 var enumerator = dir.enumerate_children(
"standard::name,standard::type", 0);
470 var info = enumerator.next_file();
472 while (info !=
null) {
473 if (info.get_file_type() == FileType.DIRECTORY
474 && info.get_name() !=
".sync") {
477 info = enumerator.next_file();
484 App.backup_uuid = dev.uuid;
489 if (count > 0)
break;
498 var parser =
new Json.Parser();
499 parser.load_from_file(config_path);
501 Json.Node? node = parser.get_root();
502 Json.Object config = node?.get_object() ??
new Json.Object();
504 string backup_uuid =
json_get_string(config,
"backup_device_uuid",
"");
505 string parent_uuid =
json_get_string(config,
"parent_device_uuid",
"");
506 bool tmp_btrfs_mode =
json_get_bool(config,
"btrfs_mode",
false);
510 if (backup_uuid.length > 0) {
513 else if (parent_uuid.length > 0) {
517 if (tmp_repo ==
null) {
525 log_error(
"probe_timeshift_snapshot_count(): " + e.message);
533 lbl_timeshift_found.label =
_(
"No Timeshift configuration or backup was detected.");
534 lbl_timeshift_path.label =
"";
535 radio_import_yes.sensitive =
false;
536 radio_import_no.active =
true;
544 lbl_timeshift_path.label =
_(
"Backups detected on device UUID") +
": " +
App.
backup_uuid;
547 lbl_timeshift_path.label =
_(
"Timeshift backups detected by scanning available devices.");
552 lbl_timeshift_found.label =
_(
"Timeshift configuration found, but no importable backup was detected.");
555 lbl_timeshift_found.label =
_(
"Timeshift configuration found. 1 backup was detected.");
558 lbl_timeshift_found.label =
_(
"Timeshift configuration found. %d backups were detected.").printf(
timeshift_backup_count);
563 lbl_timeshift_found.label =
_(
"1 Timeshift backup was detected, but no Timeshift configuration file was found.");
566 lbl_timeshift_found.label =
_(
"%d Timeshift backups were detected, but no Timeshift configuration file was found.").printf(
timeshift_backup_count);
570 radio_import_yes.sensitive =
true;
573 radio_import_yes.active =
true;
600 _(
"Backup repository detected"),
601 _(
"Existing Timeshift backups were detected and will be used, but no Timeshift configuration file was found to import settings from."),
612 _(
"The Timeshift configuration could not be imported. BastionGuard may already have its own configuration, or the Timeshift configuration file may be invalid."),
627 _(
"Import completed"),
628 _(
"Timeshift settings were imported successfully into BastionGuard."),
641 actions_box =
new Gtk.Box(Gtk.Orientation.HORIZONTAL, 8);
642 actions_box.margin_start = 20;
643 actions_box.margin_end = 20;
644 actions_box.margin_bottom = 20;
645 actions_box.halign = Gtk.Align.END;
647 btn_prev =
new Gtk.Button.with_label(
_(
"Previous"));
648 btn_next =
new Gtk.Button.with_label(
_(
"Next"));
649 btn_close =
new Gtk.Button.with_label(
_(
"Finish"));
650 btn_cancel =
new Gtk.Button.with_label(
_(
"Cancel"));
657 btn_prev.get_style_context().add_class(
"btn-back");
658 btn_next.get_style_context().add_class(
"btn-next");
659 btn_close.get_style_context().add_class(
"btn-finish");
660 btn_close.get_style_context().add_class(
"suggested-action");
661 btn_cancel.get_style_context().add_class(
"btn-cancel");
689 btn_prev.visible = visible;
690 btn_next.visible = visible;
691 btn_close.visible = visible;
692 btn_cancel.visible = visible;
717 App.schedule_boot =
false;
718 App.schedule_hourly =
false;
719 App.schedule_daily =
false;
720 App.schedule_weekly =
false;
721 App.schedule_monthly =
false;
730 App.first_run =
false;
749 case Tabs.IMPORT_TIMESHIFT:
751 case Tabs.SNAPSHOT_BACKEND:
757 case Tabs.BACKUP_DEVICE:
787 case Tabs.IMPORT_TIMESHIFT:
794 case Tabs.SNAPSHOT_BACKEND:
807 case Tabs.BACKUP_DEVICE:
837 case Tabs.IMPORT_TIMESHIFT:
843 btn_prev.sensitive =
false;
844 btn_next.sensitive =
true;
845 btn_close.sensitive =
true;
850 case Tabs.SNAPSHOT_BACKEND:
856 btn_prev.sensitive =
true;
857 btn_next.sensitive =
true;
858 btn_close.sensitive =
true;
869 btn_prev.sensitive =
false;
870 btn_next.sensitive =
false;
871 btn_close.sensitive =
false;
883 case Tabs.BACKUP_DEVICE:
889 btn_prev.sensitive =
true;
890 btn_next.sensitive =
true;
891 btn_close.sensitive =
true;
902 btn_prev.sensitive =
true;
903 btn_next.sensitive =
true;
904 btn_close.sensitive =
true;
915 btn_prev.sensitive =
true;
916 btn_next.sensitive =
true;
917 btn_close.sensitive =
true;
928 btn_prev.sensitive =
false;
929 btn_next.sensitive =
false;
930 btn_close.sensitive =
true;
972 case Tabs.IMPORT_TIMESHIFT:
973 stack.set_visible_child_name(
"import");
975 case Tabs.SNAPSHOT_BACKEND:
976 stack.set_visible_child_name(
"backend");
979 stack.set_visible_child_name(
"estimate");
981 case Tabs.BACKUP_DEVICE:
982 stack.set_visible_child_name(
"location");
985 stack.set_visible_child_name(
"schedule");
988 stack.set_visible_child_name(
"users");
991 stack.set_visible_child_name(
"finish");
1005 case Tabs.IMPORT_TIMESHIFT:
1008 case Tabs.SNAPSHOT_BACKEND:
1014 case Tabs.BACKUP_DEVICE:
1031 case Tabs.IMPORT_TIMESHIFT:
1032 lbl_page_title.label =
_(
"Import from Timeshift");
1034 case Tabs.SNAPSHOT_BACKEND:
1035 lbl_page_title.label =
_(
"Backend");
1038 lbl_page_title.label =
_(
"Estimate");
1040 case Tabs.BACKUP_DEVICE:
1041 lbl_page_title.label =
_(
"Location");
1044 lbl_page_title.label =
_(
"Schedule");
1047 lbl_page_title.label =
_(
"Users");
1050 lbl_page_title.label =
_(
"Finish");
1056 btn_nav_import.get_style_context().remove_class(
"active-sidebar-button");
1057 btn_nav_backend.get_style_context().remove_class(
"active-sidebar-button");
1058 btn_nav_estimate.get_style_context().remove_class(
"active-sidebar-button");
1059 btn_nav_location.get_style_context().remove_class(
"active-sidebar-button");
1060 btn_nav_schedule.get_style_context().remove_class(
"active-sidebar-button");
1061 btn_nav_users.get_style_context().remove_class(
"active-sidebar-button");
1062 btn_nav_finish.get_style_context().remove_class(
"active-sidebar-button");
1066 btn.get_style_context().add_class(
"active-sidebar-button");
1071 IMPORT_TIMESHIFT = 0,
1072 SNAPSHOT_BACKEND = 1,
1096 img.set_from_pixbuf(pix);
1098 img.set_from_icon_name(name);
void stop(AppStatus status_to_update=AppStatus.CANCELLED)
BackupDeviceBox(Gtk.Window _parent_window)
static Gee.ArrayList< Device > get_block_devices_using_lsblk(string dev_name="")
void estimate_system_size()
EstimateBox(Gtk.Window _parent_window)
ExcludeBox(Gtk.Window _parent_window)
FinishBox(Gtk.Window _parent_window, bool _show_notes)
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 import_timeshift_config_if_available()
ScheduleBox(Gtk.Window _parent_window)
BackupDeviceBox backup_dev_box
Gee.ArrayList< string > themed_img_name
Gtk.? Button current_nav_btn
void reload_themed_icons()
void update_sidebar_state()
void set_sidebar_active(Gtk.Button btn)
bool run_timeshift_import()
SetupWizardWindow(bool embedded=false)
Gtk.Button btn_nav_backend
Gtk.CheckButton radio_import_yes
Gee.ArrayList< Gtk.Image > themed_img_list
void refresh_timeshift_page()
Gtk.Widget detach_root_widget()
Gtk.Button btn_nav_import
int timeshift_backup_count
Gtk.Button btn_nav_schedule
void clear_sidebar_selection()
Gtk.Label lbl_timeshift_title
Gtk.Label lbl_timeshift_note
Gtk.Image themed_icon(string icon_name, int size)
string timeshift_config_path
Gtk.Button btn_nav_location
void detect_timeshift_state()
Gtk.Button btn_nav_estimate
int probe_timeshift_snapshots_from_mounts()
void action_buttons_set_initial_visibility(bool visible)
Gtk.Label lbl_timeshift_found
bool timeshift_import_done
Gtk.Label lbl_timeshift_desc
Gtk.CheckButton radio_import_no
Gtk.Box timeshift_page_box
void build_timeshift_page()
Gtk.Label lbl_timeshift_path
bool validate_current_tab()
SnapshotBackendBox backend_box
Gtk.Button make_nav_button(string icon_name, string label_text)
Gtk.Widget wrap_page(Gtk.Widget child)
bool should_import_timeshift()
Gtk.Button btn_nav_finish
Gee.ArrayList< int > themed_img_size
signal void request_close()
int probe_timeshift_snapshot_count(string config_path)
SnapshotBackendBox(Gtk.Window _parent_window)
Gee.ArrayList< Snapshot?> snapshots
bool has_space(uint64 needed=0)
SnapshotRepo. from_uuid(string uuid, Gtk.Window? parent_win, bool btrfs_repo)
UsersBox(Gtk.Window _parent_window, ExcludeBox _exclude_box, bool _restore_mode)
bool file_exists(string file_path)
string path_combine(string path1, string path2)
bool dir_exists(string dir_path)
string json_get_string(Json.Object jobj, string member, string def_value)
bool json_get_bool(Json.Object jobj, string member, bool def_value)
void log_debug(string message)
void log_error(string message, bool highlight=false, bool is_warning=false)