Skip to content
API Documentation
BastionGuard™
SnapshotListBox.vala
Go to the documentation of this file.
1using Gtk;
2using Gee;
3
9using TeeJee.System;
10using TeeJee.Misc;
11
12class SnapshotRow : Gtk.ListBoxRow {
14 public Gtk.CheckButton check;
15 private Gtk.Entry desc_entry;
16
17 public SnapshotRow(Snapshot bak) {
18 snapshot = bak;
19 build_ui();
20 }
21
22 private void build_ui() {
23 var outer = new Gtk.Box(Gtk.Orientation.VERTICAL, 2);
24 outer.margin_top = 5;
25 outer.margin_bottom = 5;
26 outer.margin_start = 8;
27 outer.margin_end = 8;
28 set_child(outer);
29
30 var top = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 8);
31 outer.append(top);
32
33 check = new Gtk.CheckButton();
34 check.valign = Gtk.Align.START;
35 top.append(check);
36
37 var info = new Gtk.Box(Gtk.Orientation.VERTICAL, 2);
38 info.hexpand = true;
39 top.append(info);
40
41 var title = new Gtk.Label(null);
42 title.use_markup = true;
43 title.wrap = true;
44 title.xalign = 0.0f;
45 string line1 = GLib.Markup.escape_text(snapshot.date_formatted);
46 if (snapshot.live) {
47 line1 = "<b>%s</b>".printf(line1);
48 }
49 title.label = line1;
50 info.append(title);
51
52 var meta = new Gtk.Label(build_meta_text());
53 meta.wrap = true;
54 meta.xalign = 0.0f;
55 meta.add_css_class("dim-label");
56 info.append(meta);
57
58 desc_entry = new Gtk.Entry();
59 desc_entry.placeholder_text = _("Comments");
60 desc_entry.text = snapshot.description ?? "";
61 desc_entry.sensitive = !snapshot.marked_for_deletion;
62 // Mostra il campo commento solo se ha contenuto o se esplicitamente visibile
63 desc_entry.visible = (snapshot.description != null && snapshot.description.length > 0);
64 desc_entry.changed.connect(() => {
65 if (snapshot.description != desc_entry.text) {
66 snapshot.description = desc_entry.text;
68 }
69 });
70 info.append(desc_entry);
71
72 // Mostra campo commento al click del checkbox
73 check.toggled.connect(() => {
74 if (check.active) {
75 desc_entry.visible = true;
76 } else if (snapshot.description == null || snapshot.description.length == 0) {
77 desc_entry.visible = false;
78 }
79 });
80
82 add_css_class("error");
83 }
84 }
85
86 private string build_meta_text() {
87 var parts = new Gee.ArrayList<string>();
88 if ((snapshot.sys_distro ?? "").length > 0) {
89 parts.add(snapshot.sys_distro.replace("LinuxMint", "Linux Mint"));
90 }
91 if ((snapshot.taglist_short ?? "").length > 0) {
92 parts.add(_("Tags") + ": " + snapshot.taglist_short);
93 }
94 if (snapshot.btrfs_mode) {
95 int64 size = 0;
96 int64 unshared = 0;
97 if (snapshot.subvolumes.has_key("@")) {
98 size += snapshot.subvolumes["@"].total_bytes;
99 unshared += snapshot.subvolumes["@"].unshared_bytes;
100 }
101 if (snapshot.subvolumes.has_key("@home")) {
102 size += snapshot.subvolumes["@home"].total_bytes;
103 unshared += snapshot.subvolumes["@home"].unshared_bytes;
104 }
105 parts.add(_("Size") + ": " + format_file_size(size));
107 parts.add(_("Unshared") + ": " + format_file_size(unshared));
108 }
109 }
110 return string.joinv(" • ", parts.to_array());
111 }
112}
113
114class SnapshotListBox : Gtk.Box {
115 public Gtk.ListBox treeview;
116 private Gtk.Window parent_window;
117 private Gtk.ListBox listbox;
118 private Gtk.ScrolledWindow scrolled;
119 private Gtk.Box header_actions;
120 private int sort_column_index = 0;
121 private bool sort_desc = true;
122
123 public signal void delete_selected();
124 public signal void mark_selected();
125 public signal void browse_selected();
126 public signal void view_snapshot_log(bool show_restore_log);
127
128 public SnapshotListBox(Gtk.Window _parent_window) {
129 GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6);
130 parent_window = _parent_window;
131 margin_top = 6;
132 margin_bottom = 6;
133 margin_start = 6;
134 margin_end = 6;
135 build_ui();
136 refresh();
137 }
138
139 private void build_ui() {
140 header_actions = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
141 header_actions.halign = Gtk.Align.END;
142 append(header_actions);
143
144 add_sort_button(_("Newest"), 0, true);
145 add_sort_button(_("System"), 1, false);
146 add_sort_button(_("Tags"), 2, false);
147
148 listbox = new Gtk.ListBox();
149 listbox.selection_mode = Gtk.SelectionMode.NONE;
150 listbox.add_css_class("boxed-list");
151 listbox.row_activated.connect((row) => {
152 var snap_row = row as SnapshotRow;
153 if (snap_row != null) {
154 snap_row.check.active = !snap_row.check.active;
155 }
156 });
158
159 scrolled = new Gtk.ScrolledWindow();
160 scrolled.set_child(listbox);
161 scrolled.vexpand = false;
162 scrolled.hexpand = true;
163 scrolled.set_min_content_height(100);
164 scrolled.set_max_content_height(160);
165 scrolled.set_propagate_natural_height(true);
166 append(scrolled);
167
168 var footer = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
169 footer.halign = Gtk.Align.END;
170 append(footer);
171
172 var btn_browse = new Gtk.Button.with_label(_("Browse Files"));
173 btn_browse.add_css_class("btn-info");
174 btn_browse.clicked.connect(() => { browse_selected(); });
175 footer.append(btn_browse);
176
177 var btn_log_create = new Gtk.Button.with_label(_("Rsync Log (Create)"));
178 btn_log_create.sensitive = !App.btrfs_mode;
179 btn_log_create.add_css_class("btn-primary");
180 btn_log_create.clicked.connect(() => { view_snapshot_log(false); });
181 footer.append(btn_log_create);
182
183 var btn_log_restore = new Gtk.Button.with_label(_("Rsync Log (Restore)"));
184 btn_log_restore.sensitive = !App.btrfs_mode;
185 btn_log_restore.add_css_class("btn-primary");
186 btn_log_restore.clicked.connect(() => { view_snapshot_log(true); });
187 footer.append(btn_log_restore);
188
189 var btn_mark = new Gtk.Button.with_label(_("Mark/Unmark"));
190 btn_mark.add_css_class("btn-warning");
191 btn_mark.clicked.connect(() => { mark_selected(); });
192 footer.append(btn_mark);
193
194 var btn_delete = new Gtk.Button.with_label(_("Delete"));
195 btn_delete.add_css_class("btn-danger");
196 btn_delete.clicked.connect(() => { delete_selected(); });
197 footer.append(btn_delete);
198 }
199
200 private void add_sort_button(string label, int column, bool default_desc) {
201 var btn = new Gtk.Button.with_label(label);
202 btn.clicked.connect(() => {
203 if (sort_column_index == column) {
205 } else {
206 sort_column_index = column;
207 sort_desc = default_desc;
208 }
209 refresh();
210 });
211 header_actions.append(btn);
212 }
213
214 public void hide_context_menu() {
215 // no-op in GTK4 list implementation
216 }
217
218 private void clear_rows() {
219 Gtk.Widget? child = listbox.get_first_child();
220 while (child != null) {
221 Gtk.Widget? next = child.get_next_sibling();
222 listbox.remove(child);
223 child = next;
224 }
225 }
226
227 public void refresh() {
228 clear_rows();
229 if ((App.repo == null) || !App.repo.available()) {
230 return;
231 }
232
234 var list = App.repo.snapshots;
235
236 if (sort_column_index == 0) {
237 if (sort_desc) {
238 list.sort((a,b) => ((Snapshot)a).date.compare(((Snapshot)b).date));
239 } else {
240 list.sort((a,b) => -1 * (((Snapshot)a).date.compare(((Snapshot)b).date)));
241 }
242 } else if (sort_column_index == 1) {
243 if (sort_desc) {
244 list.sort((a,b) => strcmp(((Snapshot)b).sys_distro, ((Snapshot)a).sys_distro));
245 } else {
246 list.sort((a,b) => strcmp(((Snapshot)a).sys_distro, ((Snapshot)b).sys_distro));
247 }
248 } else {
249 if (sort_desc) {
250 list.sort((a,b) => strcmp(((Snapshot)b).taglist, ((Snapshot)a).taglist));
251 } else {
252 list.sort((a,b) => strcmp(((Snapshot)a).taglist, ((Snapshot)b).taglist));
253 }
254 }
255
256 foreach (Snapshot bak in list) {
257 listbox.append(new SnapshotRow(bak));
258 }
259 }
260
261 public Gee.ArrayList<Snapshot> selected_snapshots() {
262 var list = new Gee.ArrayList<Snapshot>();
263 Gtk.Widget? child = listbox.get_first_child();
264 while (child != null) {
265 var row = child as SnapshotRow;
266 if ((row != null) && row.check.active) {
267 list.add(row.snapshot);
268 }
269 child = child.get_next_sibling();
270 }
271 return list;
272 }
273}
Main App
#define _(s)
SnapshotRepo repo
Definition Main.vala:70
bool btrfs_mode
Definition Main.vala:52
bool btrfs_qgroups_enabled
Definition Main.vala:182
Gtk.ScrolledWindow scrolled
signal void browse_selected()
void add_sort_button(string label, int column, bool default_desc)
SnapshotListBox(Gtk.Window _parent_window)
Gee.ArrayList< Snapshot > selected_snapshots()
signal void view_snapshot_log(bool show_restore_log)
signal void mark_selected()
signal void delete_selected()
Gee.ArrayList< Snapshot?> snapshots
bool load_snapshots()
string build_meta_text()
SnapshotRow(Snapshot bak)
Gtk.Entry desc_entry
Gtk.CheckButton check
string description
Definition Snapshot.vala:42
string sys_distro
Definition Snapshot.vala:40
Gee.HashMap< string, Subvolume > subvolumes
Definition Snapshot.vala:46
bool live
Definition Snapshot.vala:50
void update_control_file()
bool btrfs_mode
Definition Snapshot.vala:56
string taglist_short
string date_formatted
Definition Snapshot.vala:95
bool marked_for_deletion
Definition Snapshot.vala:51
string format_file_size(uint64 size, bool binary_units=false, string unit="", bool show_units=true, int decimals=1)