[gnome-usage/tracker-powered-storage-view-wip: 80/103] storage: Add the new Storage panel
- From: Petr Štětka <pstetka src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-usage/tracker-powered-storage-view-wip: 80/103] storage: Add the new Storage panel
- Date: Tue, 2 Apr 2019 12:26:32 +0000 (UTC)
commit 1f92dc8fec5aa09b1d78112d4c1adc3bf2eb8d0a
Author: Felipe Borges <felipeborges gnome org>
Date: Thu Mar 22 11:07:29 2018 +0100
storage: Add the new Storage panel
See #29
data/interface/adwaita.css | 51 ++++++++--
data/org.gnome.Usage.gresource.xml | 1 +
data/ui/storage-view-row.ui | 55 +++++++++++
data/ui/storage-view.ui | 99 ++++++++++---------
src/meson.build | 6 ++
src/storage-graph.vala | 138 ++++++++++++--------------
src/storage-view.vala | 4 -
src/storage/query-builder.vala | 32 ++++++
src/storage/storage-view-item.vala | 103 ++++++++++++++++++++
src/storage/storage-view-row.vala | 69 +++++++++++++
src/storage/storage-view.vala | 187 ++++++++++++++++++++++++++++++++++++
src/storage/tracker-controller.vala | 123 ++++++++++++++++++++++++
src/storage/tracker-worker.vala | 44 +++++++++
src/window.vala | 2 +-
14 files changed, 779 insertions(+), 135 deletions(-)
---
diff --git a/data/interface/adwaita.css b/data/interface/adwaita.css
index db63a7c..3fc3578 100644
--- a/data/interface/adwaita.css
+++ b/data/interface/adwaita.css
@@ -82,14 +82,6 @@ ColorRectangle.available-storage, StorageGraph.available-storage {
color: #d3d7cf;
}
-row.folders, list.folders {
- color: #457fd3;
-}
-
-box.storage {
- background-color: #ffffff;
-}
-
/* Speedometer */
.speedometer-outter, .speedometer-inner, .speedometer-content-area {
border-radius: 50%;
@@ -129,3 +121,46 @@ box.storage {
.tag.tag-user {
background: alpha(@theme_fg_color, 0.4);
}
+
+.row_tag {
+ border-radius: 100%;
+}
+
+/* Storage */
+.storage-list:last-child {
+ background: @theme_bg_color;
+}
+
+.row-tag {
+ border-radius: 100%;
+}
+
+.used-tag {
+ background-image:
+ linear-gradient(90deg,
+ #737373 33%,
+ #ffe451 33%,
+ #ffe451 66%,
+ #ff002c 66%);
+}
+
+.available-tag { background: white; border: 1px solid @borders; }
+.os-tag { background: black; }
+
+.folders { background: #737373; }
+.files { background: #cdcdcd; }
+.downloads { background: #ffe451; }
+.pictures { background: #2493d3; }
+.videos { background: #a77aa5; }
+.documents { background: #7be95a; }
+.music { background: #f9a14a; }
+
+.stack-children .storage-row {
+ border-bottom: 1px solid @borders;
+}
+
+.stack-children { background: #fafafa; } /* FIXME: Doesn't work with other themes. */
+
+box.storage {
+ background-color: #ffffff;
+}
diff --git a/data/org.gnome.Usage.gresource.xml b/data/org.gnome.Usage.gresource.xml
index de8eece..490df5a 100644
--- a/data/org.gnome.Usage.gresource.xml
+++ b/data/org.gnome.Usage.gresource.xml
@@ -11,6 +11,7 @@
<file preprocess="xml-stripblanks">ui/speedometer.ui</file>
<file preprocess="xml-stripblanks">ui/storage-actionbar.ui</file>
<file preprocess="xml-stripblanks">ui/storage-view.ui</file>
+ <file preprocess="xml-stripblanks">ui/storage-view-row.ui</file>
<file preprocess="xml-stripblanks">ui/process-row.ui</file>
<file preprocess="xml-stripblanks">ui/swap-speedometer.ui</file>
</gresource>
diff --git a/data/ui/storage-view-row.ui b/data/ui/storage-view-row.ui
new file mode 100644
index 0000000..1a57d49
--- /dev/null
+++ b/data/ui/storage-view-row.ui
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.9 -->
+ <template class="UsageStorageViewRow" parent="GtkListBoxRow">
+ <property name="visible">True</property>
+ <style>
+ <class name="storage-row"/>
+ </style>
+
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="spacing">10</property>
+ <property name="margin">10</property>
+
+ <child>
+ <object class="GtkBox" id="tag">
+ <property name="visible">True</property>
+ <property name="width-request">15</property>
+ <property name="height-request">15</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <style>
+ <class name="row-tag"/>
+ <class name="circular"/>
+ </style>
+ </object>
+ <packing>
+ <property name="pack-type">start</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkLabel" id="title">
+ <property name="visible">True</property>
+ <property name="ellipsize">middle</property>
+ </object>
+ <packing>
+ <property name="pack-type">start</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkLabel" id="size_label">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/storage-view.ui b/data/ui/storage-view.ui
index 00b1974..5296a6a 100644
--- a/data/ui/storage-view.ui
+++ b/data/ui/storage-view.ui
@@ -1,82 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.9 -->
- <template class="UsageStorageView" parent="UsageView">
+ <template class="UsageNewStorageView" parent="UsageView">
<property name="visible">True</property>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<child>
- <object class="GtkSpinner">
+ <object class="GtkPaned">
<property name="visible">True</property>
- <property name="active">True</property>
- </object>
- <packing>
- <property name="name">spinner</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
+ <property name="orientation">horizontal</property>
+ <property name="position">360</property>
<child>
- <object class="GtkPaned" id="paned">
+ <object class="GtkBox">
<property name="visible">True</property>
- <property name="orientation">horizontal</property>
- <property name="position">300</property>
+ <property name="orientation">vertical</property>
+ <style><class name="view"/></style>
+
+ <child>
+ <object class="GtkLabel" id="header_label">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ <property name="margin">10</property>
+ <property name="label" translatable="yes">Home Partition</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+
<child>
- <object class="GtkScrolledWindow" id="scrolled_window">
+ <object class="UsageStorageViewRow" id="used_row">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Used</property>
+ <property name="tag_size">1</property>
+ </object>
+ </child>
+
+ <child>
+ <object class="UsageStorageViewRow" id="available_row">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Available</property>
+ <property name="tag_size">1</property>
+ </object>
+ </child>
+
+ <child>
+ <object class="DzlStackList" id="listbox">
<property name="visible">True</property>
<property name="vexpand">True</property>
+ <style>
+ <class name="storage-list"/>
+ </style>
</object>
</child>
</object>
</child>
<child>
- <object class="GtkRevealer" id="revealer">
+ <object class="GtkBox">
<property name="visible">True</property>
- <property name="transition-type">slide-up</property>
- <property name="transition-duration">400</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="UsageStorageGraph" id="graph">
+ <property name="visible">True</property>
+ <property name="expand">True</property>
+ </object>
+ </child>
</object>
</child>
</object>
- <packing>
- <property name="name">content</property>
- </packing>
</child>
<child>
- <object class="GtkBox">
+ <object class="GtkSpinner">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="valign">center</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="icon-name">folder-symbolic</property>
- <property name="pixel-size">128</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="margin-top">10</property>
- <property name="label" translatable="yes">No content here</property>
- <style>
- <class name="dim-label"/>
- </style>
- <attributes>
- <attribute name="weight" value="bold"/>
- <attribute name="scale" value="1.66"/>
- </attributes>
- </object>
- </child>
+ <property name="active">True</property>
</object>
<packing>
- <property name="name">empty</property>
+ <property name="name">spinner</property>
</packing>
</child>
</object>
</child>
-
</template>
</interface>
diff --git a/src/meson.build b/src/meson.build
index 7e44f2b..452cb8d 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -29,6 +29,12 @@ vala_sources = [
'quit-process-dialog.vala',
'settings.vala',
'speedometer.vala',
+ 'storage/query-builder.vala',
+ 'storage/storage-view-item.vala',
+ 'storage/storage-view.vala',
+ 'storage/storage-view-row.vala',
+ 'storage/tracker-controller.vala',
+ 'storage/tracker-worker.vala',
'storage-actionbar.vala',
'storage-analyzer.vala',
'storage-graph.vala',
diff --git a/src/storage-graph.vala b/src/storage-graph.vala
index 6605640..87234c1 100644
--- a/src/storage-graph.vala
+++ b/src/storage-graph.vala
@@ -24,6 +24,15 @@ namespace Usage
{
public class StorageGraph : Gtk.DrawingArea
{
+ private GLib.ListStore _model;
+ public GLib.ListStore model {
+ set {
+ _model = value;
+ this.draw.connect(draw_storage_graph);
+ this.queue_draw ();
+ }
+ get { return _model; }
+ }
public const uint MIN_PERCENTAGE_SHOWN_FILES = 2;
class construct
@@ -33,7 +42,6 @@ namespace Usage
public StorageGraph()
{
- this.draw.connect(draw_storage_graph);
}
public enum Circle
@@ -48,63 +56,35 @@ namespace Usage
double start_angle = 0;
double final_angle = - Math.PI / 2.0;
double ratio = 0;
- var fill_color = Gdk.RGBA();
var background_color =
get_toplevel().get_style_context().get_background_color(get_toplevel().get_style_context().get_state());
for(int i = 0; i < model.get_n_items(); i++)
{
- StorageItem item = (StorageItem) model.get_item(i);
- if(item.get_percentage() > 0 && item.get_item_type() != StorageItemType.STORAGE &&
item.get_section() == section)
- {
+ var item = model.get_item(i) as StorageViewItem;
+ //StorageViewRow item = (StorageViewRow) model.get_item(i);
+ //if(item.percentage > 0)
+ //{
var style_context = get_style_context();
- switch(item.get_item_type())
- {
- case StorageItemType.SYSTEM:
- style_context.add_class("system");
- fill_color = style_context.get_color(style_context.get_state());
- style_context.remove_class("system");
- break;
- case StorageItemType.TRASH:
- style_context.add_class("trash");
- fill_color = style_context.get_color(style_context.get_state());
- style_context.remove_class("trash");
- break;
- case StorageItemType.USER:
- style_context.add_class("user");
- fill_color = style_context.get_color(style_context.get_state());
- style_context.remove_class("user");
- break;
- case StorageItemType.AVAILABLE:
- style_context.add_class("available-storage");
- fill_color = style_context.get_color(style_context.get_state());
- style_context.remove_class("available-storage");
- break;
- case StorageItemType.DOCUMENTS:
- case StorageItemType.DOWNLOADS:
- case StorageItemType.DESKTOP:
- case StorageItemType.MUSIC:
- case StorageItemType.PICTURES:
- case StorageItemType.VIDEOS:
- case StorageItemType.DIRECTORY:
- case StorageItemType.FILE:
- fill_color = item.get_color();
- break;
- }
+ style_context.add_class(item.style_class);
+ var base_color = style_context.get_background_color(style_context.get_state());
+ style_context.remove_class(item.style_class);
+
+ Gdk.RGBA fill_color = generate_color(base_color, i, model.get_n_items ());
context.set_line_width (2.0);
start_angle = final_angle;
- ratio = ratio + ((double) item.get_percentage() / 100);
+ ratio = ratio + ((double) item.percentage / 100);
final_angle = ratio * 2 * Math.PI - Math.PI / 2.0;
context.move_to (x, y);
Gdk.cairo_set_source_rgba (context, fill_color);
context.arc (x, y, radius, start_angle, final_angle);
- if(item.get_percentage() == 100)
+ if(item.percentage == 100)
context.fill();
else
context.fill_preserve();
Gdk.cairo_set_source_rgba (context, background_color);
context.stroke();
- if(item.get_percentage() > MIN_PERCENTAGE_SHOWN_FILES)
+ if(item.percentage > MIN_PERCENTAGE_SHOWN_FILES)
{
double midle_angle = start_angle + (final_angle - start_angle) / 2;
midle_angle += Math.PI / 2;
@@ -166,10 +146,10 @@ namespace Usage
}
space -= SIDE_MARGIN;
x_text += SIDE_MARGIN;
- draw_text(context, item.get_name(), x_text, y_text, quadrant, space);
+ draw_text(context, item.name, x_text, y_text, quadrant, space);
}
}
- }
+ //}
}
private void draw_text(Cairo.Context context, string text, double x, double y, CornerType
start_corner, double width)
@@ -204,45 +184,55 @@ namespace Usage
int height = this.get_allocated_height ();
int width = this.get_allocated_width ();
- var storage_list_box = ((StorageView) (GLib.Application.get_default() as
Application).get_window().get_views()[Views.STORAGE]).get_storage_list_box();
- var model = storage_list_box.get_model();
-
- var two_graphs = false;
- if(storage_list_box.get_root() && StorageAnalyzer.get_default().get_separate_home())
- two_graphs = true;
-
double x = 0;
double y = 0;
double radius = 0;
- if(two_graphs)
+
+ radius = int.min (width, height) / 2.0;
+ radius -= radius / 3;
+ x = width / 2.0;
+ y = height / 2.0;
+
+ draw_circle(context, model, x, y, radius, 0, Circle.HOME);
+
+ return true;
+ }
+
+ private Gdk.RGBA generate_color(Gdk.RGBA default_color, uint order, uint all_color, bool reverse =
false)
+ {
+ if(order >= all_color)
+ order = all_color - 1;
+
+ order += 1;
+
+ double step = 100 / all_color;
+ if(all_color % 2 == 1)
+ {
+ if((all_color / 2) + 1 == order)
+ return default_color;
+ else
+ step = 100 / (all_color - 1);
+ }
+
+ if(order > (all_color / 2))
{
- double border = 5.5;
- radius = int.min (width, height) / 3.5;
- x = width / 1.8;
- x -= x / border;
- y = height / 2.1;
- y -= y / border;
- draw_circle(context, model, x, y, radius, 0, Circle.HOME);
-
- border = 1.75;
- radius = int.min (width, height) / 11.0;
- x = width / 2.0;
- x += x / border;
- y = height / 1.9;
- y += y / border;
- draw_circle(context, model, x, y, radius, 1, Circle.ROOT);
+ if(all_color % 2 == 1)
+ order -= 1;
+ double percentage = step * (order - (all_color/2));
+ if(reverse)
+ return Utils.color_lighter(default_color, percentage);
+ else
+ return Utils.color_darker(default_color, percentage);
}
else
{
- radius = int.min (width, height) / 2.0;
- radius -= radius / 3;
- x = width / 2.0;
- y = height / 2.0;
-
- draw_circle(context, model, x, y, radius, 0, Circle.BASE);
+ double percentage = step * ((all_color/2) - (order-1));
+ if(reverse)
+ return Utils.color_darker(default_color, percentage);
+ else
+ return Utils.color_lighter(default_color, percentage);
}
-
- return true;
}
+
}
}
diff --git a/src/storage-view.vala b/src/storage-view.vala
index 3ab1d0b..e26974b 100644
--- a/src/storage-view.vala
+++ b/src/storage-view.vala
@@ -27,16 +27,12 @@ namespace Usage
private StorageListBox storage_list_box;
private StorageActionBar action_bar;
- [GtkChild]
private Gtk.Revealer revealer;
- [GtkChild]
private Gtk.Stack stack;
- [GtkChild]
private Gtk.ScrolledWindow scrolled_window;
- [GtkChild]
private Gtk.Paned paned;
public StorageView ()
diff --git a/src/storage/query-builder.vala b/src/storage/query-builder.vala
new file mode 100644
index 0000000..4ca82cb
--- /dev/null
+++ b/src/storage/query-builder.vala
@@ -0,0 +1,32 @@
+/* query-builder.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: Felipe Borges <felipeborges gnome org>
+ */
+
+public class Usage.StorageQueryBuilder {
+ public string enumerate_children (string uri, bool recursive = false) {
+ string filter;
+ if (recursive) {
+ filter = @"tracker:uri-is-descendant ('$uri', ?uri)";
+ } else {
+ filter = @"tracker:uri-is-parent ('$uri', ?uri)";
+ }
+
+ return @"SELECT ?uri rdf:type(?u) { ?u nie:url ?uri . FILTER($filter) }";
+ }
+}
diff --git a/src/storage/storage-view-item.vala b/src/storage/storage-view-item.vala
new file mode 100644
index 0000000..54e0a52
--- /dev/null
+++ b/src/storage/storage-view-item.vala
@@ -0,0 +1,103 @@
+/* storage-view-item.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: Felipe Borges <felipeborges gnome org>
+ */
+
+public class Usage.StorageViewItem : GLib.Object {
+ public double percentage { set; get; }
+
+ public string uri;
+ public string name;
+ public uint64 size;
+
+ public FileType type;
+ public UserDirectory? dir;
+ public string ontology;
+
+ private string _style_class = null;
+ public string style_class {
+ protected set {
+ _style_class = value;
+ }
+ get {
+ if (_style_class != null)
+ return _style_class;
+
+ setup_tag_style ();
+
+ return _style_class;
+ }
+ }
+
+ public StorageViewItem.from_file (File file) {
+ 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 ();
+ } catch (GLib.Error error) {
+ warning (error.message);
+ }
+ }
+
+ private void setup_tag_style () {
+ if (type == FileType.DIRECTORY) {
+ style_class = "folders";
+ }
+
+ if (dir != null) {
+ switch (dir) {
+ case UserDirectory.PICTURES:
+ style_class = "pictures";
+ break;
+ case UserDirectory.VIDEOS:
+ style_class = "videos";
+ break;
+ case UserDirectory.DOCUMENTS:
+ style_class = "documents";
+ break;
+ case UserDirectory.MUSIC:
+ style_class = "music";
+ break;
+ }
+ } else {
+ switch (ontology) {
+ case "nmm#MusicPiece":
+ style_class = "music";
+ break;
+ case "nmm#Photo":
+ style_class = "pictures";
+ break;
+ case "nmm#Video":
+ style_class = "videos";
+ break;
+ case "nfo#PaginatedTextDocument":
+ case "nfo#PlainTextDocument":
+ case "nfo#FileDataObject":
+ case "nfo#EBook":
+ style_class = "documents";
+ break;
+ }
+ }
+
+ if (_style_class == null)
+ style_class = "files";
+ }
+}
diff --git a/src/storage/storage-view-row.vala b/src/storage/storage-view-row.vala
new file mode 100644
index 0000000..2e9170b
--- /dev/null
+++ b/src/storage/storage-view-row.vala
@@ -0,0 +1,69 @@
+/* storage-view-row.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: Felipe Borges <felipeborges gnome org>
+ */
+
+[GtkTemplate (ui = "/org/gnome/Usage/ui/storage-view-row.ui")]
+public class Usage.StorageViewRow : Gtk.ListBoxRow {
+ public string label {
+ set {
+ title.label = value;
+ }
+ get {
+ return title.label;
+ }
+ }
+
+ [GtkChild]
+ private Gtk.Label title;
+
+ [GtkChild]
+ public Gtk.Label size_label;
+
+ [GtkChild]
+ public Gtk.Box tag;
+
+ public enum TagSize {
+ SMALL,
+ BIG,
+ }
+ public TagSize tag_size {
+ set {
+ if (value == TagSize.BIG) {
+ tag.width_request = tag.height_request = 20;
+ }
+ }
+ get {
+ return (tag.width_request == 20 ? TagSize.BIG : TagSize.SMALL);
+ }
+ }
+
+ public StorageViewItem item;
+
+ public StorageViewRow.from_item (StorageViewItem item) {
+ this.item = item;
+
+ title.label = item.name;
+ size_label.label = Utils.format_size_values (item.size);
+
+ tag.get_style_context ().add_class (item.style_class);
+
+ if (item.type == FileType.DIRECTORY)
+ tag.width_request = tag.height_request = 20;
+ }
+}
diff --git a/src/storage/storage-view.vala b/src/storage/storage-view.vala
new file mode 100644
index 0000000..ef4d930
--- /dev/null
+++ b/src/storage/storage-view.vala
@@ -0,0 +1,187 @@
+/* storage-view.vala
+ *
+ * Copyright (C) 2017 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: Felipe Borges <felipeborges gnome org>
+ */
+
+using Tracker;
+using GTop;
+
+[GtkTemplate (ui = "/org/gnome/Usage/ui/storage-view.ui")]
+public class Usage.NewStorageView : Usage.View {
+ private Sparql.Connection connection;
+ private TrackerController controller;
+ private StorageQueryBuilder query_builder;
+
+ [GtkChild]
+ private Gtk.Label header_label;
+
+ [GtkChild]
+ private StorageViewRow used_row;
+
+ [GtkChild]
+ private StorageViewRow available_row;
+
+ [GtkChild]
+ private Dazzle.StackList listbox;
+
+ [GtkChild]
+ private StorageGraph graph;
+
+ private StorageViewRow os_row = new StorageViewRow ();
+
+ private UserDirectory[] xdg_folders = {
+ UserDirectory.DOCUMENTS,
+ UserDirectory.DOWNLOAD,
+ UserDirectory.MUSIC,
+ UserDirectory.PICTURES,
+ UserDirectory.VIDEOS,
+ };
+
+ construct {
+ name = "STORAGE";
+ title = _("Storage");
+
+ try {
+ connection = Sparql.Connection.get ();
+ } catch (GLib.Error error) {
+ critical ("Failed to connect to Tracker: %s", error.message);
+ }
+
+ query_builder = new StorageQueryBuilder ();
+ controller = new TrackerController (connection);
+ }
+
+ public NewStorageView () {
+ listbox.row_activated.connect (on_row_activated);
+
+ setup_header_label ();
+ setup_mount_sizes ();
+ populate_view ();
+ }
+
+ private void on_row_activated (Gtk.ListBoxRow row) {
+ var storage_row = row as StorageViewRow;
+
+ if (storage_row.item.type == FileType.DIRECTORY) {
+ present_dir (storage_row.item.uri);
+ } else {
+ graph.queue_draw ();
+ }
+ }
+
+ private string get_user_special_dir_path (UserDirectory dir) {
+ return "file://" + Environment.get_user_special_dir (dir);
+ }
+
+ private Gtk.Widget create_file_row (Object obj) {
+ var item = obj as StorageViewItem;
+
+ var row = new StorageViewRow.from_item (item);
+ row.visible = true;
+
+ if (item.type == FileType.DIRECTORY) {
+ controller.get_file_size.begin (item.uri, (obj, res) => {
+ try {
+ var size = controller.get_file_size.end (res);
+ row.size_label.label = Utils.format_size_values (size);
+ } catch (GLib.Error error) {
+ warning (error.message);
+ }
+ });
+ }
+
+ row.show_all ();
+ return row;
+ }
+
+ private async void present_dir (string uri) {
+ if (connection == null)
+ return;
+
+ try {
+ var model = yield controller.enumerate_children (uri);
+
+ var file = File.new_for_uri (uri);
+ var item = new StorageViewItem.from_file (file);
+ var row = new StorageViewRow.from_item (item);
+
+ listbox.push (row, model, create_file_row);
+
+ graph.model = model;
+ } catch (GLib.Error error) {
+ critical ("Failed to query the store: %s", error.message);
+ }
+ }
+
+ private void setup_header_label () {
+ header_label.label = Environment.get_host_name ();
+ }
+
+ private void setup_mount_sizes () {
+ uint64 total_used_size = 0;
+ uint64 total_free_size = 0;
+
+ MountList mount_list;
+ MountEntry[] entries = GTop.get_mountlist (out mount_list, false);
+
+ for (int i = 0; i < mount_list.number; i++) {
+ string dir = (string) entries[i].mountdir;
+
+ FsUsage mount;
+ GTop.get_fsusage (out mount, dir);
+
+ var total = mount.blocks * mount.block_size;
+ var free = mount.bfree * mount.block_size;
+ var used = total - free;
+
+ if (dir == "/") {
+ os_row.label = _("Operating System");
+ os_row.tag_size = StorageViewRow.TagSize.BIG;
+ os_row.get_style_context ().add_class ("stack-children");
+ os_row.tag.get_style_context ().add_class ("os-tag");
+ os_row.size_label.label = Utils.format_size_values (used);
+ }
+
+ total_used_size += used;
+ total_free_size += free;
+ }
+
+ used_row.size_label.label = Utils.format_size_values (total_used_size);
+ used_row.tag.get_style_context ().add_class ("used-tag");
+
+ available_row.size_label.label = Utils.format_size_values (total_free_size);
+ available_row.tag.get_style_context ().add_class ("available-tag");
+ }
+
+ private async void populate_view () {
+ if (connection == null)
+ return;
+
+ var model = new GLib.ListStore (typeof (StorageViewItem));
+ 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);
+ item.dir = dir;
+
+ model.append (item);
+ }
+
+ listbox.push (os_row, model, create_file_row);
+ graph.model = model;
+ }
+}
diff --git a/src/storage/tracker-controller.vala b/src/storage/tracker-controller.vala
new file mode 100644
index 0000000..d57d33c
--- /dev/null
+++ b/src/storage/tracker-controller.vala
@@ -0,0 +1,123 @@
+/* tracker-controller.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: Felipe Borges <felipeborges gnome org>
+ */
+
+using Tracker;
+
+public class Usage.TrackerController : GLib.Object {
+ private Sparql.Connection connection;
+ private StorageQueryBuilder query_builder;
+
+ construct {
+ query_builder = new StorageQueryBuilder ();
+ }
+
+ public TrackerController (Sparql.Connection connection) {
+ this.connection = connection;
+ }
+
+ public async GLib.ListStore enumerate_children (string uri) throws GLib.Error {
+ var list = new GLib.ListStore (typeof (StorageViewItem));
+
+ var query = query_builder.enumerate_children (uri);
+
+ var worker = yield new TrackerWorker (connection, query);
+ string n_uri = null;
+ string file_type = null;
+
+ var parent = File.new_for_uri (uri);
+ uint64 parent_size = 1;
+ if (parent != null) {
+ parent_size = yield get_file_size (uri);
+ }
+
+ 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);
+ item.ontology = file_type;
+
+ if (item.type == FileType.DIRECTORY) {
+ item.size = yield get_file_size (n_uri);
+ }
+
+ item.percentage = item.size*100/(double)parent_size;
+
+ list.insert_sorted (item, (a, b) => {
+ var item_a = a as StorageViewItem;
+ var item_b = b as StorageViewItem;
+
+ if (item_a.type == FileType.DIRECTORY) {
+ return -1;
+ }
+
+ if (item_b.type == FileType.DIRECTORY) {
+ return 1;
+ }
+
+ if (item_a.size > item_b.size) {
+ return -1;
+ }
+
+ if (item_b.size > item_a.size) {
+ return 1;
+ }
+
+ return 0;
+ });
+ } catch (GLib.Error error) {
+ warning (error.message);
+ }
+ }
+
+ return list;
+ }
+
+ private uint64 get_g_file_size (string uri) {
+ try {
+ var file = File.new_for_uri (uri);
+ var info = file.query_info (FileAttribute.STANDARD_SIZE, FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+
+ return info.get_size ();
+ } catch (GLib.Error error) {
+ warning (error.message);
+ }
+
+ return 0;
+ }
+
+ public async uint64 get_file_size (string uri) throws GLib.Error {
+ uint64 total = 0;
+
+ var query = query_builder.enumerate_children (uri, true);
+
+ var worker = yield new TrackerWorker (connection, query);
+
+ string n_uri = null;
+ while (yield worker.fetch_next (out n_uri, null)) {
+ try {
+ total += get_g_file_size (n_uri);
+ } catch (GLib.Error error) {
+ warning (error.message);
+ }
+ }
+
+ return total;
+ }
+}
diff --git a/src/storage/tracker-worker.vala b/src/storage/tracker-worker.vala
new file mode 100644
index 0000000..545d914
--- /dev/null
+++ b/src/storage/tracker-worker.vala
@@ -0,0 +1,44 @@
+/* tracker-worker.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: Felipe Borges <felipeborges gnome org>
+ */
+
+using Tracker;
+
+public class Usage.TrackerWorker {
+ private Sparql.Cursor cursor;
+
+ public async TrackerWorker (Sparql.Connection connection, string query) throws GLib.Error {
+ cursor = yield connection.query_async (query);
+ }
+
+ public async bool fetch_next (out string uri, out string file_type) throws GLib.Error {
+ uri = file_type = null;
+
+ if (!(yield cursor.next_async ()))
+ return false;
+
+ uri = cursor.get_string (0);
+ var type = cursor.get_string (1);
+ file_type = type.substring (type.last_index_of_char ('/') + 1, -1);
+ if (uri == null)
+ return yield fetch_next (out uri, out file_type);
+
+ return true;
+ }
+}
diff --git a/src/window.vala b/src/window.vala
index a4109fc..c4278b6 100644
--- a/src/window.vala
+++ b/src/window.vala
@@ -53,7 +53,7 @@ namespace Usage
views = new View[]
{
new PerformanceView(),
- new StorageView(),
+ new NewStorageView(),
};
foreach(var view in views)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]