[gnome-usage/tracker-powered-storage-view-wip: 95/103] storage: Add actionbar with delete action
- From: Petr Štětka <pstetka src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-usage/tracker-powered-storage-view-wip: 95/103] storage: Add actionbar with delete action
- Date: Tue, 2 Apr 2019 12:27:48 +0000 (UTC)
commit 4d9b4510be35243f6f57c253292aab36e327af30
Author: Petr Štětka <pstetka redhat com>
Date: Tue Aug 14 14:22:35 2018 +0200
storage: Add actionbar with delete action
data/ui/storage-actionbar.ui | 66 +++--------------------
data/ui/storage-view.ui | 6 +++
src/meson.build | 1 +
src/storage/storage-actionbar.vala | 86 ++++++++++++++++++++++++++++++
src/storage/storage-view-item.vala | 15 +++---
src/storage/storage-view-row.vala | 11 +++-
src/storage/storage-view.vala | 102 ++++++++++++++++++++++++++++++++----
src/storage/tracker-controller.vala | 10 ++--
8 files changed, 217 insertions(+), 80 deletions(-)
---
diff --git a/data/ui/storage-actionbar.ui b/data/ui/storage-actionbar.ui
index 1c5fda6..e45c6a2 100644
--- a/data/ui/storage-actionbar.ui
+++ b/data/ui/storage-actionbar.ui
@@ -3,71 +3,21 @@
<interface>
<requires lib="gtk+" version="3.12"/>
<template class="UsageStorageActionBar" parent="GtkActionBar">
- <property name="visible">True</property>
<child>
- <object class="GtkButton" id="move_to_button">
- <property name="label" translatable="yes">Move to</property>
- <property name="visible">False</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <signal name="clicked" handler="move_to_clicked" swapped="no"/>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="delete_button">
- <property name="label" translatable="yes">Delete</property>
- <property name="visible">False</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <signal name="clicked" handler="delete_clicked" swapped="no"/>
- <style>
- <class name="destructive-action"/>
- </style>
- </object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="move_to_trash_button">
- <property name="label" translatable="yes">Move to Trash</property>
- <property name="visible">False</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <signal name="clicked" handler="move_to_trash_clicked" swapped="no"/>
+ <object class="GtkLabel" id="size_label">
+ <property name="visible">True</property>
</object>
<packing>
- <property name="pack_type">end</property>
+ <property name="pack_type">start</property>
</packing>
</child>
+
<child>
- <object class="GtkButton" id="empty_folder_button">
- <property name="label" translatable="yes">Empty folder</property>
- <property name="visible">False</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <signal name="clicked" handler="empty_folder_clicked" swapped="no"/>
- </object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="restore_button">
- <property name="label" translatable="yes">Restore</property>
- <property name="visible">False</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <signal name="clicked" handler="restore_clicked" swapped="no"/>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="delete_from_trash_button">
- <property name="label" translatable="yes">Delete from Trash</property>
- <property name="visible">False</property>
+ <object class="GtkButton" id="delete_button">
+ <property name="label" translatable="yes">Delete...</property>
<property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <signal name="clicked" handler="delete_from_trash_clicked" swapped="no"/>
+ <property name="visible">True</property>
+ <signal name="clicked" handler="delete_clicked" swapped="no"/>
<style>
<class name="destructive-action"/>
</style>
diff --git a/data/ui/storage-view.ui b/data/ui/storage-view.ui
index 5296a6a..6f8173b 100644
--- a/data/ui/storage-view.ui
+++ b/data/ui/storage-view.ui
@@ -54,6 +54,12 @@
</style>
</object>
</child>
+
+ <child>
+ <object class="UsageStorageActionBar" id="actionbar">
+ </object>
+ </child>
+
</object>
</child>
<child>
diff --git a/src/meson.build b/src/meson.build
index 5f0774d..e31625f 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -29,6 +29,7 @@ vala_sources = [
'quit-process-dialog.vala',
'settings.vala',
'speedometer.vala',
+ 'storage/storage-actionbar.vala',
'storage/storage-graph.vala',
'storage/query-builder.vala',
'storage/storage-row-popover.vala',
diff --git a/src/storage/storage-actionbar.vala b/src/storage/storage-actionbar.vala
new file mode 100644
index 0000000..8b738eb
--- /dev/null
+++ b/src/storage/storage-actionbar.vala
@@ -0,0 +1,86 @@
+/* storage-actionbar.vala
+ *
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Petr Štětka <pstetka redhat com>
+ */
+
+namespace Usage
+{
+ [GtkTemplate (ui = "/org/gnome/Usage/ui/storage-actionbar.ui")]
+ public class StorageActionBar : Gtk.ActionBar
+ {
+ private unowned List<StorageViewItem> selected_items;
+
+ [GtkChild]
+ private Gtk.Label size_label;
+
+ public signal void refresh_listbox ();
+
+ public void update_selected_items(List<StorageViewItem> selected_items) {
+ this.selected_items = selected_items;
+
+ uint64 size = 0;
+ foreach(var item in selected_items) {
+ size += item.size;
+ }
+ size_label.label = _("%s selected").printf(Utils.format_size_values(size));
+ }
+
+ [GtkCallback]
+ private void delete_clicked() {
+ string display_message = _("Are you sure you want to permanently delete selected items?");
+
+ var dialog = new Gtk.MessageDialog ((GLib.Application.get_default() as
Application).get_window(), Gtk.DialogFlags.MODAL,
+ Gtk.MessageType.WARNING, Gtk.ButtonsType.OK_CANCEL, display_message);
+ dialog.secondary_text = _("If you delete these items, they will be permanently lost.");
+
+ if(dialog.run() == Gtk.ResponseType.OK) {
+ foreach(var item in selected_items) {
+ if(item.type == FileType.DIRECTORY && item.custom_type == "root_item")
+ delete_file(item.uri, false);
+ else
+ delete_file(item.uri, true);
+ }
+ refresh_listbox();
+ }
+ dialog.destroy();
+ }
+
+ private void delete_file(string uri, bool delete_basefile) {
+ var file = File.new_for_uri(uri);
+ var type = file.query_file_type (FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+
+ try {
+ if(type == FileType.DIRECTORY) {
+ FileInfo info;
+ FileEnumerator enumerator = file.enumerate_children("standard::*",
FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
+
+ while((info = enumerator.next_file(null)) != null) {
+ var child = file.get_child(info.get_name());
+ delete_file(child.get_uri(), true);
+ }
+ }
+
+ if(delete_basefile)
+ file.delete();
+ }
+ catch (Error e) {
+ stderr.printf ("Error: %s\n", e.message);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/storage/storage-view-item.vala b/src/storage/storage-view-item.vala
index 8749227..9251c8c 100644
--- a/src/storage/storage-view-item.vala
+++ b/src/storage/storage-view-item.vala
@@ -51,18 +51,21 @@ public class Usage.StorageViewItem : GLib.Object {
}
}
- public StorageViewItem.from_file (File file) {
- uri = file.get_uri ();
+ public static StorageViewItem? from_file(File file) {
+ var item = new StorageViewItem();
+ item.uri = file.get_uri ();
try {
var info = file.query_info (FileAttribute.STANDARD_SIZE + "," + FileAttribute.STANDARD_NAME +
"," + FileAttribute.STANDARD_TYPE + "," + FileAttribute.TRASH_ORIG_PATH,
FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
- name = info.get_name ();
- size = info.get_size ();
- type = info.get_file_type ();
+ item.name = info.get_name ();
+ item.size = info.get_size ();
+ item.type = info.get_file_type ();
} catch (GLib.Error error) {
- warning (error.message);
+ return null;
}
+
+ return item;
}
private void setup_tag_style () {
diff --git a/src/storage/storage-view-row.vala b/src/storage/storage-view-row.vala
index 4f50a06..7c0845e 100644
--- a/src/storage/storage-view-row.vala
+++ b/src/storage/storage-view-row.vala
@@ -56,7 +56,13 @@ public class Usage.StorageViewRow : Gtk.ListBoxRow {
}
}
- public StorageViewItem item;
+ public bool selected {
+ get { return check_button.active; }
+ }
+
+ public signal void check_button_toggled();
+
+ public StorageViewItem item;
public StorageViewRow.from_item (StorageViewItem item) {
this.item = item;
@@ -66,6 +72,9 @@ public class Usage.StorageViewRow : Gtk.ListBoxRow {
tag.get_style_context ().add_class (item.style_class);
check_button.visible = item.show_check_button;
+ check_button.toggled.connect(() => {
+ check_button_toggled();
+ });
if (item.type == FileType.DIRECTORY || item.custom_type != null)
tag.width_request = tag.height_request = 20;
diff --git a/src/storage/storage-view.vala b/src/storage/storage-view.vala
index 0841efb..665548e 100644
--- a/src/storage/storage-view.vala
+++ b/src/storage/storage-view.vala
@@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Felipe Borges <felipeborges gnome org>
+ * Petr Štětka <pstetka redhat com>
*/
using Tracker;
@@ -25,10 +26,6 @@ using GTop;
public class Usage.NewStorageView : Usage.View {
public const uint MIN_PERCENTAGE_SHOWN_FILES = 2;
- private Sparql.Connection connection;
- private TrackerController controller;
- private StorageQueryBuilder query_builder;
-
[GtkChild]
private Gtk.Label header_label;
@@ -44,10 +41,18 @@ public class Usage.NewStorageView : Usage.View {
[GtkChild]
private StorageGraph graph;
+ [GtkChild]
+ private StorageActionBar actionbar;
+
+ private Sparql.Connection connection;
+ private TrackerController controller;
+ private StorageQueryBuilder query_builder;
+
private StorageViewItem os_item = new StorageViewItem ();
private StorageRowPopover row_popover = new StorageRowPopover();
private uint storage_row_i = 0;
private uint? shown_rows_number = null;
+ private uint need_refresh_depth = 0;
private uint64 total_used_size = 0;
private uint64 total_free_size = 0;
@@ -61,6 +66,10 @@ public class Usage.NewStorageView : Usage.View {
UserDirectory.VIDEOS,
};
+ private List<StorageViewItem> selected_items = new List<StorageViewItem> ();
+ private Queue<List> selected_items_stack = new Queue<List> ();
+ private Queue<StorageViewItem> actual_item = new Queue<StorageViewItem> ();
+
construct {
name = "STORAGE";
title = _("Storage");
@@ -73,6 +82,23 @@ public class Usage.NewStorageView : Usage.View {
query_builder = new StorageQueryBuilder ();
controller = new TrackerController (connection);
+
+ actionbar.refresh_listbox.connect(() => {
+ var item = actual_item.peek_head();
+
+ stack_listbox_up();
+ clear_selected_items();
+
+ if(listbox.get_depth() >= 1) {
+ selected_items_stack.push_head((owned) selected_items);
+ actual_item.push_head(item);
+ present_dir.begin (item.uri, item.dir);
+ }
+ else
+ populate_view.begin ();
+
+ need_refresh_depth = listbox.get_depth();
+ });
}
public NewStorageView () {
@@ -88,16 +114,43 @@ public class Usage.NewStorageView : Usage.View {
var storage_row = row as StorageViewRow;
if(storage_row.item.custom_type == "up-folder") {
- shown_rows_number = null;
- storage_row_i = 0;
- listbox.pop();
- graph.model = (ListStore) listbox.get_model();
+ stack_listbox_up();
} else if (storage_row.item.type == FileType.DIRECTORY) {
+ selected_items_stack.push_head((owned) selected_items);
+ actual_item.push_head(storage_row.item);
+ clear_selected_items();
present_dir.begin (storage_row.item.uri, storage_row.item.dir);
} else if (storage_row.item.custom_type != null) {
row_popover.present(storage_row);
} else {
- AppInfo.launch_default_for_uri(storage_row.item.uri, null);
+ try {
+ AppInfo.launch_default_for_uri(storage_row.item.uri, null);
+ } catch (GLib.Error error) {
+ warning (error.message);
+ }
+ }
+ }
+
+ private void stack_listbox_up() {
+ shown_rows_number = null;
+ storage_row_i = 0;
+ selected_items = selected_items_stack.pop_head();
+ actual_item.pop_head();
+ refresh_actionbar();
+ listbox.pop();
+ graph.model = (ListStore) listbox.get_model();
+
+ if(need_refresh_depth >= listbox.get_depth()) {
+ var item = actual_item.peek_head();
+ need_refresh_depth -= 1;
+
+ clear_selected_items();
+ listbox.pop();
+
+ if(listbox.get_depth() == 0)
+ populate_view.begin ();
+ else
+ present_dir.begin (item.uri, item.dir);
}
}
@@ -111,6 +164,18 @@ public class Usage.NewStorageView : Usage.View {
var row = new StorageViewRow.from_item (item);
row.visible = true;
+ if(selected_items.find(item) != null)
+ row.check_button.active = true;
+
+ row.check_button_toggled.connect(() => {
+ if(row.selected)
+ selected_items.append(row.item);
+ else
+ selected_items.remove(row.item);
+
+ refresh_actionbar();
+ });
+
if(item.custom_type == "available-graph")
return new Gtk.ListBoxRow();
@@ -143,7 +208,7 @@ public class Usage.NewStorageView : Usage.View {
var model = yield controller.enumerate_children (uri, dir);
var file = File.new_for_uri (uri);
- var item = new StorageViewItem.from_file (file);
+ var item = StorageViewItem.from_file (file);
item.custom_type = "up-folder";
item.dir = dir;
controller.get_file_size.begin (item.uri, (obj, res) => {
@@ -224,13 +289,14 @@ public class Usage.NewStorageView : Usage.View {
foreach (var dir in xdg_folders) {
var file = File.new_for_uri (get_user_special_dir_path (dir));
- var item = new StorageViewItem.from_file (file);
+ var item = StorageViewItem.from_file (file);
item.dir = dir;
controller.get_file_size.begin (item.uri, (obj, res) => {
try {
item.size = controller.get_file_size.end (res);
item.percentage = item.size * 100 / (double) total_size;
+ item.custom_type = "root_item";
model.insert (1, item);
} catch (GLib.Error error) {
warning (error.message);
@@ -247,4 +313,18 @@ public class Usage.NewStorageView : Usage.View {
available_graph_item.percentage = available_graph_item.size * 100 / (double) total_size;
graph.model.append(available_graph_item);
}
+
+ private void refresh_actionbar() {
+ actionbar.update_selected_items(selected_items);
+
+ if(selected_items.length() == 0)
+ actionbar.hide();
+ else
+ actionbar.show();
+ }
+
+ private void clear_selected_items() {
+ selected_items = new List<StorageViewItem>();
+ refresh_actionbar();
+ }
}
diff --git a/src/storage/tracker-controller.vala b/src/storage/tracker-controller.vala
index d6e2621..222fab6 100644
--- a/src/storage/tracker-controller.vala
+++ b/src/storage/tracker-controller.vala
@@ -50,7 +50,11 @@ public class Usage.TrackerController : GLib.Object {
while (yield worker.fetch_next (out n_uri, out file_type)) {
try {
var file = File.new_for_uri (n_uri);
- var item = new StorageViewItem.from_file (file);
+ var item = StorageViewItem.from_file (file);
+
+ if(item == null)
+ continue;
+
item.ontology = file_type;
item.dir = dir;
@@ -89,10 +93,8 @@ public class Usage.TrackerController : GLib.Object {
return info.get_size ();
} catch (GLib.Error error) {
- warning (error.message);
+ return 0;
}
-
- return 0;
}
public async uint64 get_file_size (string uri) throws GLib.Error {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]