[gnome-usage: 1/2] Add rename, move, move to trash, delete and restore from trash actions for files in storage. System-



commit 0ee7fd595811f38295fab6998b1c8c052bfa415d
Author: Petr Štětka <pstetka redhat com>
Date:   Thu Mar 30 12:53:02 2017 +0200

    Add rename, move, move to trash, delete and restore from trash actions for files in storage.
    System-monitor: Fix crashing when commandline is null.
    Update comment in about dialog.

 README.md                 |    7 +-
 po/POTFILES.in            |    1 +
 src/application.vala      |    2 +-
 src/storage-analyzer.vala |  455 +++++++++++++++++++++++++++++++++++++--------
 src/storage-item.vala     |   27 ++-
 src/storage-list-box.vala |   32 +++-
 src/storage-row.vala      |  286 ++++++++++++++++++++++++++++-
 src/storage-view.vala     |   17 ++-
 src/storage-worker.vala   |   41 +---
 src/system-monitor.vala   |   43 +++--
 10 files changed, 754 insertions(+), 157 deletions(-)
---
diff --git a/README.md b/README.md
index 62ff55e..40c4639 100644
--- a/README.md
+++ b/README.md
@@ -7,8 +7,11 @@ New GNOME Usage!
 - [x] Memory usage
 - [x] Network usage
 - [x] Search in processes 
-- [ ] Fix bug with refreshing ProcessListBox - 50% (focus, and click when refresh)
-- [ ] Storage view - 75%
+- [ ] Multiselection in storage
+- [ ] UI for file operations errors (as duplicate file, not enough space, permission...)
+- [ ] Notification for file operations and rollback
+- [ ] Storage support for more users (multiuser system)
+- [ ] Application section in storage 
 - [ ] Power view (Design?)
 - [ ] Disk usage (What library we can use?)
 - [ ] Data view - 0%
diff --git a/po/POTFILES.in b/po/POTFILES.in
index bdb26a0..78ff036 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -14,6 +14,7 @@ src/power-view.vala
 src/process-dialog.vala
 src/storage-analyzer.vala
 src/storage-item.vala
+src/storage-row.vala
 src/storage-view.vala
 src/utils.vala
 src/window.vala
diff --git a/src/application.vala b/src/application.vala
index 2639a60..dcf7fb9 100644
--- a/src/application.vala
+++ b/src/application.vala
@@ -74,7 +74,7 @@ namespace Usage
 
             Gtk.show_about_dialog (window,
                 program_name: _("Usage"),
-                comments: _("View current application and monitor system state"),
+                comments: _("A nice way to view information about use of system resources, like memory and 
disk space."),
                authors: authors,
                website: "https://wiki.gnome.org/Apps/Usage";,
                website_label: _("Websites"),
diff --git a/src/storage-analyzer.vala b/src/storage-analyzer.vala
index fb2e2f6..2cbb58f 100644
--- a/src/storage-analyzer.vala
+++ b/src/storage-analyzer.vala
@@ -9,17 +9,18 @@ namespace Usage
 
         private bool separate_home = false;
         private Cancellable cancellable;
-        private HashTable<string, Directory?> directory_table;
+        private HashTable<string, uint64?> directory_size_table;
         private HashTable<string, Storage?> storages;
-        private AsyncQueue<StorageResult> results_queue;
         private string[] exclude_from_home;
         private static bool path_null;
         private bool can_scan = true;
+        private const string TRASH_PATH = "trash:///";
+        private const string file_attributes = FileAttribute.STANDARD_SIZE + "," + 
FileAttribute.STANDARD_NAME + "," + FileAttribute.STANDARD_TYPE;
 
-        private struct Directory
+        private enum Operation
         {
-            public uint64 size;
-            public float percentage;
+            PLUS,
+            MINUS
         }
 
         private struct Storage
@@ -36,9 +37,9 @@ namespace Usage
             return storages[mount_path];
         }
 
-        private Directory? get_directory(string path)
+        private uint64? get_size_of_directory(string path)
         {
-            return directory_table[path];
+            return directory_size_table[path];
         }
 
         public void stop_scanning()
@@ -51,7 +52,7 @@ namespace Usage
             return separate_home;
         }
 
-        public async List<StorageItem> prepare_items(string? path, Gdk.RGBA color)
+        public async List<StorageItem> prepare_items(string? path, Gdk.RGBA color, StorageItemType? parent)
         {
             if(path == null)
             {
@@ -62,7 +63,7 @@ namespace Usage
                 {
                     Storage? home = get_storage("/home");
                     items.insert_sorted(new StorageItem.storage(_("Storage 1"), home.mount_path, home.total, 
0), (CompareFunc) sort);
-                    add_home_items(ref items, 0);
+                    add_home_items(ref items, home, 0);
                     items.insert_sorted(new StorageItem.available(home.free, ((float) home.free / 
home.total) * 100, 0), (CompareFunc) sort);
                     Storage? root = get_storage("/");
                     items.insert_sorted(new StorageItem.storage(_("Storage 2"), root.mount_path, root.total, 
1), (CompareFunc) sort);
@@ -72,9 +73,9 @@ namespace Usage
                 else
                 {
                     Storage? root = get_storage("/");
-                    items.insert_sorted(new StorageItem.storage(_("Storage 1"), root.mount_path, root.total, 
0), (CompareFunc) sort);
+                    items.insert_sorted(new StorageItem.storage(_("Capacity"), root.mount_path, root.total, 
0), (CompareFunc) sort);
                     add_root_items(ref items, root, 0);
-                    add_home_items(ref items, 0);
+                    add_home_items(ref items, root, 0);
                     items.insert_sorted(new StorageItem.available(root.free, ((float) root.free / 
root.total) * 100), (CompareFunc) sort);
                 }
 
@@ -83,7 +84,7 @@ namespace Usage
             } else
             {
                 path_null = false;
-                return get_items_for_path(path, color, exclude_from_home);
+                return get_items_for_path(path, color, parent, exclude_from_home);
             }
         }
 
@@ -229,7 +230,7 @@ namespace Usage
                 analyze_storages();
                 stop_scanning();
                 cancellable.reset();
-                directory_table.remove_all();
+                directory_size_table.remove_all();
                 SourceFunc callback = create_cache.callback;
 
                 ThreadFunc<void*> run = () => {
@@ -248,8 +249,291 @@ namespace Usage
             }
         }
 
+        public async void move_file(File src_file, File dest_file)
+        {
+            var src_parent = src_file.get_parent();
+            var dest_parent = dest_file.get_parent();
+            var type = src_file.query_file_type (FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+            Array<string> folders_for_delete_from_cache = new Array<string>();
+            uint64 size = 0;
+
+            try {
+                if(type == FileType.DIRECTORY)
+                {
+                    size = get_size_of_directory(src_file.get_parse_name());
+                    get_folders_in_dir(src_file, ref folders_for_delete_from_cache);
+                }
+                else if(type == FileType.REGULAR)
+                {
+                    var file_info = src_file.query_info (FileAttribute.STANDARD_SIZE, 
FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+                    size = file_info.get_size();
+                }
+
+               src_file.move (dest_file, FileCopyFlags.NONE, null);
+
+               recalculate_size_of_parents(src_parent, size, Operation.MINUS);
+                recalculate_size_of_parents(dest_parent, size, Operation.PLUS);
+
+                if(type == FileType.DIRECTORY)
+                {
+                    for(int i = 0; i < folders_for_delete_from_cache.length; i++)
+                         directory_size_table.remove (folders_for_delete_from_cache.index(i));
+                    add_to_cache(dest_file);
+                }
+            } catch (Error e) {
+               stderr.printf (e.message);
+            }
+        }
+
+        public async void wipe_folder(string path)
+        {
+            var file = File.new_for_path(path);
+            uint64 size = get_size_of_directory(path);
+            var type = file.query_file_type (FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+
+            try {
+                if(type == FileType.DIRECTORY)
+                {
+                    FileEnumerator enumerator;
+                    enumerator = file.enumerate_children(file_attributes, 
FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
+                    FileInfo info;
+
+                    while((info = enumerator.next_file(null)) != null)
+                    {
+                        directory_size_table.remove (file.get_child(info.get_name()).get_parse_name());
+                        file.get_child(info.get_name()).trash();
+                        add_to_cache(File.new_for_uri(TRASH_PATH));
+                    }
+                }
+            }
+            catch (Error e) {
+                stderr.printf ("Error: %s\n", e.message);
+            }
+
+            recalculate_size_of_parents(file, size, Operation.MINUS);
+        }
+
+        public async void wipe_trash()
+        {
+            var file = File.new_for_uri(TRASH_PATH);
+
+            try {
+                FileEnumerator enumerator = file.enumerate_children(file_attributes, 
FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
+                FileInfo info;
+
+                while((info = enumerator.next_file(null)) != null)
+                    file.get_child(info.get_name()).delete();
+            }
+            catch (Error e) {
+                stderr.printf ("Error: %s\n", e.message);
+            }
+
+            add_to_cache(file);
+        }
+
+        public async void trash_file(string path)
+        {
+            var file = File.new_for_path(path);
+            var type = file.query_file_type (FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+            Array<string> folders_for_delete_from_cache = new Array<string>();
+            uint64 size = 0;
+
+            try {
+                if(type == FileType.DIRECTORY)
+                {
+                    size = get_size_of_directory(path);
+                    get_folders_in_dir(file, ref folders_for_delete_from_cache);
+                }
+                else if(type == FileType.REGULAR)
+                {
+                    var file_info = file.query_info (FileAttribute.STANDARD_SIZE, 
FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+                    size = file_info.get_size();
+                }
+                file.trash();
+            } catch (Error e) {
+                stderr.printf ("Error: %s\n", e.message);
+            }
+
+            recalculate_size_of_parents(file.get_parent(), size, Operation.MINUS);
+
+            if(type == FileType.DIRECTORY)
+            {
+                for(int i = 0; i < folders_for_delete_from_cache.length; i++)
+                     directory_size_table.remove (folders_for_delete_from_cache.index(i));
+            }
+
+            add_to_cache(File.new_for_uri(TRASH_PATH));
+        }
+
+        public async void delete_trash_file(string path)
+        {
+            var file = File.new_for_uri(path);
+            try {
+                file.delete();
+            }
+            catch (Error e) {
+                stderr.printf ("Error: %s\n", e.message);
+            }
+            add_to_cache(File.new_for_uri(TRASH_PATH));
+        }
+
+        public async void restore_trash_file(string path)
+        {
+            var file = File.new_for_uri(path);
+            try {
+                var file_info = file.query_info (file_attributes + "," + FileAttribute.TRASH_ORIG_PATH, 
FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+                move_file.begin(file, 
File.new_for_path(file_info.get_attribute_byte_string(FileAttribute.TRASH_ORIG_PATH)));
+            } catch(Error e) {
+                stderr.printf ("Error: %s\n", e.message);
+            }
+        }
+
+        public async void delete_file(string path)
+        {
+            var file = File.new_for_path(path);
+            var parent = file.get_parent();
+            var type = file.query_file_type (FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+            uint64 size = 0;
+
+            if(type == FileType.DIRECTORY)
+                size = get_size_of_directory(path);
+            else if(type == FileType.REGULAR)
+            {
+                try {
+                    var file_info = file.query_info (FileAttribute.STANDARD_SIZE, 
FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+                    size = file_info.get_size();
+                } catch (Error e) {
+                    stderr.printf ("Error: %s\n", e.message);
+                }
+            }
+
+            delete_file_recursive(path, true);
+            recalculate_size_of_parents(parent, size, Operation.MINUS);
+        }
+
+        private void get_folders_in_dir(File file, ref Array<string> folders)
+        {
+            try {
+                FileEnumerator enumerator = file.enumerate_children(file_attributes, 
FileQueryInfoFlags.NOFOLLOW_SYMLINKS, cancellable);
+                FileInfo info;
+
+                while((info = enumerator.next_file(null)) != null)
+                {
+                    if(info.get_file_type() == FileType.DIRECTORY)
+                    {
+                        var child = file.get_child(info.get_name());
+                        get_folders_in_dir(child, ref folders);
+                    }
+                }
+            }
+            catch (Error e) {
+                stderr.printf ("Error: %s\n", e.message);
+            }
+
+            folders.append_val(file.get_parse_name());
+        }
+
+        private uint64 add_to_cache(File file)
+        {
+            string path = file.get_parse_name();
+            uint64 size = 0;
+
+            try {
+                FileEnumerator enumerator = file.enumerate_children(file_attributes, 
FileQueryInfoFlags.NOFOLLOW_SYMLINKS, cancellable);
+                FileInfo info;
+
+                while((info = enumerator.next_file(null)) != null)
+                {
+                    if(info.get_file_type() == FileType.DIRECTORY)
+                    {
+                        var child = file.get_child(info.get_name());
+                        size += add_to_cache(child);
+                    }
+                    else if(info.get_file_type() == FileType.REGULAR)
+                    {
+                        size += info.get_size();
+                    }
+                }
+            }
+            catch (Error e) {
+                stderr.printf ("Error: %s\n", e.message);
+            }
+
+            directory_size_table.insert (path, size);
+            return size;
+        }
+
+        private void recalculate_size_of_parents(File? parent, uint64 size, Operation operation)
+        {
+            uint64 orig_size = get_size_of_directory(parent.get_parse_name());
+            uint64 new_size = 0;
+
+            switch(operation)
+            {
+                case Operation.PLUS:
+                    new_size = orig_size + size;
+                    break;
+                case Operation.MINUS:
+                    new_size = orig_size - size;
+                    break;
+            }
+            directory_size_table.replace(parent.get_parse_name(), new_size);
+
+            foreach(string exclude in exclude_from_home)
+            {
+                if(parent.equal(File.new_for_path(exclude)))
+                    return;
+            }
+
+            if(parent.equal(File.new_for_path(Environment.get_home_dir())))
+                return;
+
+            if(parent.get_parent() == null)
+                return;
+
+            recalculate_size_of_parents(parent.get_parent(), size, operation);
+        }
+
+        private void delete_file_recursive(string path, bool delete_basefile, bool uri = false)
+        {
+            File file;
+            if(uri)
+                file = File.new_for_uri(path);
+            else
+                file = File.new_for_path(path);
+
+            var type = file.query_file_type (FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+
+            try {
+                if(type == FileType.DIRECTORY)
+                {
+                    FileEnumerator enumerator;
+                    enumerator = file.enumerate_children(file_attributes, 
FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
+                    FileInfo info;
+
+                    while((info = enumerator.next_file(null)) != null)
+                    {
+                        string child = file.get_child(info.get_name()).get_parse_name();
+                        delete_file_recursive(child, true, uri);
+                    }
+                }
+
+                if(delete_basefile)
+                {
+                    file.delete();
+                    directory_size_table.remove(path);
+                }
+                else
+                    directory_size_table.replace(path, 0);
+            }
+            catch (Error e) {
+                stderr.printf ("Error: %s\n", e.message);
+            }
+        }
+
         private void scan_cache()
         {
+            var results_queue = new AsyncQueue<StorageResult>();
             uint64 total_size;
             if(separate_home)
             {
@@ -262,14 +546,14 @@ namespace Usage
                 total_size = root.total;
             }
 
-            var desktop   = new 
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.DESKTOP)), total_size, ref 
cancellable, ref results_queue);
-            var documents = new 
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.DOCUMENTS)), total_size, ref 
cancellable, ref results_queue);
-            var downloads = new 
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.DOWNLOAD)), total_size, ref 
cancellable, ref results_queue);
-            var music     = new 
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.MUSIC)), total_size, ref 
cancellable, ref results_queue);
-            var pictures  = new 
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.PICTURES)), total_size, ref 
cancellable, ref results_queue);
-            var videos    = new 
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.VIDEOS)), total_size, ref 
cancellable, ref results_queue);
-            var trash     = new StorageWorker(File.new_for_path(Environment.get_home_dir() + 
"/.local/share/Trash/files"), total_size, ref cancellable, ref results_queue, _("Trash"));
-            var home      = new StorageWorker(File.new_for_path(Environment.get_home_dir()), total_size, ref 
cancellable, ref results_queue, Environment.get_real_name(), exclude_from_home);
+            var desktop   = new 
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.DESKTOP)), ref cancellable, 
ref results_queue);
+            var documents = new 
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.DOCUMENTS)), ref cancellable, 
ref results_queue);
+            var downloads = new 
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.DOWNLOAD)), ref cancellable, 
ref results_queue);
+            var music     = new 
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.MUSIC)), ref cancellable, ref 
results_queue);
+            var pictures  = new 
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.PICTURES)), ref cancellable, 
ref results_queue);
+            var videos    = new 
StorageWorker(File.new_for_path(Environment.get_user_special_dir(UserDirectory.VIDEOS)), ref cancellable, ref 
results_queue);
+            var trash     = new StorageWorker(File.new_for_uri(TRASH_PATH), ref cancellable, ref 
results_queue);
+            var home      = new StorageWorker(File.new_for_path(Environment.get_home_dir()), ref 
cancellable, ref results_queue, exclude_from_home);
 
             try {
                 ThreadPool<StorageWorker> threads = new ThreadPool<StorageWorker>.with_owned_data((worker) 
=> {
@@ -293,10 +577,7 @@ namespace Usage
             StorageResult result;
             while ((result = results_queue.try_pop()) != null)
             {
-                var directory = Directory();
-                directory.size = result.size;
-                directory.percentage = result.percentage;
-                directory_table.insert (result.path, directory);
+                directory_size_table.insert (result.path, result.size);
             }
         }
 
@@ -305,129 +586,146 @@ namespace Usage
             items.insert_sorted(new StorageItem.system(_("Operating System"), storage.used, ((float) 
storage.used / storage.total) * 100, section), (CompareFunc) sort);
         }
 
-        private void add_home_items(ref List<StorageItem> items, int section)
+        private void add_home_items(ref List<StorageItem> items, Storage storage, int section)
         {
-            Directory? user = get_directory(Environment.get_home_dir());
-            if(user != null)
+            uint64? user_size = get_size_of_directory(Environment.get_home_dir());
+            if(user_size != null)
             {
                 items.insert_sorted(new StorageItem.item(StorageItemType.USER,
+                    StorageItemType.USER,
                     _("Home"),
                     Environment.get_home_dir(),
-                    user.size,
-                    user.percentage,
+                    user_size,
+                    ((float) user_size / storage.total) * 100,
                     section,
                     StorageItemPosition.SECOND), (CompareFunc) sort);
             }
-            Directory? desktop = get_directory(Environment.get_user_special_dir(UserDirectory.DESKTOP));
-            if(desktop != null)
+            uint64? desktop_size = 
get_size_of_directory(Environment.get_user_special_dir(UserDirectory.DESKTOP));
+            if(desktop_size != null)
             {
                 items.insert_sorted(new StorageItem.item(StorageItemType.DESKTOP,
+                    StorageItemType.DESKTOP,
                     Path.get_basename(Environment.get_user_special_dir(UserDirectory.DESKTOP)),
                     Environment.get_user_special_dir(UserDirectory.DESKTOP),
-                    desktop.size,
-                    desktop.percentage,
+                    desktop_size,
+                    ((float) desktop_size / storage.total) * 100,
                     section), (CompareFunc) sort);
             }
-            Directory? documents = get_directory(Environment.get_user_special_dir(UserDirectory.DOCUMENTS));
-            if(documents != null)
+            uint64? documents_size = 
get_size_of_directory(Environment.get_user_special_dir(UserDirectory.DOCUMENTS));
+            if(documents_size != null)
             {
                 items.insert_sorted(new StorageItem.item(StorageItemType.DOCUMENTS,
+                    StorageItemType.DOCUMENTS,
                     Path.get_basename(Environment.get_user_special_dir(UserDirectory.DOCUMENTS)),
                     Environment.get_user_special_dir(UserDirectory.DOCUMENTS),
-                    documents.size,
-                    documents.percentage,
+                    documents_size,
+                    ((float) documents_size / storage.total) * 100,
                     section), (CompareFunc) sort);
             }
-            Directory? downloads = get_directory(Environment.get_user_special_dir(UserDirectory.DOWNLOAD));
-            if(downloads != null)
+            uint64? downloads_size = 
get_size_of_directory(Environment.get_user_special_dir(UserDirectory.DOWNLOAD));
+            if(downloads_size != null)
             {
                 items.insert_sorted(new StorageItem.item(StorageItemType.DOWNLOADS,
+                    StorageItemType.DOWNLOADS,
                     Path.get_basename(Environment.get_user_special_dir(UserDirectory.DOWNLOAD)),
                     Environment.get_user_special_dir(UserDirectory.DOWNLOAD),
-                    downloads.size,
-                    downloads.percentage,
+                    downloads_size,
+                    ((float) downloads_size / storage.total) * 100,
                     section), (CompareFunc) sort);
             }
-            Directory? music = get_directory(Environment.get_user_special_dir(UserDirectory.MUSIC));
-            if(music != null)
+            uint64? music_size = 
get_size_of_directory(Environment.get_user_special_dir(UserDirectory.MUSIC));
+            if(music_size != null)
             {
                 items.insert_sorted(new StorageItem.item(StorageItemType.MUSIC,
+                    StorageItemType.MUSIC,
                     Path.get_basename(Environment.get_user_special_dir(UserDirectory.MUSIC)),
                     Environment.get_user_special_dir(UserDirectory.MUSIC),
-                    music.size,
-                    music.percentage,
+                    music_size,
+                    ((float) music_size / storage.total) * 100,
                     section), (CompareFunc) sort);
             }
-            Directory? pictures = get_directory(Environment.get_user_special_dir(UserDirectory.PICTURES));
-            if(pictures != null)
+            uint64? pictures_size = 
get_size_of_directory(Environment.get_user_special_dir(UserDirectory.PICTURES));
+            if(pictures_size != null)
             {
                 items.insert_sorted(new StorageItem.item(StorageItemType.PICTURES,
+                    StorageItemType.PICTURES,
                     Path.get_basename(Environment.get_user_special_dir(UserDirectory.PICTURES)),
                     Environment.get_user_special_dir(UserDirectory.PICTURES),
-                    pictures.size,
-                    pictures.percentage,
+                    pictures_size,
+                    ((float) pictures_size / storage.total) * 100,
                     section), (CompareFunc) sort);
             }
-            Directory? videos = get_directory(Environment.get_user_special_dir(UserDirectory.VIDEOS));
-            if(videos != null)
+            uint64? videos_size = 
get_size_of_directory(Environment.get_user_special_dir(UserDirectory.VIDEOS));
+            if(videos_size != null)
             {
                 items.insert_sorted(new StorageItem.item(StorageItemType.VIDEOS,
+                    StorageItemType.VIDEOS,
                     Path.get_basename(Environment.get_user_special_dir(UserDirectory.VIDEOS)),
                     Environment.get_user_special_dir(UserDirectory.VIDEOS),
-                    videos.size,
-                    videos.percentage,
+                    videos_size,
+                    ((float) videos_size / storage.total) * 100,
                     section), (CompareFunc) sort);
             }
-            var trash_path = Environment.get_home_dir() + "/.local/share/Trash/files";
-            Directory? trash = get_directory(trash_path);
-            if(trash != null)
+            uint64? trash_size = get_size_of_directory(TRASH_PATH);
+            if(trash_size != null)
             {
                 items.insert_sorted(new StorageItem.trash(
-                    trash_path,
-                    trash.size,
-                    trash.percentage,
+                    TRASH_PATH,
+                    trash_size,
+                    ((float) trash_size / storage.total) * 100,
                     section), (CompareFunc) sort);
             }
         }
 
-        private List<StorageItem> get_items_for_path(string path, Gdk.RGBA color, string[]? exclude_paths = 
null)
+        private List<StorageItem> get_items_for_path(string path, Gdk.RGBA color, StorageItemType parent, 
string[]? exclude_paths = null)
         {
             List<StorageItem> items = new List<StorageItem>();
 
-            File file = File.new_for_path(path);
+            File file;
             FileEnumerator enumerator;
 
+            if(parent == StorageItemType.TRASH)
+            {
+                parent = StorageItemType.TRASHFILE;
+                file = File.new_for_uri(path);
+            }
+            else if(parent == StorageItemType.TRASHFILE || parent == StorageItemType.TRASHSUBFILE)
+            {
+                parent = StorageItemType.TRASHSUBFILE;
+                file = File.new_for_uri(path);
+            }
+            else
+                file = File.new_for_path(path);
+
             try {
-                enumerator = file.enumerate_children(FileAttribute.STANDARD_SIZE, 
FileQueryInfoFlags.NOFOLLOW_SYMLINKS, cancellable);
+                enumerator = file.enumerate_children(file_attributes, FileQueryInfoFlags.NOFOLLOW_SYMLINKS, 
cancellable);
                 FileInfo info;
 
                 while((info = enumerator.next_file(null)) != null && cancellable.is_cancelled() == false)
                 {
+                    uint64 parent_size = get_size_of_directory(path);
+
                     if(info.get_file_type() == FileType.DIRECTORY)
                     {
                         if(exclude_paths == null || !(file.resolve_relative_path(info.get_name()).get_path() 
in exclude_paths))
                         {
                             string folder_path = file.get_child(info.get_name()).get_parse_name();
-                            Directory? folder = get_directory(folder_path);
-                            uint64 folder_size = 0;
-                            double folder_percentage = 0;
+                            uint64? folder_size = get_size_of_directory(folder_path);
 
-                            if(folder != null)
+                            if(folder_size != null)
                             {
-                                folder_size = folder.size;
-                                folder_percentage = folder.percentage;
-                            }
+                                double folder_percentage = ((float) folder_size / parent_size) * 100;
 
-                            items.insert_sorted(new StorageItem.directory(info.get_name(), folder_path, 
folder_size,
-                                folder_percentage), (CompareFunc) sort);
+                                items.insert_sorted(new StorageItem.directory(parent, info.get_name(), 
folder_path, folder_size,
+                                    folder_percentage), (CompareFunc) sort);
+                            }
                         }
                     }
                     else if(info.get_file_type() == FileType.REGULAR)
                     {
-                        Directory? parent = get_directory(path);
-                        float percentage = ((float) info.get_size() / parent.size) * 100;
+                        float percentage = ((float) info.get_size() / parent_size) * 100;
 
-                        items.insert_sorted(new StorageItem.file(info.get_name(),
+                        items.insert_sorted(new StorageItem.file(parent, info.get_name(),
                             file.get_child(info.get_name()).get_parse_name(), info.get_size(), percentage),
                             (CompareFunc) sort);
                     }
@@ -462,7 +760,7 @@ namespace Usage
                     GTop.get_fsusage(out root, mountdir);
 
                     Storage storage = Storage();
-                    storage.free = root.bfree * root.block_size;
+                    storage.free = root.bfree * root.block_size; //TODO bavail or bfree
                     storage.total = root.blocks * root.block_size;
                     storage.used = storage.total - storage.free;
                     storage.name = (string) entries[i].devname;
@@ -476,9 +774,8 @@ namespace Usage
         {
             cache = false;
             cancellable = new Cancellable();
-            directory_table = new HashTable<string, Directory?>(str_hash, str_equal);
+            directory_size_table = new HashTable<string, uint64?>(str_hash, str_equal);
             storages = new HashTable<string, Storage?>(str_hash, str_equal);
-            results_queue = new AsyncQueue<StorageResult>();
             exclude_from_home = {
                 Environment.get_user_special_dir(UserDirectory.DESKTOP),
                 Environment.get_user_special_dir(UserDirectory.DOCUMENTS),
@@ -486,7 +783,7 @@ namespace Usage
                 Environment.get_user_special_dir(UserDirectory.MUSIC),
                 Environment.get_user_special_dir(UserDirectory.PICTURES),
                 Environment.get_user_special_dir(UserDirectory.VIDEOS),
-                Environment.get_home_dir() + "/.local/share/Trash/files"
+                Environment.get_user_data_dir() + "/Trash/files"
             };
         }
     }
diff --git a/src/storage-item.vala b/src/storage-item.vala
index a70c3e2..6a5c833 100644
--- a/src/storage-item.vala
+++ b/src/storage-item.vala
@@ -20,6 +20,8 @@ namespace Usage
         PICTURES,
         VIDEOS,
         TRASH,
+        TRASHFILE,
+        TRASHSUBFILE,
         USER,
         AVAILABLE,
         FILE,
@@ -31,15 +33,17 @@ namespace Usage
         private string name;
         private string path;
         private StorageItemType type;
+        private StorageItemType? parent;
         private uint64 size;
         private double percentage;
         private StorageItemPosition prefered_position = StorageItemPosition.ANYWHERE;
         private int section;
         private Gdk.RGBA color;
 
-        public StorageItem.item(StorageItemType type, string name, string path, uint64 size, double 
percentage, int section = 0, StorageItemPosition prefered_position = StorageItemPosition.ANYWHERE)
+        public StorageItem.item(StorageItemType type, StorageItemType? parent, string name, string path, 
uint64 size, double percentage, int section = 0, StorageItemPosition prefered_position = 
StorageItemPosition.ANYWHERE)
         {
             this.type = type;
+            this.parent = parent;
             this.name = name;
             this.path = path;
             this.size = size;
@@ -48,34 +52,34 @@ namespace Usage
             this.prefered_position = prefered_position;
         }
 
-        public StorageItem.directory(string name, string path, uint64 size, double percentage)
+        public StorageItem.directory(StorageItemType parent, string name, string path, uint64 size, double 
percentage)
         {
-            StorageItem.item(StorageItemType.DIRECTORY, name, path, size, percentage);
+            StorageItem.item(StorageItemType.DIRECTORY, parent, name, path, size, percentage);
         }
 
-        public StorageItem.file(string name, string path, uint64 size, double percentage)
+        public StorageItem.file(StorageItemType parent, string name, string path, uint64 size, double 
percentage)
         {
-            StorageItem.item(StorageItemType.FILE, name, path, size, percentage);
+            StorageItem.item(StorageItemType.FILE, parent, name, path, size, percentage);
         }
 
         public StorageItem.trash(string path, uint64 size, double percentage, int section = 0)
         {
-            StorageItem.item(StorageItemType.TRASH, _("Trash"), path, size, percentage, section, 
StorageItemPosition.PENULTIMATE);
+            StorageItem.item(StorageItemType.TRASH, StorageItemType.TRASH, _("Trash"), path, size, 
percentage, section, StorageItemPosition.PENULTIMATE);
         }
 
         public StorageItem.storage(string name, string path, uint64 size, int section = 0)
         {
-            StorageItem.item(StorageItemType.STORAGE, name, path, size, 0, section, 
StorageItemPosition.FIRST);
+            StorageItem.item(StorageItemType.STORAGE, StorageItemType.STORAGE, name, path, size, 0, section, 
StorageItemPosition.FIRST);
         }
 
         public StorageItem.system(string name, uint64 size, double percentage, int section = 0)
         {
-            StorageItem.item(StorageItemType.SYSTEM, name, "", size, percentage, section);
+            StorageItem.item(StorageItemType.SYSTEM, StorageItemType.SYSTEM, name, "", size, percentage, 
section);
         }
 
         public StorageItem.available(uint64 size, double percentage, int section = 0)
         {
-            StorageItem.item(StorageItemType.AVAILABLE, _("Available"), "", size, percentage, section, 
StorageItemPosition.LAST);
+            StorageItem.item(StorageItemType.AVAILABLE, StorageItemType.AVAILABLE, _("Available"), "", size, 
percentage, section, StorageItemPosition.LAST);
         }
 
         public StorageItemPosition get_prefered_position()
@@ -118,6 +122,11 @@ namespace Usage
             return type;
         }
 
+        public StorageItemType? get_parent_type()
+        {
+            return parent;
+        }
+
         public string get_path()
         {
             return path;
diff --git a/src/storage-list-box.vala b/src/storage-list-box.vala
index 0db560b..be13daf 100644
--- a/src/storage-list-box.vala
+++ b/src/storage-list-box.vala
@@ -8,8 +8,10 @@ namespace Usage
 
         private List<string?> path_history;
         private List<string?> name_history;
+        private List<StorageItemType?> parent_type_history;
         private string? actual_path;
         private string? actual_name;
+        private StorageItemType? actual_parent_type;
         private ListStore model;
         private bool root = true;
         private StorageAnalyzer storage_analyzer;
@@ -27,8 +29,10 @@ namespace Usage
 
             path_history = new List<string>();
             name_history = new List<string>();
+            parent_type_history = new List<StorageItemType?>();
             actual_path = null;
             actual_name = null;
+            actual_parent_type = null;
             storage_analyzer = (GLib.Application.get_default() as Application).get_storage_analyzer();
 
             get_style_context().add_class("folders");
@@ -51,11 +55,16 @@ namespace Usage
         {
             unowned List<string>? path = path_history.last();
             unowned List<string>? name = name_history.last();
+            unowned List<StorageItemType?>? parent = parent_type_history.last();
             actual_path = path.data;
             actual_name = name.data;
-            load(path.data);
+            actual_parent_type = parent.data;
+
+            load(path.data, actual_parent_type);
+
             path_history.delete_link(path);
             name_history.delete_link(name);
+            parent_type_history.delete_link(parent);
             if(root)
             {
                 (GLib.Application.get_default() as 
Application).get_window().get_header_bar().show_storage_back_button(false);
@@ -74,7 +83,7 @@ namespace Usage
             this.hide();
             loading();
             storage_analyzer.cache_complete.connect(() => {
-                storage_analyzer.prepare_items.begin(actual_path, color, (obj, res) => {
+                storage_analyzer.prepare_items.begin(actual_path, color, actual_parent_type, (obj, res) => {
                     var header_bar = (GLib.Application.get_default() as 
Application).get_window().get_header_bar();
                     if(root == false)
                     {
@@ -100,7 +109,12 @@ namespace Usage
             });
         }
 
-        private void load(string? path)
+        public void refresh()
+        {
+            load(actual_path, actual_parent_type);
+        }
+
+        private void load(string? path, StorageItemType? parent)
         {
             if(path == null)
             {
@@ -114,7 +128,7 @@ namespace Usage
 
             this.hide();
             loading();
-            storage_analyzer.prepare_items.begin(path, color, (obj, res) => {
+            storage_analyzer.prepare_items.begin(path, color, parent, (obj, res) => {
                 loaded();
                 this.show();
                 model.remove_all();
@@ -130,15 +144,15 @@ namespace Usage
         private void on_row_activated (Gtk.ListBoxRow row)
         {
             StorageRow storage_row = (StorageRow) row;
-            if(storage_row.get_item_type() == StorageItemType.FILE)
-                ;//TODO: action on click
-            else if(storage_row.get_item_type() != StorageItemType.STORAGE && storage_row.get_item_type() != 
StorageItemType.SYSTEM
-                 && storage_row.get_item_type() != StorageItemType.AVAILABLE)
+            if(storage_row.get_item_type() != StorageItemType.STORAGE && storage_row.get_item_type() != 
StorageItemType.SYSTEM &&
+                storage_row.get_item_type() != StorageItemType.AVAILABLE && storage_row.get_item_type() != 
StorageItemType.FILE)
             {
                 path_history.append(actual_path);
                 name_history.append(actual_name);
+                parent_type_history.append(actual_parent_type);
                 actual_path = storage_row.get_item_path();
                 actual_name = storage_row.get_item_name();
+                actual_parent_type = storage_row.get_parent_type();
 
                 (GLib.Application.get_default() as 
Application).get_window().get_header_bar().show_storage_back_button(true);
                 (GLib.Application.get_default() as 
Application).get_window().get_header_bar().set_title_text(actual_name);
@@ -147,7 +161,7 @@ namespace Usage
                 if(root)
                     color = storage_row.get_color();
 
-                load(actual_path);
+                load(actual_path, actual_parent_type);
             }
         }
 
diff --git a/src/storage-row.vala b/src/storage-row.vala
index 44e8b43..9e97770 100644
--- a/src/storage-row.vala
+++ b/src/storage-row.vala
@@ -3,10 +3,22 @@ namespace Usage
     public class StorageRow : Gtk.ListBoxRow
     {
         private StorageItemType type;
+        private StorageItemType? parent_type;
         private string item_path;
         private string item_name;
         private Gdk.RGBA color;
 
+               const GLib.ActionEntry[] action_entries = {
+           { "rename", action_rename },
+           { "move", action_move },
+           { "move-to-trash", action_move_to_trash },
+           { "delete", action_delete },
+           { "wipe-trash", action_wipe_trash },
+           { "wipe-folder", action_wipe_folder },
+           { "trash-restore", action_trash_restore },
+           { "trash-delete", action_trash_delete }
+        };
+
         public StorageRow(StorageItem storage_item)
         {
             var box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
@@ -16,6 +28,7 @@ namespace Usage
             var size_label = new Gtk.Label(Utils.format_size_values(storage_item.get_size()));
             item_path = storage_item.get_path();
             item_name = storage_item.get_name();
+            parent_type = storage_item.get_parent_type();
             type = storage_item.get_item_type();
             var title_label = new Gtk.Label(storage_item.get_name());
             title_label.set_ellipsize(Pango.EllipsizeMode.MIDDLE);
@@ -43,8 +56,6 @@ namespace Usage
                     box.pack_start(color_rectangle, false, false, 5);
                     break;
                 case StorageItemType.STORAGE:
-                    box.margin_top = 10;
-                    box.margin_bottom = 10;
                     title_label.set_markup ("<b>" + storage_item.get_name() + "</b>");
                     size_label.set_markup ("<b>" + Utils.format_size_values(storage_item.get_size()) + 
"</b>");
                     activatable = false;
@@ -92,7 +103,10 @@ namespace Usage
 
             box.pack_start(title_label, false, true, 5);
             box.pack_end(size_label, false, true, 10);
-            add(box);
+            var event_box = new Gtk.EventBox();
+            event_box.add(box);
+            event_box.button_press_event.connect(row_press_event);
+            add(event_box);
 
             show_all();
         }
@@ -116,5 +130,271 @@ namespace Usage
         {
             return type;
         }
+
+        public StorageItemType? get_parent_type()
+        {
+            return parent_type;
+        }
+
+        private bool row_press_event (Gdk.EventButton event)
+        {
+            if(event.type == Gdk.EventType.BUTTON_PRESS)
+            {
+                switch (event.button)
+                {
+                    case Gdk.BUTTON_PRIMARY:
+                        action_primary();
+                        return false;
+                    case Gdk.BUTTON_SECONDARY:
+                        action_secondary();
+                        return true;
+                }
+            }
+
+            return true;
+        }
+
+        private void action_primary()
+        {
+            if(type == StorageItemType.FILE)
+            {
+                File file;
+                if(parent_type == StorageItemType.TRASH || parent_type == StorageItemType.TRASHFILE || 
parent_type == StorageItemType.TRASHSUBFILE)
+                    file = File.new_for_uri(item_path);
+                else
+                    file = File.new_for_path(item_path);
+
+                try {
+                    AppInfo.launch_default_for_uri(file.get_uri(), null);
+                } catch (Error e) {
+                       stderr.printf (e.message);
+                }
+            }
+        }
+
+        private void action_secondary()
+        {
+            bool show_popover = false;
+
+            var action_group = new GLib.SimpleActionGroup ();
+            action_group.add_action_entries (action_entries, this);
+
+            var menu = new GLib.Menu ();
+            var section = new GLib.Menu ();
+
+            switch(type)
+            {
+                case StorageItemType.SYSTEM:
+                case StorageItemType.AVAILABLE:
+                case StorageItemType.STORAGE:
+                case StorageItemType.TRASHSUBFILE:
+                case StorageItemType.TRASHFILE:
+                    break;
+                case StorageItemType.USER:
+                case StorageItemType.DOCUMENTS:
+                case StorageItemType.DOWNLOADS:
+                case StorageItemType.DESKTOP:
+                case StorageItemType.MUSIC:
+                case StorageItemType.PICTURES:
+                case StorageItemType.VIDEOS:
+                    section.append (_("Empty") + " " + item_name, "row.wipe-folder");
+                    menu.append_section (null, section);
+                    show_popover = true;
+                    break;
+                case StorageItemType.TRASH:
+                    section.append (_("Empty Trash"), "row.wipe-trash");
+                    menu.append_section (null, section);
+                    show_popover = true;
+                    break;
+                case StorageItemType.DIRECTORY:
+                case StorageItemType.FILE:
+                    show_popover = true;
+                    switch(parent_type)
+                    {
+                        case StorageItemType.TRASHFILE:
+                            section.append (_("Restore"), "row.trash-restore");
+                            menu.append_section (null, section);
+                            section = new GLib.Menu ();
+                            section.append (_("Delete from Trash"), "row.trash-delete");
+                            menu.append_section (null, section);
+                            break;
+                        case StorageItemType.TRASHSUBFILE:
+                            show_popover = false;
+                            break;
+                        default:
+                            section.append (_("Rename"), "row.rename");
+                            section.append (_("Move to"), "row.move");
+                            menu.append_section (null, section);
+                            section = new GLib.Menu ();
+                            section.append (_("Move to trash"), "row.move-to-trash");
+                            section.append (_("Delete"), "row.delete");
+                            menu.append_section (null, section);
+                            break;
+                    }
+                    break;
+            }
+
+            if(show_popover)
+            {
+                var pop = new Gtk.Popover (this);
+                pop.bind_model (menu, null);
+                pop.insert_action_group ("row", action_group);
+                pop.set_position(Gtk.PositionType.BOTTOM);
+                pop.show_all ();
+            }
+        }
+
+        private void action_trash_restore()
+        {
+            Timeout.add(0, () => {
+                var storage_analyzer = (GLib.Application.get_default() as 
Application).get_storage_analyzer();
+                storage_analyzer.restore_trash_file.begin(item_path, () => {
+                    ((StorageView) (GLib.Application.get_default() as 
Application).get_window().get_views()[2]).get_storage_list_box().refresh();
+                });
+
+                return false;
+            });
+        }
+
+        private void action_trash_delete()
+        {
+            Timeout.add(0, () => {
+                var storage_analyzer = (GLib.Application.get_default() as 
Application).get_storage_analyzer();
+                storage_analyzer.delete_trash_file.begin(item_path, () => {
+                    ((StorageView) (GLib.Application.get_default() as 
Application).get_window().get_views()[2]).get_storage_list_box().refresh();
+                });
+
+                return false;
+            });
+        }
+
+        private void action_wipe_folder()
+        {
+            var dialog = new Gtk.MessageDialog ((GLib.Application.get_default() as 
Application).get_window(), Gtk.DialogFlags.MODAL,
+                Gtk.MessageType.WARNING, Gtk.ButtonsType.OK_CANCEL, _("Empty all items from 
%s?").printf(item_name));
+            dialog.secondary_text = _("All items in the %s will be moved to the Trash.").printf(item_name);
+
+            if(dialog.run() == Gtk.ResponseType.OK)
+            {
+               Timeout.add(0, () => {
+                    var storage_analyzer = (GLib.Application.get_default() as 
Application).get_storage_analyzer();
+                    storage_analyzer.wipe_folder.begin(item_path, () => {
+                        ((StorageView) (GLib.Application.get_default() as 
Application).get_window().get_views()[2]).get_storage_list_box().refresh();
+                    });
+
+                    return false;
+                });
+            }
+            dialog.close();
+        }
+
+        private void action_wipe_trash()
+        {
+            var dialog = new Gtk.MessageDialog ((GLib.Application.get_default() as 
Application).get_window(), Gtk.DialogFlags.MODAL,
+                Gtk.MessageType.WARNING, Gtk.ButtonsType.OK_CANCEL, _("Empty all items from Trash?"));
+            dialog.secondary_text = _("All items in the Trash will be permanently deleted.");
+
+            if(dialog.run() == Gtk.ResponseType.OK)
+            {
+               Timeout.add(0, () => {
+                    var storage_analyzer = (GLib.Application.get_default() as 
Application).get_storage_analyzer();
+                    storage_analyzer.wipe_trash.begin(() => {
+                        ((StorageView) (GLib.Application.get_default() as 
Application).get_window().get_views()[2]).get_storage_list_box().refresh();
+                    });
+
+                    return false;
+                });
+            }
+            dialog.close();
+        }
+
+        private void action_rename()
+        {
+            var pop = new Gtk.Popover (this);
+            var box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 5);
+            box.margin = 10;
+            var entry = new Gtk.Entry();
+            entry.set_text (Path.get_basename(item_path));
+            box.add(entry);
+            var button = new Gtk.Button.with_label(_("Rename"));
+            button.get_style_context().add_class ("suggested-action");
+            button.clicked.connect (() => {
+               Timeout.add(0, () => {
+                    string destination = Path.get_dirname(item_path) + "/" + entry.get_text();
+                    var storage_analyzer = (GLib.Application.get_default() as 
Application).get_storage_analyzer();
+                    storage_analyzer.move_file.begin(File.new_for_path(item_path), 
File.new_for_path(destination), () => {
+                        ((StorageView) (GLib.Application.get_default() as 
Application).get_window().get_views()[2]).get_storage_list_box().refresh();
+                    });
+
+                    return false;
+                });
+            });
+            entry.activate.connect(() => {
+                button.activate();
+            });
+            box.add(button);
+            pop.add(box);
+            pop.set_position(Gtk.PositionType.BOTTOM);
+            pop.show_all ();
+        }
+
+        private void action_move()
+        {
+            Gtk.FileChooserDialog chooser = new Gtk.FileChooserDialog (
+                _("Select destination folder"), (GLib.Application.get_default() as 
Application).get_window(), Gtk.FileChooserAction.SELECT_FOLDER,
+                _("Cancel"),
+                Gtk.ResponseType.CANCEL,
+                _("Select"),
+                Gtk.ResponseType.ACCEPT);
+            chooser.destroy_with_parent = true;
+            Gtk.FileFilter filter = new Gtk.FileFilter();
+            filter.add_custom(Gtk.FileFilterFlags.FILENAME, (filter_info) => {
+                if(filter_info.filename != item_path)
+                    return true;
+                else
+                    return false;
+            });
+            chooser.set_filter(filter);
+            chooser.set_filename(item_path);
+            chooser.show();
+
+            if(chooser.run() == Gtk.ResponseType.ACCEPT)
+            {
+               Timeout.add(0, () => {
+                   string destination = chooser.get_file().get_parse_name() + "/" + 
Path.get_basename(item_path);
+                    var storage_analyzer = (GLib.Application.get_default() as 
Application).get_storage_analyzer();
+                    storage_analyzer.move_file.begin(File.new_for_path(item_path), 
File.new_for_path(destination), () => {
+                        ((StorageView) (GLib.Application.get_default() as 
Application).get_window().get_views()[2]).get_storage_list_box().refresh();
+                    });
+
+                    return false;
+                });
+            }
+            chooser.close ();
+        }
+
+        private void action_move_to_trash()
+        {
+            Timeout.add(0, () => {
+                var storage_analyzer = (GLib.Application.get_default() as 
Application).get_storage_analyzer();
+                storage_analyzer.trash_file.begin(item_path, () => {
+                    ((StorageView) (GLib.Application.get_default() as 
Application).get_window().get_views()[2]).get_storage_list_box().refresh();
+                });
+
+                return false;
+            });
+        }
+
+        private void action_delete()
+        {
+            Timeout.add(0, () => {
+                var storage_analyzer = (GLib.Application.get_default() as 
Application).get_storage_analyzer();
+                storage_analyzer.delete_file.begin(item_path, () => {
+                    ((StorageView) (GLib.Application.get_default() as 
Application).get_window().get_views()[2]).get_storage_list_box().refresh();
+                });
+
+                return false;
+            });
+        }
     }
 }
diff --git a/src/storage-view.vala b/src/storage-view.vala
index bdc3a12..4e984c5 100644
--- a/src/storage-view.vala
+++ b/src/storage-view.vala
@@ -23,12 +23,23 @@ namespace Usage
             paned.position = 300;
             paned.add2(spinner);
 
-            Gtk.Label empty_label = new Gtk.Label("<span font_desc=\"17.0\">" + _("No content here") + 
"</span>");
+            var center_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 12);
+            var image = new Gtk.Image.from_icon_name("folder-symbolic", Gtk.IconSize.DIALOG );
+            image.pixel_size = 128;
+            center_box.add(image);
+
+            Gtk.Label empty_label = new Gtk.Label("<span size='xx-large' font_weight='bold'>" + _("No 
content here") + "</span>");
             empty_label.set_use_markup (true);
+            empty_label.margin_top = 10;
+            center_box.add(empty_label);
+            center_box.get_style_context().add_class("dim-label");
+            var empty_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
+            empty_box.set_center_widget(center_box);
+            empty_box.show_all();
 
             storage_list_box.loading.connect(() =>
             {
-                paned.remove(empty_label);
+                paned.remove(empty_box);
                 paned.remove(scrolled_window);
                 paned.remove(graph);
                 paned.add2(spinner);
@@ -49,7 +60,7 @@ namespace Usage
                 paned.remove(scrolled_window);
                 paned.remove(graph);
                 paned.remove(spinner);
-                paned.add2(empty_label);
+                paned.add2(empty_box);
                 empty_label.show();
             });
 
diff --git a/src/storage-worker.vala b/src/storage-worker.vala
index f51e15f..cabcb9b 100644
--- a/src/storage-worker.vala
+++ b/src/storage-worker.vala
@@ -2,9 +2,8 @@ namespace Usage
 {
     [Compact]
     public class StorageResult {
-        internal string path;
-        internal uint64 size;
-        internal float percentage;
+        public string path;
+        public uint64 size;
     }
 
     public class StorageWorker
@@ -13,28 +12,22 @@ namespace Usage
         private File path;
         private string[] exclude_paths;
         private Cancellable cancellable;
-        private string? name;
-        private uint64 total_size;
 
-        public StorageWorker(File path, uint64 total_size, ref Cancellable cancellable, ref 
AsyncQueue<StorageResult> results_queue, string? name = null, string[]? exclude_paths = null)
+        public StorageWorker(File path, ref Cancellable cancellable, ref AsyncQueue<StorageResult> 
results_queue, string[]? exclude_paths = null)
         {
             this.path = path;
             this.cancellable = cancellable;
-            this.name = name;
             this.exclude_paths = exclude_paths;
             this.results_queue = results_queue;
-            this.total_size = total_size;
         }
 
-        private StorageResult get_directory(File file, out uint64 size)
+        private uint64 get_directory(File file)
         {
             string path = file.get_parse_name();
-            FileEnumerator enumerator;
-            List<StorageResult> childs = new List<StorageResult>();
-            size = 0;
+            uint64 size = 0;
 
             try {
-                enumerator = file.enumerate_children(FileAttribute.STANDARD_SIZE, 
FileQueryInfoFlags.NOFOLLOW_SYMLINKS, cancellable);
+                FileEnumerator enumerator = file.enumerate_children(FileAttribute.STANDARD_SIZE + "," + 
FileAttribute.STANDARD_NAME + "," + FileAttribute.STANDARD_TYPE, FileQueryInfoFlags.NOFOLLOW_SYMLINKS, 
cancellable);
                 FileInfo info;
 
                 while((info = enumerator.next_file(null)) != null && cancellable.is_cancelled() == false)
@@ -44,9 +37,7 @@ namespace Usage
                         if(exclude_paths == null || !(file.resolve_relative_path(info.get_name()).get_path() 
in exclude_paths))
                         {
                             var child = file.get_child(info.get_name());
-                            uint64 child_size = 0;
-                            childs.append(get_directory(child, out child_size));
-                            size += child_size;
+                            size += get_directory(child);
                         }
                     }
                     else if(info.get_file_type() == FileType.REGULAR)
@@ -62,26 +53,14 @@ namespace Usage
             StorageResult result = new StorageResult();
             result.path = path;
             result.size = size;
+            results_queue.push ((owned) result);
 
-            foreach (unowned StorageResult child in childs)
-            {
-                child.percentage = ((float) child.size / size) * 100;
-                var child_copy = new StorageResult();
-                child_copy.path = child.path;
-                child_copy.size = child.size;
-                child_copy.percentage = child.percentage;
-                results_queue.push ((owned) child_copy);
-            }
-
-            return result;
+            return size;
         }
 
         public void run ()
         {
-            uint64 size = 0;
-            var child = get_directory(path, out size);
-            child.percentage = ((float) size / total_size) * 100;
-            results_queue.push ((owned) child);
+            get_directory(path);
         }
     }
 }
\ No newline at end of file
diff --git a/src/system-monitor.vala b/src/system-monitor.vala
index ca15c9f..eecccd4 100644
--- a/src/system-monitor.vala
+++ b/src/system-monitor.vala
@@ -187,34 +187,37 @@ namespace Usage
             foreach (AppInfo info in apps_info)
             {
                 string commandline = info.get_commandline();
-                for (int i = 0; i < commandline.length; i++)
+                if(commandline != null)
                 {
-                    if(commandline[i] == ' ' && commandline[i] == '%')
-                        commandline = commandline.substring(0, i);
-                }
-
-                commandline = Path.get_basename(commandline);
-                string process_full_cmd = cmdline + " " + cmdline_parameter;
-                if(commandline == process_full_cmd)
-                    app_info = info;
-                else if(commandline.contains("google-" + cmdline + "-")) //Fix for Google Chrome naming
-                    app_info = info;
-
-                if(app_info == null)
-                {
-                    commandline = info.get_commandline();
                     for (int i = 0; i < commandline.length; i++)
                     {
-                        if(commandline[i] == ' ')
+                        if(commandline[i] == ' ' && commandline[i] == '%')
                             commandline = commandline.substring(0, i);
                     }
 
-                    if(info.get_commandline().has_prefix(commandline + " " + commandline + "://")) //Fix for 
Steam naming
-                        commandline = info.get_commandline();
-
                     commandline = Path.get_basename(commandline);
-                    if(commandline == cmdline)
+                    string process_full_cmd = cmdline + " " + cmdline_parameter;
+                    if(commandline == process_full_cmd)
                         app_info = info;
+                    else if(commandline.contains("google-" + cmdline + "-")) //Fix for Google Chrome naming
+                        app_info = info;
+
+                    if(app_info == null)
+                    {
+                        commandline = info.get_commandline();
+                        for (int i = 0; i < commandline.length; i++)
+                        {
+                            if(commandline[i] == ' ')
+                                commandline = commandline.substring(0, i);
+                        }
+
+                        if(info.get_commandline().has_prefix(commandline + " " + commandline + "://")) //Fix 
for Steam naming
+                            commandline = info.get_commandline();
+
+                        commandline = Path.get_basename(commandline);
+                        if(commandline == cmdline)
+                            app_info = info;
+                    }
                 }
             }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]