[baobab] Consistenly convert to space indent
- From: Paolo Borelli <pborelli src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [baobab] Consistenly convert to space indent
- Date: Fri, 6 Apr 2012 17:08:38 +0000 (UTC)
commit 1251e74399d6bbbda0d5a4f40b03efb0cf25678d
Author: Paolo Borelli <pborelli gnome org>
Date: Fri Apr 6 18:37:29 2012 +0200
Consistenly convert to space indent
Let's make indentation sane and consistent before it is too late
src/baobab-application.vala | 214 ++++----
src/baobab-cellrenderers.vala | 142 +++---
src/baobab-connect-server.vala | 104 ++--
src/baobab-location-monitor.vala | 1 +
src/baobab-location-widget.vala | 1 +
src/baobab-location.vala | 1 +
src/baobab-scanner.vala | 305 ++++++------
src/baobab-sync-scanner.vala | 248 +++++-----
src/baobab-threaded-scanner.vala | 492 +++++++++---------
src/baobab-window.vala | 1077 +++++++++++++++++++-------------------
src/main.vala | 11 +-
11 files changed, 1307 insertions(+), 1289 deletions(-)
---
diff --git a/src/baobab-application.vala b/src/baobab-application.vala
index 08832bf..305bfa6 100644
--- a/src/baobab-application.vala
+++ b/src/baobab-application.vala
@@ -1,3 +1,4 @@
+/* -*- indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Baobab - disk usage analyzer
*
* Copyright (C) 2012 Ryan Lortie <desrt desrt ca>
@@ -20,110 +21,111 @@
*/
namespace Baobab {
- public class Application : Gtk.Application {
- static Application baobab;
-
- private const GLib.ActionEntry[] action_entries = {
- { "quit", on_quit_activate }
- };
-
- Settings desktop_settings;
- Settings prefs_settings;
- Settings ui_settings;
-
- protected override void activate () {
- new Window (this);
- }
-
- protected override void open (File[] files, string hint) {
- foreach (var file in files) {
- var window = new Window (this);
- window.scan_directory (file);
- }
- }
-
- public static HashTable<File, unowned File> get_excluded_locations () {
- var app = baobab;
-
- var excluded_locations = new HashTable<File, unowned File> (File.hash, File.equal);
- excluded_locations.add (File.new_for_path ("/proc"));
- excluded_locations.add (File.new_for_path ("/sys"));
- excluded_locations.add (File.new_for_path ("/selinux"));
-
- var home = File.new_for_path (Environment.get_home_dir ());
- excluded_locations.add (home.get_child (".gvfs"));
-
- var root = File.new_for_path ("/");
- foreach (var uri in app.prefs_settings.get_value ("excluded-uris")) {
- var file = File.new_for_uri ((string) uri);
- if (!file.equal (root)) {
- excluded_locations.add (file);
- }
- }
-
- return excluded_locations;
- }
-
- protected override void startup () {
- base.startup ();
-
- baobab = this;
-
- // Settings
- ui_settings = new Settings ("org.gnome.baobab.ui");
- prefs_settings = new Settings ("org.gnome.baobab.preferences");
- desktop_settings = new Settings ("org.gnome.desktop.interface");
-
- // Menus: in gnome shell we just use the app menu, since the remaining
- // items are too few to look ok in a menubar and they are not essential
- var gtk_settings = Gtk.Settings.get_default ();
- var builder = new Gtk.Builder ();
- try {
- builder.add_from_resource ("/org/gnome/baobab/ui/baobab-menu.ui");
- } catch (Error e) {
- error ("loading menu builder file: %s", e.message);
- }
- if (gtk_settings.gtk_shell_shows_app_menu) {
- var app_menu = builder.get_object ("appmenu") as MenuModel;
- set_app_menu (app_menu);
- } else {
- var menubar = builder.get_object ("menubar") as MenuModel;
- set_menubar (menubar);
- }
- }
-
- protected override bool local_command_line ([CCode (array_length = false, array_null_terminated = true)] ref unowned string[] arguments, out int exit_status) {
- if (arguments[1] == "-v") {
- print ("%s %s\n", Environment.get_application_name (), Config.VERSION);
- exit_status = 0;
- return true;
- }
-
- return base.local_command_line (ref arguments, out exit_status);
- }
-
- public Application () {
- Object (application_id: "org.gnome.baobab", flags: ApplicationFlags.HANDLES_OPEN);
-
- add_action_entries (action_entries, this);
- }
-
- public static Settings get_desktop_settings () {
- var app = baobab;
- return app.desktop_settings;
- }
-
- public static Settings get_prefs_settings () {
- var app = baobab;
- return app.prefs_settings;
- }
-
- public static Settings get_ui_settings () {
- var app = baobab;
- return app.ui_settings;
- }
-
- void on_quit_activate () {
- }
- }
+
+ public class Application : Gtk.Application {
+ static Application baobab;
+
+ private const GLib.ActionEntry[] action_entries = {
+ { "quit", on_quit_activate }
+ };
+
+ Settings desktop_settings;
+ Settings prefs_settings;
+ Settings ui_settings;
+
+ protected override void activate () {
+ new Window (this);
+ }
+
+ protected override void open (File[] files, string hint) {
+ foreach (var file in files) {
+ var window = new Window (this);
+ window.scan_directory (file);
+ }
+ }
+
+ public static HashTable<File, unowned File> get_excluded_locations () {
+ var app = baobab;
+
+ var excluded_locations = new HashTable<File, unowned File> (File.hash, File.equal);
+ excluded_locations.add (File.new_for_path ("/proc"));
+ excluded_locations.add (File.new_for_path ("/sys"));
+ excluded_locations.add (File.new_for_path ("/selinux"));
+
+ var home = File.new_for_path (Environment.get_home_dir ());
+ excluded_locations.add (home.get_child (".gvfs"));
+
+ var root = File.new_for_path ("/");
+ foreach (var uri in app.prefs_settings.get_value ("excluded-uris")) {
+ var file = File.new_for_uri ((string) uri);
+ if (!file.equal (root)) {
+ excluded_locations.add (file);
+ }
+ }
+
+ return excluded_locations;
+ }
+
+ protected override void startup () {
+ base.startup ();
+
+ baobab = this;
+
+ // Settings
+ ui_settings = new Settings ("org.gnome.baobab.ui");
+ prefs_settings = new Settings ("org.gnome.baobab.preferences");
+ desktop_settings = new Settings ("org.gnome.desktop.interface");
+
+ // Menus: in gnome shell we just use the app menu, since the remaining
+ // items are too few to look ok in a menubar and they are not essential
+ var gtk_settings = Gtk.Settings.get_default ();
+ var builder = new Gtk.Builder ();
+ try {
+ builder.add_from_resource ("/org/gnome/baobab/ui/baobab-menu.ui");
+ } catch (Error e) {
+ error ("loading menu builder file: %s", e.message);
+ }
+ if (gtk_settings.gtk_shell_shows_app_menu) {
+ var app_menu = builder.get_object ("appmenu") as MenuModel;
+ set_app_menu (app_menu);
+ } else {
+ var menubar = builder.get_object ("menubar") as MenuModel;
+ set_menubar (menubar);
+ }
+ }
+
+ protected override bool local_command_line ([CCode (array_length = false, array_null_terminated = true)] ref unowned string[] arguments, out int exit_status) {
+ if (arguments[1] == "-v") {
+ print ("%s %s\n", Environment.get_application_name (), Config.VERSION);
+ exit_status = 0;
+ return true;
+ }
+
+ return base.local_command_line (ref arguments, out exit_status);
+ }
+
+ public Application () {
+ Object (application_id: "org.gnome.baobab", flags: ApplicationFlags.HANDLES_OPEN);
+
+ add_action_entries (action_entries, this);
+ }
+
+ public static Settings get_desktop_settings () {
+ var app = baobab;
+ return app.desktop_settings;
+ }
+
+ public static Settings get_prefs_settings () {
+ var app = baobab;
+ return app.prefs_settings;
+ }
+
+ public static Settings get_ui_settings () {
+ var app = baobab;
+ return app.ui_settings;
+ }
+
+ void on_quit_activate () {
+ }
+ }
}
diff --git a/src/baobab-cellrenderers.vala b/src/baobab-cellrenderers.vala
index 3a86405..0fe987c 100644
--- a/src/baobab-cellrenderers.vala
+++ b/src/baobab-cellrenderers.vala
@@ -1,3 +1,4 @@
+/* -*- indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Baobab - disk usage analyzer
*
* Copyright (C) 2012 Ryan Lortie <desrt desrt ca>
@@ -18,82 +19,83 @@
*/
namespace Baobab {
- public class CellRendererPercent : Gtk.CellRendererText {
- public double percent {
- set {
- text = "%.1f %%".printf (value);
- }
- }
- }
- public class CellRendererSize : Gtk.CellRendererText {
- public new uint64 size {
- set {
- if (!show_allocated_size) {
- text = format_size (value);
- }
- }
- }
+ public class CellRendererPercent : Gtk.CellRendererText {
+ public double percent {
+ set {
+ text = "%.1f %%".printf (value);
+ }
+ }
+ }
- public uint64 alloc_size {
- set {
- if (show_allocated_size) {
- text = format_size (value);
- }
- }
- }
+ public class CellRendererSize : Gtk.CellRendererText {
+ public new uint64 size {
+ set {
+ if (!show_allocated_size) {
+ text = format_size (value);
+ }
+ }
+ }
- public bool show_allocated_size { private get; set; }
- }
+ public uint64 alloc_size {
+ set {
+ if (show_allocated_size) {
+ text = format_size (value);
+ }
+ }
+ }
- public class CellRendererItems : Gtk.CellRendererText {
- public int items {
- set {
- text = value >= 0 ? ngettext ("%d item", "%d items", value).printf (value) : "";
- }
- }
- }
+ public bool show_allocated_size { private get; set; }
+ }
- public class CellRendererProgress : Gtk.CellRendererProgress {
- public override void render (Cairo.Context cr, Gtk.Widget widget, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gtk.CellRendererState flags) {
- int xpad;
- int ypad;
- get_padding (out xpad, out ypad);
+ public class CellRendererItems : Gtk.CellRendererText {
+ public int items {
+ set {
+ text = value >= 0 ? ngettext ("%d item", "%d items", value).printf (value) : "";
+ }
+ }
+ }
- // fill entire drawing area with black
- var x = cell_area.x + xpad;
- var y = cell_area.y + ypad;
- var w = cell_area.width - xpad * 2;
- var h = cell_area.height - ypad * 2;
- cr.rectangle (x, y, w, h);
- cr.set_source_rgb (0, 0, 0);
- cr.fill ();
+ public class CellRendererProgress : Gtk.CellRendererProgress {
+ public override void render (Cairo.Context cr, Gtk.Widget widget, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gtk.CellRendererState flags) {
+ int xpad;
+ int ypad;
+ get_padding (out xpad, out ypad);
- // draw a smaller white rectangle on top, leaving a black outline
- var style = widget.get_style ();
- x += style.xthickness;
- y += style.xthickness;
- w -= style.xthickness * 2;
- h -= style.xthickness * 2;
- cr.rectangle (x, y, w, h);
- cr.set_source_rgb (1, 1, 1);
- cr.fill ();
+ // fill entire drawing area with black
+ var x = cell_area.x + xpad;
+ var y = cell_area.y + ypad;
+ var w = cell_area.width - xpad * 2;
+ var h = cell_area.height - ypad * 2;
+ cr.rectangle (x, y, w, h);
+ cr.set_source_rgb (0, 0, 0);
+ cr.fill ();
- // fill in remaining area according to percentage value
- var percent = value;
- var perc_w = (w * percent) / 100;
- if (widget.get_direction () == Gtk.TextDirection.RTL) {
- x += w - perc_w;
- }
- cr.rectangle (x, y, perc_w, h);
- if (percent <= 33) {
- cr.set_source_rgb (0x73 / 255.0, 0xd2 / 255.0, 0x16 / 255.0);
- } else if (percent <= 66) {
- cr.set_source_rgb (0xed / 255.0, 0xd4 / 255.0, 0x00 / 255.0);
- } else {
- cr.set_source_rgb (0xcc / 255.0, 0x00 / 255.0, 0x00 / 255.0);
- }
- cr.fill ();
- }
- }
+ // draw a smaller white rectangle on top, leaving a black outline
+ var style = widget.get_style ();
+ x += style.xthickness;
+ y += style.xthickness;
+ w -= style.xthickness * 2;
+ h -= style.xthickness * 2;
+ cr.rectangle (x, y, w, h);
+ cr.set_source_rgb (1, 1, 1);
+ cr.fill ();
+
+ // fill in remaining area according to percentage value
+ var percent = value;
+ var perc_w = (w * percent) / 100;
+ if (widget.get_direction () == Gtk.TextDirection.RTL) {
+ x += w - perc_w;
+ }
+ cr.rectangle (x, y, perc_w, h);
+ if (percent <= 33) {
+ cr.set_source_rgb (0x73 / 255.0, 0xd2 / 255.0, 0x16 / 255.0);
+ } else if (percent <= 66) {
+ cr.set_source_rgb (0xed / 255.0, 0xd4 / 255.0, 0x00 / 255.0);
+ } else {
+ cr.set_source_rgb (0xcc / 255.0, 0x00 / 255.0, 0x00 / 255.0);
+ }
+ cr.fill ();
+ }
+ }
}
diff --git a/src/baobab-connect-server.vala b/src/baobab-connect-server.vala
index 14d7a76..8c86178 100644
--- a/src/baobab-connect-server.vala
+++ b/src/baobab-connect-server.vala
@@ -1,3 +1,4 @@
+/* -*- indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Baobab - disk usage analyzer
*
* Copyright (C) 2012 Paolo Borelli <pborelli gnome org>
@@ -18,65 +19,66 @@
*/
namespace Baobab {
- class ConnectServer : Object {
- string[] argv = {
- "nautilus-connect-server",
- "--print-uri"
- };
- public signal void selected(string? uri);
+ class ConnectServer : Object {
+ string[] argv = {
+ "nautilus-connect-server",
+ "--print-uri"
+ };
- void on_child_watch (Pid pid, int status) {
- Process.close_pid (pid);
- }
+ public signal void selected(string? uri);
- bool on_out_watch (IOChannel channel, IOCondition cond) {
- if (IOCondition.HUP in cond) {
- selected(null);
- return false;
- }
+ void on_child_watch (Pid pid, int status) {
+ Process.close_pid (pid);
+ }
- string? uri = null;
- try {
- size_t len;
- size_t lineend;
- channel.read_line(out uri, out len, out lineend);
- if (len > 0) {
- uri = uri[0:(int)lineend];
- }
- } catch {
- } finally {
- selected(uri);
- }
+ bool on_out_watch (IOChannel channel, IOCondition cond) {
+ if (IOCondition.HUP in cond) {
+ selected(null);
+ return false;
+ }
- return true;
- }
+ string? uri = null;
+ try {
+ size_t len;
+ size_t lineend;
+ channel.read_line(out uri, out len, out lineend);
+ if (len > 0) {
+ uri = uri[0:(int)lineend];
+ }
+ } catch {
+ } finally {
+ selected(uri);
+ }
- public void show () {
+ return true;
+ }
- Pid pid;
- int out_fd;
+ public void show () {
- try {
- Process.spawn_async_with_pipes (
- null,
- argv,
- null, // envp
- SpawnFlags.SEARCH_PATH | SpawnFlags.STDERR_TO_DEV_NULL,
- null, // child_setup
- out pid,
- null, // stdin
- out out_fd,
- null // stderr
- );
- } catch (SpawnError e) {
- warning ("Failed to run nautilus-connect-server: %s", e.message);
- }
+ Pid pid;
+ int out_fd;
- var out_channel = new IOChannel.unix_new (out_fd);
- out_channel.add_watch (IOCondition.IN | IOCondition.HUP, on_out_watch);
+ try {
+ Process.spawn_async_with_pipes (
+ null,
+ argv,
+ null, // envp
+ SpawnFlags.SEARCH_PATH | SpawnFlags.STDERR_TO_DEV_NULL,
+ null, // child_setup
+ out pid,
+ null, // stdin
+ out out_fd,
+ null // stderr
+ );
+ } catch (SpawnError e) {
+ warning ("Failed to run nautilus-connect-server: %s", e.message);
+ }
- ChildWatch.add (pid, on_child_watch);
- }
- }
+ var out_channel = new IOChannel.unix_new (out_fd);
+ out_channel.add_watch (IOCondition.IN | IOCondition.HUP, on_out_watch);
+
+ ChildWatch.add (pid, on_child_watch);
+ }
+ }
}
diff --git a/src/baobab-location-monitor.vala b/src/baobab-location-monitor.vala
index 23f41d5..47c45e1 100644
--- a/src/baobab-location-monitor.vala
+++ b/src/baobab-location-monitor.vala
@@ -19,6 +19,7 @@
*/
namespace Baobab {
+
public class LocationMonitor {
private static LocationMonitor? instance = null;
diff --git a/src/baobab-location-widget.vala b/src/baobab-location-widget.vala
index a68e351..632597c 100644
--- a/src/baobab-location-widget.vala
+++ b/src/baobab-location-widget.vala
@@ -19,6 +19,7 @@
*/
namespace Baobab {
+
public class LocationWidget : Gtk.Grid {
private static Gtk.SizeGroup name_size_group = null;
private static Gtk.SizeGroup mount_point_size_group = null;
diff --git a/src/baobab-location.vala b/src/baobab-location.vala
index 8f384c3..1cf399a 100644
--- a/src/baobab-location.vala
+++ b/src/baobab-location.vala
@@ -19,6 +19,7 @@
*/
namespace Baobab {
+
public class Location {
public string name { get; private set; }
public string? mount_point { get; private set; }
diff --git a/src/baobab-scanner.vala b/src/baobab-scanner.vala
index 2605039..429b1e4 100644
--- a/src/baobab-scanner.vala
+++ b/src/baobab-scanner.vala
@@ -1,3 +1,4 @@
+/* -*- indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Baobab - disk usage analyzer
*
* Copyright (C) 2012 Ryan Lortie <desrt desrt ca>
@@ -20,155 +21,157 @@
*/
namespace Baobab {
- [Flags]
- public enum ScanFlags {
- NONE,
- EXCLUDE_MOUNTS
- }
-
- abstract class Scanner : Gtk.TreeStore {
- public enum Columns {
- DISPLAY_NAME,
- PARSE_NAME,
- PERCENT,
- SIZE,
- ALLOC_SIZE,
- ELEMENTS,
- STATE,
- ERROR,
- COLUMNS
- }
-
- public enum State {
- SCANNING,
- CANCELLED,
- NEED_PERCENT,
- ERROR,
- DONE
- }
-
- protected struct HardLink {
- uint64 inode;
- uint32 device;
-
- public HardLink (FileInfo info) {
- this.inode = info.get_attribute_uint64 (FileAttribute.UNIX_INODE);
- this.device = info.get_attribute_uint32 (FileAttribute.UNIX_DEVICE);
- }
- }
-
- protected Cancellable cancellable;
- protected HashTable<File, unowned File> excluded_locations;
- protected HardLink[] hardlinks;
- protected Error? scan_error;
-
- protected static const string ATTRIBUTES =
- FileAttribute.STANDARD_NAME + "," +
- FileAttribute.STANDARD_DISPLAY_NAME + "," +
- FileAttribute.STANDARD_TYPE + "," +
- FileAttribute.STANDARD_SIZE + "," +
- FileAttribute.STANDARD_ALLOCATED_SIZE + "," +
- FileAttribute.UNIX_NLINK + "," +
- FileAttribute.UNIX_INODE + "," +
- FileAttribute.UNIX_DEVICE + "," +
- FileAttribute.ACCESS_CAN_READ;
-
- public File directory { get; private set; }
-
- public ScanFlags scan_flags { get; private set; }
-
- public int max_depth { get; protected set; }
-
- public signal void completed();
-
- public abstract void scan ();
-
- public virtual void cancel () {
- cancellable.cancel ();
- }
-
- public virtual void finish () throws Error {
- if (scan_error != null) {
- throw scan_error;
- }
- }
-
- protected static const string FS_ATTRIBUTES =
- FileAttribute.FILESYSTEM_SIZE + "," +
- FileAttribute.FILESYSTEM_USED + "," +
- FileAttribute.FILESYSTEM_FREE;
-
- public void get_filesystem_usage () throws Error {
- var info = directory.query_filesystem_info (FS_ATTRIBUTES, cancellable);
-
- var size = info.get_attribute_uint64 (FileAttribute.FILESYSTEM_SIZE);
- var used = info.get_attribute_uint64 (FileAttribute.FILESYSTEM_USED);
- var free = info.get_attribute_uint64 (FileAttribute.FILESYSTEM_FREE);
- var reserved = size - free - used;
-
- var used_perc = 100 * ((double) used) / ((double) size);
- var reserved_perc = 100 * ((double) reserved) / ((double) size);
-
- Gtk.TreeIter? root_iter, iter;
- append (out root_iter, null);
- set (root_iter,
- Columns.STATE, State.DONE,
- Columns.DISPLAY_NAME, _("Total filesystem capacity"),
- Columns.PARSE_NAME, "",
- Columns.SIZE, size,
- Columns.ALLOC_SIZE, size,
- Columns.PERCENT, 100.0,
- Columns.ELEMENTS, -1,
- Columns.ERROR, null);
-
- append (out iter, root_iter);
- set (iter,
- Columns.STATE, State.DONE,
- Columns.DISPLAY_NAME, _("Used"),
- Columns.PARSE_NAME, "",
- Columns.SIZE, used,
- Columns.ALLOC_SIZE, used,
- Columns.PERCENT, used_perc,
- Columns.ELEMENTS, -1,
- Columns.ERROR, null);
-
- append (out iter, root_iter);
- set (iter,
- Columns.STATE, State.DONE,
- Columns.DISPLAY_NAME, _("Reserved"),
- Columns.PARSE_NAME, "",
- Columns.SIZE, reserved,
- Columns.ALLOC_SIZE, reserved,
- Columns.PERCENT, reserved_perc,
- Columns.ELEMENTS, -1,
- Columns.ERROR, null);
- }
-
- public Scanner (File directory, ScanFlags flags) {
- this.directory = directory;
- this.scan_flags = flags;
- cancellable = new Cancellable();
- scan_error = null;
- set_column_types (new Type[] {
- typeof (string), // DIR_NAME
- typeof (string), // PARSE_NAME
- typeof (double), // PERCENT
- typeof (uint64), // SIZE
- typeof (uint64), // ALLOC_SIZE
- typeof (int), // ELEMENTS
- typeof (State), // STATE
- typeof (Error)}); // ERROR (if STATE is ERROR)
- set_sort_column_id (Columns.SIZE, Gtk.SortType.DESCENDING);
-
- excluded_locations = Application.get_excluded_locations ();
-
- if (ScanFlags.EXCLUDE_MOUNTS in flags) {
- foreach (unowned UnixMountEntry mount in UnixMountEntry.get (null)) {
- excluded_locations.add (File.new_for_path (mount.get_mount_path ()));
- }
- }
-
- excluded_locations.remove (directory);
- }
- }
+
+ [Flags]
+ public enum ScanFlags {
+ NONE,
+ EXCLUDE_MOUNTS
+ }
+
+ abstract class Scanner : Gtk.TreeStore {
+ public enum Columns {
+ DISPLAY_NAME,
+ PARSE_NAME,
+ PERCENT,
+ SIZE,
+ ALLOC_SIZE,
+ ELEMENTS,
+ STATE,
+ ERROR,
+ COLUMNS
+ }
+
+ public enum State {
+ SCANNING,
+ CANCELLED,
+ NEED_PERCENT,
+ ERROR,
+ DONE
+ }
+
+ protected struct HardLink {
+ uint64 inode;
+ uint32 device;
+
+ public HardLink (FileInfo info) {
+ this.inode = info.get_attribute_uint64 (FileAttribute.UNIX_INODE);
+ this.device = info.get_attribute_uint32 (FileAttribute.UNIX_DEVICE);
+ }
+ }
+
+ protected Cancellable cancellable;
+ protected HashTable<File, unowned File> excluded_locations;
+ protected HardLink[] hardlinks;
+ protected Error? scan_error;
+
+ protected static const string ATTRIBUTES =
+ FileAttribute.STANDARD_NAME + "," +
+ FileAttribute.STANDARD_DISPLAY_NAME + "," +
+ FileAttribute.STANDARD_TYPE + "," +
+ FileAttribute.STANDARD_SIZE + "," +
+ FileAttribute.STANDARD_ALLOCATED_SIZE + "," +
+ FileAttribute.UNIX_NLINK + "," +
+ FileAttribute.UNIX_INODE + "," +
+ FileAttribute.UNIX_DEVICE + "," +
+ FileAttribute.ACCESS_CAN_READ;
+
+ public File directory { get; private set; }
+
+ public ScanFlags scan_flags { get; private set; }
+
+ public int max_depth { get; protected set; }
+
+ public signal void completed();
+
+ public abstract void scan ();
+
+ public virtual void cancel () {
+ cancellable.cancel ();
+ }
+
+ public virtual void finish () throws Error {
+ if (scan_error != null) {
+ throw scan_error;
+ }
+ }
+
+ protected static const string FS_ATTRIBUTES =
+ FileAttribute.FILESYSTEM_SIZE + "," +
+ FileAttribute.FILESYSTEM_USED + "," +
+ FileAttribute.FILESYSTEM_FREE;
+
+ public void get_filesystem_usage () throws Error {
+ var info = directory.query_filesystem_info (FS_ATTRIBUTES, cancellable);
+
+ var size = info.get_attribute_uint64 (FileAttribute.FILESYSTEM_SIZE);
+ var used = info.get_attribute_uint64 (FileAttribute.FILESYSTEM_USED);
+ var free = info.get_attribute_uint64 (FileAttribute.FILESYSTEM_FREE);
+ var reserved = size - free - used;
+
+ var used_perc = 100 * ((double) used) / ((double) size);
+ var reserved_perc = 100 * ((double) reserved) / ((double) size);
+
+ Gtk.TreeIter? root_iter, iter;
+ append (out root_iter, null);
+ set (root_iter,
+ Columns.STATE, State.DONE,
+ Columns.DISPLAY_NAME, _("Total filesystem capacity"),
+ Columns.PARSE_NAME, "",
+ Columns.SIZE, size,
+ Columns.ALLOC_SIZE, size,
+ Columns.PERCENT, 100.0,
+ Columns.ELEMENTS, -1,
+ Columns.ERROR, null);
+
+ append (out iter, root_iter);
+ set (iter,
+ Columns.STATE, State.DONE,
+ Columns.DISPLAY_NAME, _("Used"),
+ Columns.PARSE_NAME, "",
+ Columns.SIZE, used,
+ Columns.ALLOC_SIZE, used,
+ Columns.PERCENT, used_perc,
+ Columns.ELEMENTS, -1,
+ Columns.ERROR, null);
+
+ append (out iter, root_iter);
+ set (iter,
+ Columns.STATE, State.DONE,
+ Columns.DISPLAY_NAME, _("Reserved"),
+ Columns.PARSE_NAME, "",
+ Columns.SIZE, reserved,
+ Columns.ALLOC_SIZE, reserved,
+ Columns.PERCENT, reserved_perc,
+ Columns.ELEMENTS, -1,
+ Columns.ERROR, null);
+ }
+
+ public Scanner (File directory, ScanFlags flags) {
+ this.directory = directory;
+ this.scan_flags = flags;
+ cancellable = new Cancellable();
+ scan_error = null;
+ set_column_types (new Type[] {
+ typeof (string), // DIR_NAME
+ typeof (string), // PARSE_NAME
+ typeof (double), // PERCENT
+ typeof (uint64), // SIZE
+ typeof (uint64), // ALLOC_SIZE
+ typeof (int), // ELEMENTS
+ typeof (State), // STATE
+ typeof (Error) // ERROR (if STATE is ERROR)
+ });
+ set_sort_column_id (Columns.SIZE, Gtk.SortType.DESCENDING);
+
+ excluded_locations = Application.get_excluded_locations ();
+
+ if (ScanFlags.EXCLUDE_MOUNTS in flags) {
+ foreach (unowned UnixMountEntry mount in UnixMountEntry.get (null)) {
+ excluded_locations.add (File.new_for_path (mount.get_mount_path ()));
+ }
+ }
+
+ excluded_locations.remove (directory);
+ }
+ }
}
diff --git a/src/baobab-sync-scanner.vala b/src/baobab-sync-scanner.vala
index c585ab5..f119602 100644
--- a/src/baobab-sync-scanner.vala
+++ b/src/baobab-sync-scanner.vala
@@ -1,3 +1,4 @@
+/* -*- indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Baobab - disk usage analyzer
*
* Copyright (C) 2012 Ryan Lortie <desrt desrt ca>
@@ -20,127 +21,128 @@
*/
namespace Baobab {
- class SyncScanner : Scanner {
- struct Results {
- uint64 size;
- uint64 alloc_size;
- uint64 elements;
- int max_depth;
- }
-
- Results add_directory (File directory, FileInfo info, Gtk.TreeIter? parent_iter = null) {
- var results = Results ();
- Gtk.TreeIter iter;
-
- if (directory in excluded_locations) {
- return results;
- }
-
- var display_name = info.get_display_name ();
- var parse_name = directory.get_parse_name ();
-
- append (out iter, parent_iter);
- set (iter,
- Columns.DISPLAY_NAME, display_name,
- Columns.PARSE_NAME, parse_name);
-
- results.size = info.get_size ();
- if (info.has_attribute (FileAttribute.STANDARD_ALLOCATED_SIZE)) {
- results.alloc_size = info.get_attribute_uint64 (FileAttribute.STANDARD_ALLOCATED_SIZE);
- }
- results.elements = 1;
-
- try {
- var children = directory.enumerate_children (ATTRIBUTES, FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
- FileInfo? child_info;
- while ((child_info = children.next_file (cancellable)) != null) {
- if (cancellable.is_cancelled ()) {
- break;
- }
-
- switch (child_info.get_file_type ()) {
- case FileType.DIRECTORY:
- var child = directory.get_child (child_info.get_name ());
- var child_results = add_directory (child, child_info, iter);
-
- results.size += child_results.size;
- results.alloc_size += child_results.alloc_size;
- results.elements += child_results.elements;
- results.max_depth = int.max (results.max_depth, child_results.max_depth + 1);
- break;
-
- case FileType.REGULAR:
- if (child_info.has_attribute (FileAttribute.UNIX_NLINK)) {
- if (child_info.get_attribute_uint32 (FileAttribute.UNIX_NLINK) > 1) {
- var hl = HardLink (child_info);
-
- /* check if we've already encountered this file */
- if (hl in hardlinks) {
- continue;
- }
-
- hardlinks += hl;
- }
- }
-
- results.size += child_info.get_size ();
- if (child_info.has_attribute (FileAttribute.STANDARD_ALLOCATED_SIZE)) {
- results.alloc_size += child_info.get_attribute_uint64 (FileAttribute.STANDARD_ALLOCATED_SIZE);
- }
- results.elements++;
- break;
-
- default:
- /* ignore other types (symlinks, sockets, devices, etc) */
- break;
- }
- }
- } catch (IOError.PERMISSION_DENIED e) {
- } catch (Error e) {
- warning ("couldn't iterate %s: %s", parse_name, e.message);
- }
-
- add_percent (results.size, iter);
-
- if (!cancellable.is_cancelled ()) {
- set (iter,
- Columns.SIZE, results.size,
- Columns.ALLOC_SIZE, results.alloc_size,
- Columns.ELEMENTS, results.elements,
- Columns.STATE, State.NEED_PERCENT);
- } else {
- set (iter,
- Columns.STATE, State.CANCELLED);
- }
-
- return results;
- }
-
- void add_percent (uint64 parent_size, Gtk.TreeIter? parent = null) {
- Gtk.TreeIter iter;
-
- if (iter_children (out iter, parent)) {
- do {
- uint64 size;
- get (iter, Columns.SIZE, out size);
- set (iter,
- Columns.PERCENT, 100 * ((double) size) / ((double) parent_size),
- Columns.STATE, State.DONE);
- } while (iter_next (ref iter));
- }
- }
-
- public override void scan () {
- try {
- var info = directory.query_info (ATTRIBUTES, 0, cancellable);
- var results = add_directory (directory, info);
- add_percent (results.size);
- max_depth = results.max_depth;
- } catch { }
- }
-
- public SyncScanner (File directory, ScanFlags flags) {
- base (directory, flags);
- }
- }
+
+ class SyncScanner : Scanner {
+ struct Results {
+ uint64 size;
+ uint64 alloc_size;
+ uint64 elements;
+ int max_depth;
+ }
+
+ Results add_directory (File directory, FileInfo info, Gtk.TreeIter? parent_iter = null) {
+ var results = Results ();
+ Gtk.TreeIter iter;
+
+ if (directory in excluded_locations) {
+ return results;
+ }
+
+ var display_name = info.get_display_name ();
+ var parse_name = directory.get_parse_name ();
+
+ append (out iter, parent_iter);
+ set (iter,
+ Columns.DISPLAY_NAME, display_name,
+ Columns.PARSE_NAME, parse_name);
+
+ results.size = info.get_size ();
+ if (info.has_attribute (FileAttribute.STANDARD_ALLOCATED_SIZE)) {
+ results.alloc_size = info.get_attribute_uint64 (FileAttribute.STANDARD_ALLOCATED_SIZE);
+ }
+ results.elements = 1;
+
+ try {
+ var children = directory.enumerate_children (ATTRIBUTES, FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
+ FileInfo? child_info;
+ while ((child_info = children.next_file (cancellable)) != null) {
+ if (cancellable.is_cancelled ()) {
+ break;
+ }
+
+ switch (child_info.get_file_type ()) {
+ case FileType.DIRECTORY:
+ var child = directory.get_child (child_info.get_name ());
+ var child_results = add_directory (child, child_info, iter);
+
+ results.size += child_results.size;
+ results.alloc_size += child_results.alloc_size;
+ results.elements += child_results.elements;
+ results.max_depth = int.max (results.max_depth, child_results.max_depth + 1);
+ break;
+
+ case FileType.REGULAR:
+ if (child_info.has_attribute (FileAttribute.UNIX_NLINK)) {
+ if (child_info.get_attribute_uint32 (FileAttribute.UNIX_NLINK) > 1) {
+ var hl = HardLink (child_info);
+
+ /* check if we've already encountered this file */
+ if (hl in hardlinks) {
+ continue;
+ }
+
+ hardlinks += hl;
+ }
+ }
+
+ results.size += child_info.get_size ();
+ if (child_info.has_attribute (FileAttribute.STANDARD_ALLOCATED_SIZE)) {
+ results.alloc_size += child_info.get_attribute_uint64 (FileAttribute.STANDARD_ALLOCATED_SIZE);
+ }
+ results.elements++;
+ break;
+
+ default:
+ /* ignore other types (symlinks, sockets, devices, etc) */
+ break;
+ }
+ }
+ } catch (IOError.PERMISSION_DENIED e) {
+ } catch (Error e) {
+ warning ("couldn't iterate %s: %s", parse_name, e.message);
+ }
+
+ add_percent (results.size, iter);
+
+ if (!cancellable.is_cancelled ()) {
+ set (iter,
+ Columns.SIZE, results.size,
+ Columns.ALLOC_SIZE, results.alloc_size,
+ Columns.ELEMENTS, results.elements,
+ Columns.STATE, State.NEED_PERCENT);
+ } else {
+ set (iter,
+ Columns.STATE, State.CANCELLED);
+ }
+
+ return results;
+ }
+
+ void add_percent (uint64 parent_size, Gtk.TreeIter? parent = null) {
+ Gtk.TreeIter iter;
+
+ if (iter_children (out iter, parent)) {
+ do {
+ uint64 size;
+ get (iter, Columns.SIZE, out size);
+ set (iter,
+ Columns.PERCENT, 100 * ((double) size) / ((double) parent_size),
+ Columns.STATE, State.DONE);
+ } while (iter_next (ref iter));
+ }
+ }
+
+ public override void scan () {
+ try {
+ var info = directory.query_info (ATTRIBUTES, 0, cancellable);
+ var results = add_directory (directory, info);
+ add_percent (results.size);
+ max_depth = results.max_depth;
+ } catch { }
+ }
+
+ public SyncScanner (File directory, ScanFlags flags) {
+ base (directory, flags);
+ }
+ }
}
diff --git a/src/baobab-threaded-scanner.vala b/src/baobab-threaded-scanner.vala
index e0927cf..42b0572 100644
--- a/src/baobab-threaded-scanner.vala
+++ b/src/baobab-threaded-scanner.vala
@@ -1,3 +1,4 @@
+/* -*- indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Baobab - disk usage analyzer
*
* Copyright (C) 2012 Ryan Lortie <desrt desrt ca>
@@ -20,249 +21,250 @@
*/
namespace Baobab {
- class ThreadedScanner : Scanner {
- AsyncQueue<ResultsArray> results_queue;
- ThreadedScanner? self;
-
- /* General overview:
- *
- * We cannot directly modify the treemodel from the worker thread, so we have to have a way to dispatch
- * the results back to the main thread.
- *
- * Each scanned directory gets a 'Results' struct created for it. If the directory has a parent
- * directory, then the 'parent' pointer is set. The 'display_name' and 'parse_name' fields are filled
- * in as soon as the struct is created. This part is done as soon as the directory is encountered.
- *
- * In order to determine all of the information for a particular directory (and finish filling in the
- * results structure), we must scan it and all of its children. We must also scan all of the siblings
- * of the directory so that we know what percentage of the total size of the parent directory the
- * directory in question is responsible for.
- *
- * After a directory, all of its children and all of its siblings have been scanned, we can do the
- * percentage calculation. We do this from the iteration that takes care of the parent directory: we
- * collect an array of all of the child directory result structs and when we have them all, we assign
- * the proper percentage to each. At this point we can report this array of result structs back to the
- * main thread to be added to the treemodel.
- *
- * Back in the main thread, we receive a Results object. If the results object has not yet had a
- * TreeIter assigned to it, we create it one. We use the parent results object to determine the correct
- * place in the tree (assigning the parent an iter if required, recursively). When we create the iter,
- * we fill in the data that existed from the start (ie: display name and parse name) and mark the status
- * of the iter as 'scanning'.
- *
- * For the iter that was actually directly reported (ie: the one that's ready) we record the information
- * into the treemodel and free the results structure (or Vala does it for us).
- *
- * We can be sure that the 'parent' field always points to valid memory because of the nature of the
- * recursion and the queue. At the time we queue a Results struct for dispatch back to the main thread,
- * its 'parent' is held on the stack by a higher invocation of add_directory(). This invocation will
- * never finish without first pushing its own Results struct onto the queue -- after ours. It is
- * therefore guaranteed that the 'parent' Results object will not be freed before each child.
- */
- [Compact]
- class ResultsArray {
- internal Results[] results;
- }
-
- [Compact]
- class Results {
- // written in the worker thread on creation
- // read from the main thread at any time
- internal unowned Results? parent;
- internal string display_name;
- internal string parse_name;
-
- // written in the worker thread before dispatch
- // read from the main thread only after dispatch
- internal uint64 size;
- internal uint64 alloc_size;
- internal uint64 elements;
- internal double percent;
- internal int max_depth;
- internal Error? error;
-
- // accessed only by the main thread
- internal Gtk.TreeIter iter;
- internal bool iter_is_set;
- }
-
- Results? add_directory (File directory, FileInfo info, Results? parent = null) {
- var results_array = new ResultsArray ();
-
- if (directory in excluded_locations) {
- return null;
- }
-
- var results = new Results ();
- results.display_name = info.get_display_name ();
- results.parse_name = directory.get_parse_name ();
- results.parent = parent;
-
- results.size = info.get_size ();
- if (info.has_attribute (FileAttribute.STANDARD_ALLOCATED_SIZE)) {
- results.alloc_size = info.get_attribute_uint64 (FileAttribute.STANDARD_ALLOCATED_SIZE);
- }
- results.elements = 1;
- results.error = null;
-
- try {
- var children = directory.enumerate_children (ATTRIBUTES, FileQueryInfoFlags.NOFOLLOW_SYMLINKS, cancellable);
- FileInfo? child_info;
- while ((child_info = children.next_file (cancellable)) != null) {
- switch (child_info.get_file_type ()) {
- case FileType.DIRECTORY:
- var child = directory.get_child (child_info.get_name ());
- var child_results = add_directory (child, child_info, results);
-
- if (child_results != null) {
- results.size += child_results.size;
- results.alloc_size += child_results.alloc_size;
- results.elements += child_results.elements;
- results.max_depth = int.max (results.max_depth, child_results.max_depth + 1);
- results_array.results += (owned) child_results;
- }
- break;
-
- case FileType.REGULAR:
- if (child_info.has_attribute (FileAttribute.UNIX_NLINK)) {
- if (child_info.get_attribute_uint32 (FileAttribute.UNIX_NLINK) > 1) {
- var hl = HardLink (child_info);
-
- // check if we've already encountered this file
- if (hl in hardlinks) {
- continue;
- }
-
- hardlinks += hl;
- }
- }
-
- results.size += child_info.get_size ();
- if (child_info.has_attribute (FileAttribute.STANDARD_ALLOCATED_SIZE)) {
- results.alloc_size += child_info.get_attribute_uint64 (FileAttribute.STANDARD_ALLOCATED_SIZE);
- }
- results.elements++;
- break;
-
- default:
- // ignore other types (symlinks, sockets, devices, etc)
- break;
- }
- }
- } catch (Error e) {
- results.error = e;
- }
-
- foreach (unowned Results child_results in results_array.results) {
- child_results.percent = 100 * ((double) child_results.size) / ((double) results.size);
- }
-
- /* No early exit. In order to avoid a potential crash, we absolutely *must* push this onto the
- * queue after having passed it to any recursive invocation of add_directory() above. See the large
- * comment at the top of this class for why.
- */
- results_queue.push ((owned) results_array);
-
- return results;
- }
-
- void* scan_in_thread () {
- try {
- var array = new ResultsArray ();
- var info = directory.query_info (ATTRIBUTES, 0, cancellable);
- var results = add_directory (directory, info);
- results.percent = 100.0;
- array.results += (owned) results;
- results_queue.push ((owned) array);
- } catch {
- }
-
- // drop the thread's reference on the Scanner object
- this.self = null;
- return null;
- }
-
- void ensure_iter_exists (Results results) {
- Gtk.TreeIter? parent_iter;
-
- if (results.iter_is_set) {
- return;
- }
-
- if (results.parent != null) {
- ensure_iter_exists (results.parent);
- parent_iter = results.parent.iter;
- } else {
- parent_iter = null;
- }
-
- append (out results.iter, parent_iter);
- set (results.iter,
- Columns.STATE, State.SCANNING,
- Columns.DISPLAY_NAME, results.display_name,
- Columns.PARSE_NAME, results.parse_name);
- results.iter_is_set = true;
- }
-
- bool process_results () {
- while (true) {
- var results_array = results_queue.try_pop ();
-
- if (results_array == null) {
- break;
- }
-
- foreach (unowned Results results in results_array.results) {
- ensure_iter_exists (results);
-
- set (results.iter,
- Columns.SIZE, results.size,
- Columns.ALLOC_SIZE, results.alloc_size,
- Columns.PERCENT, results.percent,
- Columns.ELEMENTS, results.elements,
- Columns.STATE, results.error == null ? State.DONE : State.ERROR,
- Columns.ERROR, results.error);
-
- if (results.max_depth > max_depth) {
- max_depth = results.max_depth;
- }
-
- // If the user cancelled abort the scan and
- // report CANCELLED as the error, otherwise
- // consider the error not fatal and report the
- // first error we encountered
- if (results.error != null) {
- if (results.error is IOError.CANCELLED) {
- scan_error = results.error;
- completed ();
- return false;
- } else if (scan_error == null) {
- scan_error = results.error;
- }
- }
-
- if (results.parent == null) {
- completed ();
- return false;
- }
- }
- }
-
- return this.self != null;
- }
-
- public override void scan () {
- new GLib2.Thread ("scanner", scan_in_thread);
- Timeout.add (100, process_results);
- }
-
- public ThreadedScanner (File directory, ScanFlags flags) {
- base (directory, flags);
-
- results_queue = new AsyncQueue<ResultsArray> ();
-
- // the thread owns a reference on the Scanner object
- this.self = this;
- }
- }
+
+ class ThreadedScanner : Scanner {
+ AsyncQueue<ResultsArray> results_queue;
+ ThreadedScanner? self;
+
+ /* General overview:
+ *
+ * We cannot directly modify the treemodel from the worker thread, so we have to have a way to dispatch
+ * the results back to the main thread.
+ *
+ * Each scanned directory gets a 'Results' struct created for it. If the directory has a parent
+ * directory, then the 'parent' pointer is set. The 'display_name' and 'parse_name' fields are filled
+ * in as soon as the struct is created. This part is done as soon as the directory is encountered.
+ *
+ * In order to determine all of the information for a particular directory (and finish filling in the
+ * results structure), we must scan it and all of its children. We must also scan all of the siblings
+ * of the directory so that we know what percentage of the total size of the parent directory the
+ * directory in question is responsible for.
+ *
+ * After a directory, all of its children and all of its siblings have been scanned, we can do the
+ * percentage calculation. We do this from the iteration that takes care of the parent directory: we
+ * collect an array of all of the child directory result structs and when we have them all, we assign
+ * the proper percentage to each. At this point we can report this array of result structs back to the
+ * main thread to be added to the treemodel.
+ *
+ * Back in the main thread, we receive a Results object. If the results object has not yet had a
+ * TreeIter assigned to it, we create it one. We use the parent results object to determine the correct
+ * place in the tree (assigning the parent an iter if required, recursively). When we create the iter,
+ * we fill in the data that existed from the start (ie: display name and parse name) and mark the status
+ * of the iter as 'scanning'.
+ *
+ * For the iter that was actually directly reported (ie: the one that's ready) we record the information
+ * into the treemodel and free the results structure (or Vala does it for us).
+ *
+ * We can be sure that the 'parent' field always points to valid memory because of the nature of the
+ * recursion and the queue. At the time we queue a Results struct for dispatch back to the main thread,
+ * its 'parent' is held on the stack by a higher invocation of add_directory(). This invocation will
+ * never finish without first pushing its own Results struct onto the queue -- after ours. It is
+ * therefore guaranteed that the 'parent' Results object will not be freed before each child.
+ */
+ [Compact]
+ class ResultsArray {
+ internal Results[] results;
+ }
+
+ [Compact]
+ class Results {
+ // written in the worker thread on creation
+ // read from the main thread at any time
+ internal unowned Results? parent;
+ internal string display_name;
+ internal string parse_name;
+
+ // written in the worker thread before dispatch
+ // read from the main thread only after dispatch
+ internal uint64 size;
+ internal uint64 alloc_size;
+ internal uint64 elements;
+ internal double percent;
+ internal int max_depth;
+ internal Error? error;
+
+ // accessed only by the main thread
+ internal Gtk.TreeIter iter;
+ internal bool iter_is_set;
+ }
+
+ Results? add_directory (File directory, FileInfo info, Results? parent = null) {
+ var results_array = new ResultsArray ();
+
+ if (directory in excluded_locations) {
+ return null;
+ }
+
+ var results = new Results ();
+ results.display_name = info.get_display_name ();
+ results.parse_name = directory.get_parse_name ();
+ results.parent = parent;
+
+ results.size = info.get_size ();
+ if (info.has_attribute (FileAttribute.STANDARD_ALLOCATED_SIZE)) {
+ results.alloc_size = info.get_attribute_uint64 (FileAttribute.STANDARD_ALLOCATED_SIZE);
+ }
+ results.elements = 1;
+ results.error = null;
+
+ try {
+ var children = directory.enumerate_children (ATTRIBUTES, FileQueryInfoFlags.NOFOLLOW_SYMLINKS, cancellable);
+ FileInfo? child_info;
+ while ((child_info = children.next_file (cancellable)) != null) {
+ switch (child_info.get_file_type ()) {
+ case FileType.DIRECTORY:
+ var child = directory.get_child (child_info.get_name ());
+ var child_results = add_directory (child, child_info, results);
+
+ if (child_results != null) {
+ results.size += child_results.size;
+ results.alloc_size += child_results.alloc_size;
+ results.elements += child_results.elements;
+ results.max_depth = int.max (results.max_depth, child_results.max_depth + 1);
+ results_array.results += (owned) child_results;
+ }
+ break;
+
+ case FileType.REGULAR:
+ if (child_info.has_attribute (FileAttribute.UNIX_NLINK)) {
+ if (child_info.get_attribute_uint32 (FileAttribute.UNIX_NLINK) > 1) {
+ var hl = HardLink (child_info);
+
+ // check if we've already encountered this file
+ if (hl in hardlinks) {
+ continue;
+ }
+
+ hardlinks += hl;
+ }
+ }
+
+ results.size += child_info.get_size ();
+ if (child_info.has_attribute (FileAttribute.STANDARD_ALLOCATED_SIZE)) {
+ results.alloc_size += child_info.get_attribute_uint64 (FileAttribute.STANDARD_ALLOCATED_SIZE);
+ }
+ results.elements++;
+ break;
+
+ default:
+ // ignore other types (symlinks, sockets, devices, etc)
+ break;
+ }
+ }
+ } catch (Error e) {
+ results.error = e;
+ }
+
+ foreach (unowned Results child_results in results_array.results) {
+ child_results.percent = 100 * ((double) child_results.size) / ((double) results.size);
+ }
+
+ /* No early exit. In order to avoid a potential crash, we absolutely *must* push this onto the
+ * queue after having passed it to any recursive invocation of add_directory() above. See the large
+ * comment at the top of this class for why.
+ */
+ results_queue.push ((owned) results_array);
+
+ return results;
+ }
+
+ void* scan_in_thread () {
+ try {
+ var array = new ResultsArray ();
+ var info = directory.query_info (ATTRIBUTES, 0, cancellable);
+ var results = add_directory (directory, info);
+ results.percent = 100.0;
+ array.results += (owned) results;
+ results_queue.push ((owned) array);
+ } catch {
+ }
+
+ // drop the thread's reference on the Scanner object
+ this.self = null;
+ return null;
+ }
+
+ void ensure_iter_exists (Results results) {
+ Gtk.TreeIter? parent_iter;
+
+ if (results.iter_is_set) {
+ return;
+ }
+
+ if (results.parent != null) {
+ ensure_iter_exists (results.parent);
+ parent_iter = results.parent.iter;
+ } else {
+ parent_iter = null;
+ }
+
+ append (out results.iter, parent_iter);
+ set (results.iter,
+ Columns.STATE, State.SCANNING,
+ Columns.DISPLAY_NAME, results.display_name,
+ Columns.PARSE_NAME, results.parse_name);
+ results.iter_is_set = true;
+ }
+
+ bool process_results () {
+ while (true) {
+ var results_array = results_queue.try_pop ();
+
+ if (results_array == null) {
+ break;
+ }
+
+ foreach (unowned Results results in results_array.results) {
+ ensure_iter_exists (results);
+
+ set (results.iter,
+ Columns.SIZE, results.size,
+ Columns.ALLOC_SIZE, results.alloc_size,
+ Columns.PERCENT, results.percent,
+ Columns.ELEMENTS, results.elements,
+ Columns.STATE, results.error == null ? State.DONE : State.ERROR,
+ Columns.ERROR, results.error);
+
+ if (results.max_depth > max_depth) {
+ max_depth = results.max_depth;
+ }
+
+ // If the user cancelled abort the scan and
+ // report CANCELLED as the error, otherwise
+ // consider the error not fatal and report the
+ // first error we encountered
+ if (results.error != null) {
+ if (results.error is IOError.CANCELLED) {
+ scan_error = results.error;
+ completed ();
+ return false;
+ } else if (scan_error == null) {
+ scan_error = results.error;
+ }
+ }
+
+ if (results.parent == null) {
+ completed ();
+ return false;
+ }
+ }
+ }
+
+ return this.self != null;
+ }
+
+ public override void scan () {
+ new GLib2.Thread ("scanner", scan_in_thread);
+ Timeout.add (100, process_results);
+ }
+
+ public ThreadedScanner (File directory, ScanFlags flags) {
+ base (directory, flags);
+
+ results_queue = new AsyncQueue<ResultsArray> ();
+
+ // the thread owns a reference on the Scanner object
+ this.self = this;
+ }
+ }
}
diff --git a/src/baobab-window.vala b/src/baobab-window.vala
index c4e24df..9932fd1 100644
--- a/src/baobab-window.vala
+++ b/src/baobab-window.vala
@@ -1,3 +1,4 @@
+/* -*- indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Baobab - disk usage analyzer
*
* Copyright (C) 2012 Ryan Lortie <desrt desrt ca>
@@ -20,542 +21,542 @@
*/
namespace Baobab {
- public class Window : Gtk.ApplicationWindow {
- Settings ui_settings;
- Gtk.Notebook main_notebook;
- Gtk.Toolbar toolbar;
- Gtk.ToolItem toolbar_home_toolitem;
- Gtk.ToolButton toolbar_show_home_page;
- Gtk.ToolButton toolbar_rescan;
- Gtk.InfoBar infobar;
- Gtk.Label infobar_primary;
- Gtk.Label infobar_secondary;
- Gtk.TreeView treeview;
- Gtk.Notebook chart_notebook;
- Gtk.Grid location_view;
- Chart rings_chart;
- Chart treemap_chart;
- Gtk.Spinner spinner;
- Scanner? scanner;
- LocationMonitor location_monitor;
-
- static Gdk.Cursor busy_cursor;
-
- void radio_activate (SimpleAction action, Variant? parameter) {
- action.change_state (parameter);
- }
-
- private const GLib.ActionEntry[] action_entries = {
- { "show-home-page", on_show_home_page_activate },
- { "active-chart", radio_activate, "s", "'rings'", on_chart_type_changed },
- { "scan-home", on_scan_home_activate },
- { "scan-folder", on_scan_folder_activate },
- { "scan-remote", on_scan_remote_activate },
- { "stop", on_stop_activate },
- { "reload", on_reload_activate },
- { "show-toolbar", on_show_toolbar },
- { "show-allocated", on_show_allocated },
- { "expand-all", on_expand_all },
- { "collapse-all", on_collapse_all },
- { "help", on_help_activate },
- { "about", on_about_activate }
- };
-
- protected struct ActionState {
- string name;
- bool enable;
- }
-
- private const ActionState[] actions_while_scanning = {
- { "scan-home", false },
- { "scan-folder", false },
- { "scan-remote", false },
- { "stop", true },
- { "reload", false },
- { "show-allocated", false },
- { "expand-all", false },
- { "collapse-all", false }
- };
-
- private enum UIPage {
- HOME,
- RESULT
- }
-
- private enum ChartPage {
- RINGS,
- TREEMAP,
- SPINNER
- }
-
- private enum DndTargets {
- URI_LIST
- }
-
- private const Gtk.TargetEntry dnd_target_list[1] = {
- {"text/uri-list", 0, DndTargets.URI_LIST}
- };
-
- public Window (Application app) {
- Object (application: app);
-
- busy_cursor = new Gdk.Cursor (Gdk.CursorType.WATCH);
-
- add_action_entries (action_entries, this);
-
- // Build ourselves.
- var builder = new Gtk.Builder ();
- try {
- builder.add_from_resource ("/org/gnome/baobab/ui/baobab-main-window.ui");
- } catch (Error e) {
- error ("loading main builder file: %s", e.message);
- }
-
-
- // Cache some objects from the builder.
- main_notebook = builder.get_object ("main-notebook") as Gtk.Notebook;
- toolbar = builder.get_object ("toolbar") as Gtk.Toolbar;
- toolbar_home_toolitem = builder.get_object ("home-page-toolitem") as Gtk.ToolItem;
- toolbar_show_home_page = builder.get_object ("show-home-page-button") as Gtk.ToolButton;
- toolbar_rescan = builder.get_object ("rescan-button") as Gtk.ToolButton;
- infobar = builder.get_object ("infobar") as Gtk.InfoBar;
- infobar_primary = builder.get_object ("infobar-primary-label") as Gtk.Label;
- infobar_secondary = builder.get_object ("infobar-secondary-label") as Gtk.Label;
- treeview = builder.get_object ("treeview") as Gtk.TreeView;
- chart_notebook = builder.get_object ("chart-notebook") as Gtk.Notebook;
- rings_chart = builder.get_object ("rings-chart") as Chart;
- treemap_chart = builder.get_object ("treemap-chart") as Chart;
- spinner = builder.get_object ("spinner") as Gtk.Spinner;
- location_view = builder.get_object ("location-view") as Gtk.Grid;
-
- setup_home_page ();
- setup_treeview (builder);
-
- // To make it draggable like a primary toolbar
- toolbar.get_style_context ().add_class (Gtk.STYLE_CLASS_MENUBAR);
-
- ui_settings = Application.get_ui_settings ();
- lookup_action ("active-chart").change_state (ui_settings.get_value ("active-chart"));
-
- rings_chart.item_activated.connect (on_chart_item_activated);
- treemap_chart.item_activated.connect (on_chart_item_activated);
-
- // Setup drag-n-drop
- drag_data_received.connect (on_drag_data_received);
- enable_drop ();
-
- add (builder.get_object ("window-contents") as Gtk.Widget);
- title = _("Disk Usage Analyzer");
- set_default_size (800, 500);
- set_hide_titlebar_when_maximized (true);
-
- set_ui_page (UIPage.HOME);
-
- set_busy (false);
-
- show ();
- }
-
- void set_ui_page (UIPage page) {
- toolbar_home_toolitem.visible = (page == UIPage.HOME);
- toolbar_show_home_page.visible = (page == UIPage.RESULT);
- toolbar_rescan.visible = (page == UIPage.RESULT);
-
- main_notebook.page = page;
- }
-
- void on_show_home_page_activate () {
- if (scanner != null) {
- scanner.cancel ();
- }
-
- set_ui_page (UIPage.HOME);
- }
-
- void on_chart_type_changed (SimpleAction action, Variant value) {
- switch (value as string) {
- case "rings":
- chart_notebook.page = ChartPage.RINGS;
- break;
- case "treemap":
- chart_notebook.page = ChartPage.TREEMAP;
- break;
- default:
- return;
- }
-
- ui_settings.set_value ("active-chart", value);
- action.set_state (value);
- }
-
- void on_scan_home_activate () {
- var dir = File.new_for_path (GLib.Environment.get_home_dir ());
- scan_directory (dir);
- }
-
- void on_scan_folder_activate () {
- var file_chooser = new Gtk.FileChooserDialog (_("Select Folder"), this,
- Gtk.FileChooserAction.SELECT_FOLDER,
- Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL,
- Gtk.Stock.OPEN, Gtk.ResponseType.ACCEPT);
-
- file_chooser.set_modal (true);
-
- file_chooser.response.connect ((response) => {
- if (response == Gtk.ResponseType.ACCEPT) {
- var dir = file_chooser.get_file ();
- scan_directory (dir);
- }
- file_chooser.destroy ();
- });
-
- file_chooser.show ();
- }
-
- void on_scan_remote_activate () {
- var connect_server = new ConnectServer ();
-
- connect_server.selected.connect ((uri) => {
- if (uri != null) {
- var dir = File.new_for_uri (uri);
- scan_directory (dir);
- }
- });
-
- connect_server.show ();
- }
-
- void on_stop_activate () {
- if (scanner != null) {
- scanner.cancel ();
- }
- }
-
- void on_reload_activate () {
- if (scanner != null) {
- scan_directory (scanner.directory, scanner.scan_flags);
- }
- }
-
- void on_show_toolbar () {
- }
-
- void on_show_allocated () {
- }
-
- void on_expand_all () {
- treeview.expand_all ();
- }
-
- void on_collapse_all () {
- treeview.collapse_all ();
- }
-
- void on_help_activate () {
- try {
- Gtk.show_uri (get_screen (), "help:baobab", Gtk.get_current_event_time ());
- } catch (Error e) {
- warning ("Failed to show help: %s", e.message);
- }
- }
-
- void on_about_activate () {
- const string authors[] = {
- "Ryan Lortie <desrt desrt ca>",
- "Fabio Marzocca <thesaltydog gmail com>",
- "Paolo Borelli <pborelli gnome com>",
- "BenoÃt Dejean <benoit placenet org>",
- "Igalia (rings-chart and treemap widget) <www.igalia.com>"
- };
-
- const string copyright = "Copyright \xc2\xa9 2005-2011 Fabio Marzocca, Paolo Borelli, BenoÃt Dejean, Igalia\n" +
- "Copyright \xc2\xa9 2011-2012 Ryan Lortie, Paolo Borelli\n";
-
- Gtk.show_about_dialog (this,
- "program-name", _("Baobab"),
- "logo-icon-name", "baobab",
- "version", Config.VERSION,
- "comments", "A graphical tool to analyze disk usage.",
- "copyright", copyright,
- "license-type", Gtk.License.GPL_2_0,
- "wrap-license", false,
- "authors", authors,
- "translator-credits", _("translator-credits"),
- null);
- }
-
- void on_chart_item_activated (Chart chart, Gtk.TreeIter iter) {
- var path = scanner.get_path (iter);
-
- if (!treeview.is_row_expanded (path)) {
- treeview.expand_to_path (path);
- }
-
- treeview.set_cursor (path, null, false);
- }
-
- void on_drag_data_received (Gtk.Widget widget, Gdk.DragContext context, int x, int y,
- Gtk.SelectionData selection_data, uint target_type, uint time) {
- File dir = null;
-
- if ((selection_data != null) && (selection_data.get_length () >= 0) && (target_type == DndTargets.URI_LIST)) {
- var uris = GLib.Uri.list_extract_uris ((string) selection_data.get_data ());
- if (uris != null && uris.length == 1) {
- dir = File.new_for_uri (uris[0]);
- }
- }
-
- if (dir != null) {
- // finish drop before scanning, since the it can time out
- Gtk.drag_finish (context, true, false, time);
- scan_directory (dir);
- } else {
- Gtk.drag_finish (context, false, false, time);
- }
- }
-
- void enable_drop () {
- Gtk.drag_dest_set (this,
- Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT,
- dnd_target_list,
- Gdk.DragAction.COPY);
- }
-
- void disable_drop () {
- Gtk.drag_dest_unset (this);
- }
-
- void update_locations () {
- location_view.foreach ((widget) => { widget.destroy (); });
-
- foreach (var location in location_monitor.get_locations ()) {
- LocationWidget loc_widget;
- if (location.is_home_location) {
- loc_widget = new LocationWidget (location, (location_) => {
- on_scan_home_activate ();
- });
- } else {
- loc_widget = new LocationWidget (location, (location_) => {
- location_.mount_volume.begin ((location__, res) => {
- try {
- location_.mount_volume.end (res);
- scan_directory (File.new_for_path (location_.mount_point), ScanFlags.EXCLUDE_MOUNTS);
- } catch (Error e) {
- message (_("Could not analyze volume."), e.message, Gtk.MessageType.ERROR);
- }
- });
- });
- }
-
- location_view.add (loc_widget);
- }
-
- location_view.show_all ();
- }
-
- void setup_home_page () {
- location_monitor = LocationMonitor.get ();
- location_monitor.changed.connect (() => { update_locations (); });
- update_locations ();
- }
-
- bool show_treeview_popup (Gtk.Menu popup, Gdk.EventButton? event) {
- if (event != null) {
- popup.popup (null, null, null, event.button, event.time);
- } else {
- popup.popup (null, null, null, 0, Gtk.get_current_event_time ());
- popup.select_first (false);
- }
- return true;
- }
-
- void setup_treeview (Gtk.Builder builder) {
- var popup = builder.get_object ("treeview-popup-menu") as Gtk.Menu;
- var open_item = builder.get_object ("treeview-popup-open") as Gtk.MenuItem;
- var trash_item = builder.get_object ("treeview-popup-trash") as Gtk.MenuItem;
-
- treeview.button_press_event.connect ((event) => {
- if (((Gdk.Event) (&event)).triggers_context_menu ()) {
- return show_treeview_popup (popup, event);
- }
-
- return false;
- });
-
- treeview.popup_menu.connect (() => {
- return show_treeview_popup (popup, null);
- });
-
- open_item.activate.connect (() => {
- var selection = treeview.get_selection ();
- Gtk.TreeIter iter;
- if (selection.get_selected (null, out iter)) {
- string parse_name;
- scanner.get (iter, Scanner.Columns.PARSE_NAME, out parse_name);
- var file = File.parse_name (parse_name);
- try {
- var info = file.query_info (FileAttribute.STANDARD_CONTENT_TYPE, 0, null);
- var content = info.get_content_type ();
- var appinfo = AppInfo.get_default_for_type (content, true);
- var files = new List<File>();
- files.append (file);
- appinfo.launch(files, null);
- } catch (Error e) {
- warning ("Failed open file with application: %s", e.message);
- }
- }
- });
-
- trash_item.activate.connect (() => {
- var selection = treeview.get_selection ();
- Gtk.TreeIter iter;
- if (selection.get_selected (null, out iter)) {
- string parse_name;
- scanner.get (iter, Scanner.Columns.PARSE_NAME, out parse_name);
- var file = File.parse_name (parse_name);
- try {
- file.trash ();
- scanner.remove (iter);
- } catch (Error e) {
- warning ("Failed to move file to the trash: %s", e.message);
- }
- }
- });
-
- var selection = treeview.get_selection ();
- selection.changed.connect (() => {
- Gtk.TreeIter iter;
- if (selection.get_selected (null, out iter)) {
- var path = scanner.get_path (iter);
- rings_chart.set_root (path);
- treemap_chart.set_root (path);
- }
- });
- }
-
- void message (string primary_msg, string secondary_msg, Gtk.MessageType type) {
- infobar.message_type = type;
- infobar_primary.set_label ("<b>%s</b>".printf (_(primary_msg)));
- infobar_secondary.set_label ("<small>%s</small>".printf (_(secondary_msg)));
- infobar.show ();
- }
-
- void clear_message () {
- infobar.hide ();
- }
-
- void set_busy (bool busy) {
- Gdk.Cursor? cursor = null;
-
- if (busy) {
- cursor = busy_cursor;
- disable_drop ();
- rings_chart.freeze_updates ();
- treemap_chart.freeze_updates ();
- (lookup_action ("active-chart") as SimpleAction).set_enabled (false);
- chart_notebook.page = ChartPage.SPINNER;
- spinner.start ();
- toolbar_show_home_page.label = _("Cancel scan");
- } else {
- enable_drop ();
- rings_chart.thaw_updates ();
- treemap_chart.thaw_updates ();
- (lookup_action ("active-chart") as SimpleAction).set_enabled (true);
- spinner.stop ();
- lookup_action ("active-chart").change_state (ui_settings.get_value ("active-chart"));
- toolbar_show_home_page.label = _("All locations");
- }
-
- var window = get_window ();
- if (window != null) {
- window.set_cursor (cursor);
- }
-
- foreach (ActionState action_state in actions_while_scanning) {
- var action = lookup_action (action_state.name) as SimpleAction;
- action.set_enabled (busy == action_state.enable);
- }
- }
-
- public bool check_dir (File directory) {
- //if (Application.is_excluded_location (directory)) {
- // message("", _("Cannot check an excluded folder!"), Gtk.MessageType.INFO);
- // return false;
- //}
-
- try {
- var info = directory.query_info (FileAttribute.STANDARD_TYPE, FileQueryInfoFlags.NONE, null);
- if (info.get_file_type () != FileType.DIRECTORY/* || is_virtual_filesystem ()*/) {
- var primary = _("\"%s\" is not a valid folder").printf (directory.get_parse_name ());
- message (primary, _("Could not analyze disk usage."), Gtk.MessageType.ERROR);
- return false;
- }
- return true;
- } catch (Error e) {
- message ("", e.message, Gtk.MessageType.INFO);
- return false;
- }
- }
-
- void first_row_has_child (Gtk.TreeModel model, Gtk.TreePath path, Gtk.TreeIter iter) {
- model.row_has_child_toggled.disconnect (first_row_has_child);
- treeview.expand_row (path, false);
- }
-
- void set_model (Gtk.TreeModel model) {
- Gtk.TreeIter first;
-
- treeview.model = model;
-
- if (model.iter_children (out first, null) && model.iter_has_child (first)) {
- treeview.expand_row (model.get_path (first), false);
- } else {
- model.row_has_child_toggled.connect (first_row_has_child);
- }
-
- model.bind_property ("max-depth", rings_chart, "max-depth", BindingFlags.SYNC_CREATE);
- model.bind_property ("max-depth", treemap_chart, "max-depth", BindingFlags.SYNC_CREATE);
- treemap_chart.set_model_with_columns (model,
- Scanner.Columns.DISPLAY_NAME,
- Scanner.Columns.ALLOC_SIZE,
- Scanner.Columns.PARSE_NAME,
- Scanner.Columns.PERCENT,
- Scanner.Columns.ELEMENTS, null);
- rings_chart.set_model_with_columns (model,
- Scanner.Columns.DISPLAY_NAME,
- Scanner.Columns.ALLOC_SIZE,
- Scanner.Columns.PARSE_NAME,
- Scanner.Columns.PERCENT,
- Scanner.Columns.ELEMENTS, null);
- }
-
- public void scan_directory (File directory, ScanFlags flags = ScanFlags.NONE) {
- if (!check_dir (directory)) {
- return;
- }
-
- scanner = new ThreadedScanner (directory, flags);
- set_model (scanner);
-
- scanner.completed.connect(() => {
- set_busy (false);
- try {
- scanner.finish();
- } catch (IOError.CANCELLED e) {
- // Handle cancellation silently
- scanner.clear ();
- } catch (Error e) {
- var primary = _("Could not scan folder \"%s\" or some of the folders it contains.").printf (scanner.directory.get_parse_name ());
- message (primary, e.message, Gtk.MessageType.WARNING);
- }
- });
-
- clear_message ();
-
- set_ui_page (UIPage.RESULT);
- set_busy (true);
-
- scanner.scan ();
- }
- }
+
+ public class Window : Gtk.ApplicationWindow {
+ Settings ui_settings;
+ Gtk.Notebook main_notebook;
+ Gtk.Toolbar toolbar;
+ Gtk.ToolItem toolbar_home_toolitem;
+ Gtk.ToolButton toolbar_show_home_page;
+ Gtk.ToolButton toolbar_rescan;
+ Gtk.InfoBar infobar;
+ Gtk.Label infobar_primary;
+ Gtk.Label infobar_secondary;
+ Gtk.TreeView treeview;
+ Gtk.Notebook chart_notebook;
+ Gtk.Grid location_view;
+ Chart rings_chart;
+ Chart treemap_chart;
+ Gtk.Spinner spinner;
+ Scanner? scanner;
+ LocationMonitor location_monitor;
+
+ static Gdk.Cursor busy_cursor;
+
+ void radio_activate (SimpleAction action, Variant? parameter) {
+ action.change_state (parameter);
+ }
+
+ private const GLib.ActionEntry[] action_entries = {
+ { "show-home-page", on_show_home_page_activate },
+ { "active-chart", radio_activate, "s", "'rings'", on_chart_type_changed },
+ { "scan-home", on_scan_home_activate },
+ { "scan-folder", on_scan_folder_activate },
+ { "scan-remote", on_scan_remote_activate },
+ { "stop", on_stop_activate },
+ { "reload", on_reload_activate },
+ { "show-toolbar", on_show_toolbar },
+ { "show-allocated", on_show_allocated },
+ { "expand-all", on_expand_all },
+ { "collapse-all", on_collapse_all },
+ { "help", on_help_activate },
+ { "about", on_about_activate }
+ };
+
+ protected struct ActionState {
+ string name;
+ bool enable;
+ }
+
+ private const ActionState[] actions_while_scanning = {
+ { "scan-home", false },
+ { "scan-folder", false },
+ { "scan-remote", false },
+ { "stop", true },
+ { "reload", false },
+ { "show-allocated", false },
+ { "expand-all", false },
+ { "collapse-all", false }
+ };
+
+ private enum UIPage {
+ HOME,
+ RESULT
+ }
+
+ private enum ChartPage {
+ RINGS,
+ TREEMAP,
+ SPINNER
+ }
+
+ private enum DndTargets {
+ URI_LIST
+ }
+
+ private const Gtk.TargetEntry dnd_target_list[1] = {
+ {"text/uri-list", 0, DndTargets.URI_LIST}
+ };
+
+ public Window (Application app) {
+ Object (application: app);
+
+ busy_cursor = new Gdk.Cursor (Gdk.CursorType.WATCH);
+
+ add_action_entries (action_entries, this);
+
+ // Build ourselves.
+ var builder = new Gtk.Builder ();
+ try {
+ builder.add_from_resource ("/org/gnome/baobab/ui/baobab-main-window.ui");
+ } catch (Error e) {
+ error ("loading main builder file: %s", e.message);
+ }
+
+ // Cache some objects from the builder.
+ main_notebook = builder.get_object ("main-notebook") as Gtk.Notebook;
+ toolbar = builder.get_object ("toolbar") as Gtk.Toolbar;
+ toolbar_home_toolitem = builder.get_object ("home-page-toolitem") as Gtk.ToolItem;
+ toolbar_show_home_page = builder.get_object ("show-home-page-button") as Gtk.ToolButton;
+ toolbar_rescan = builder.get_object ("rescan-button") as Gtk.ToolButton;
+ infobar = builder.get_object ("infobar") as Gtk.InfoBar;
+ infobar_primary = builder.get_object ("infobar-primary-label") as Gtk.Label;
+ infobar_secondary = builder.get_object ("infobar-secondary-label") as Gtk.Label;
+ treeview = builder.get_object ("treeview") as Gtk.TreeView;
+ chart_notebook = builder.get_object ("chart-notebook") as Gtk.Notebook;
+ rings_chart = builder.get_object ("rings-chart") as Chart;
+ treemap_chart = builder.get_object ("treemap-chart") as Chart;
+ spinner = builder.get_object ("spinner") as Gtk.Spinner;
+ location_view = builder.get_object ("location-view") as Gtk.Grid;
+
+ setup_home_page ();
+ setup_treeview (builder);
+
+ // To make it draggable like a primary toolbar
+ toolbar.get_style_context ().add_class (Gtk.STYLE_CLASS_MENUBAR);
+
+ ui_settings = Application.get_ui_settings ();
+ lookup_action ("active-chart").change_state (ui_settings.get_value ("active-chart"));
+
+ rings_chart.item_activated.connect (on_chart_item_activated);
+ treemap_chart.item_activated.connect (on_chart_item_activated);
+
+ // Setup drag-n-drop
+ drag_data_received.connect (on_drag_data_received);
+ enable_drop ();
+
+ add (builder.get_object ("window-contents") as Gtk.Widget);
+ title = _("Disk Usage Analyzer");
+ set_default_size (800, 500);
+ set_hide_titlebar_when_maximized (true);
+
+ set_ui_page (UIPage.HOME);
+
+ set_busy (false);
+
+ show ();
+ }
+
+ void set_ui_page (UIPage page) {
+ toolbar_home_toolitem.visible = (page == UIPage.HOME);
+ toolbar_show_home_page.visible = (page == UIPage.RESULT);
+ toolbar_rescan.visible = (page == UIPage.RESULT);
+
+ main_notebook.page = page;
+ }
+
+ void on_show_home_page_activate () {
+ if (scanner != null) {
+ scanner.cancel ();
+ }
+
+ set_ui_page (UIPage.HOME);
+ }
+
+ void on_chart_type_changed (SimpleAction action, Variant value) {
+ switch (value as string) {
+ case "rings":
+ chart_notebook.page = ChartPage.RINGS;
+ break;
+ case "treemap":
+ chart_notebook.page = ChartPage.TREEMAP;
+ break;
+ default:
+ return;
+ }
+
+ ui_settings.set_value ("active-chart", value);
+ action.set_state (value);
+ }
+
+ void on_scan_home_activate () {
+ var dir = File.new_for_path (GLib.Environment.get_home_dir ());
+ scan_directory (dir);
+ }
+
+ void on_scan_folder_activate () {
+ var file_chooser = new Gtk.FileChooserDialog (_("Select Folder"), this,
+ Gtk.FileChooserAction.SELECT_FOLDER,
+ Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL,
+ Gtk.Stock.OPEN, Gtk.ResponseType.ACCEPT);
+
+ file_chooser.set_modal (true);
+
+ file_chooser.response.connect ((response) => {
+ if (response == Gtk.ResponseType.ACCEPT) {
+ var dir = file_chooser.get_file ();
+ scan_directory (dir);
+ }
+ file_chooser.destroy ();
+ });
+
+ file_chooser.show ();
+ }
+
+ void on_scan_remote_activate () {
+ var connect_server = new ConnectServer ();
+
+ connect_server.selected.connect ((uri) => {
+ if (uri != null) {
+ var dir = File.new_for_uri (uri);
+ scan_directory (dir);
+ }
+ });
+
+ connect_server.show ();
+ }
+
+ void on_stop_activate () {
+ if (scanner != null) {
+ scanner.cancel ();
+ }
+ }
+
+ void on_reload_activate () {
+ if (scanner != null) {
+ scan_directory (scanner.directory, scanner.scan_flags);
+ }
+ }
+
+ void on_show_toolbar () {
+ }
+
+ void on_show_allocated () {
+ }
+
+ void on_expand_all () {
+ treeview.expand_all ();
+ }
+
+ void on_collapse_all () {
+ treeview.collapse_all ();
+ }
+
+ void on_help_activate () {
+ try {
+ Gtk.show_uri (get_screen (), "help:baobab", Gtk.get_current_event_time ());
+ } catch (Error e) {
+ warning ("Failed to show help: %s", e.message);
+ }
+ }
+
+ void on_about_activate () {
+ const string authors[] = {
+ "Ryan Lortie <desrt desrt ca>",
+ "Fabio Marzocca <thesaltydog gmail com>",
+ "Paolo Borelli <pborelli gnome com>",
+ "BenoÃt Dejean <benoit placenet org>",
+ "Igalia (rings-chart and treemap widget) <www.igalia.com>"
+ };
+
+ const string copyright = "Copyright \xc2\xa9 2005-2011 Fabio Marzocca, Paolo Borelli, BenoÃt Dejean, Igalia\n" +
+ "Copyright \xc2\xa9 2011-2012 Ryan Lortie, Paolo Borelli\n";
+
+ Gtk.show_about_dialog (this,
+ "program-name", _("Baobab"),
+ "logo-icon-name", "baobab",
+ "version", Config.VERSION,
+ "comments", "A graphical tool to analyze disk usage.",
+ "copyright", copyright,
+ "license-type", Gtk.License.GPL_2_0,
+ "wrap-license", false,
+ "authors", authors,
+ "translator-credits", _("translator-credits"),
+ null);
+ }
+
+ void on_chart_item_activated (Chart chart, Gtk.TreeIter iter) {
+ var path = scanner.get_path (iter);
+
+ if (!treeview.is_row_expanded (path)) {
+ treeview.expand_to_path (path);
+ }
+
+ treeview.set_cursor (path, null, false);
+ }
+
+ void on_drag_data_received (Gtk.Widget widget, Gdk.DragContext context, int x, int y,
+ Gtk.SelectionData selection_data, uint target_type, uint time) {
+ File dir = null;
+
+ if ((selection_data != null) && (selection_data.get_length () >= 0) && (target_type == DndTargets.URI_LIST)) {
+ var uris = GLib.Uri.list_extract_uris ((string) selection_data.get_data ());
+ if (uris != null && uris.length == 1) {
+ dir = File.new_for_uri (uris[0]);
+ }
+ }
+
+ if (dir != null) {
+ // finish drop before scanning, since the it can time out
+ Gtk.drag_finish (context, true, false, time);
+ scan_directory (dir);
+ } else {
+ Gtk.drag_finish (context, false, false, time);
+ }
+ }
+
+ void enable_drop () {
+ Gtk.drag_dest_set (this,
+ Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT,
+ dnd_target_list,
+ Gdk.DragAction.COPY);
+ }
+
+ void disable_drop () {
+ Gtk.drag_dest_unset (this);
+ }
+
+ void update_locations () {
+ location_view.foreach ((widget) => { widget.destroy (); });
+
+ foreach (var location in location_monitor.get_locations ()) {
+ LocationWidget loc_widget;
+ if (location.is_home_location) {
+ loc_widget = new LocationWidget (location, (location_) => {
+ on_scan_home_activate ();
+ });
+ } else {
+ loc_widget = new LocationWidget (location, (location_) => {
+ location_.mount_volume.begin ((location__, res) => {
+ try {
+ location_.mount_volume.end (res);
+ scan_directory (File.new_for_path (location_.mount_point), ScanFlags.EXCLUDE_MOUNTS);
+ } catch (Error e) {
+ message (_("Could not analyze volume."), e.message, Gtk.MessageType.ERROR);
+ }
+ });
+ });
+ }
+
+ location_view.add (loc_widget);
+ }
+
+ location_view.show_all ();
+ }
+
+ void setup_home_page () {
+ location_monitor = LocationMonitor.get ();
+ location_monitor.changed.connect (() => { update_locations (); });
+ update_locations ();
+ }
+
+ bool show_treeview_popup (Gtk.Menu popup, Gdk.EventButton? event) {
+ if (event != null) {
+ popup.popup (null, null, null, event.button, event.time);
+ } else {
+ popup.popup (null, null, null, 0, Gtk.get_current_event_time ());
+ popup.select_first (false);
+ }
+ return true;
+ }
+
+ void setup_treeview (Gtk.Builder builder) {
+ var popup = builder.get_object ("treeview-popup-menu") as Gtk.Menu;
+ var open_item = builder.get_object ("treeview-popup-open") as Gtk.MenuItem;
+ var trash_item = builder.get_object ("treeview-popup-trash") as Gtk.MenuItem;
+
+ treeview.button_press_event.connect ((event) => {
+ if (((Gdk.Event) (&event)).triggers_context_menu ()) {
+ return show_treeview_popup (popup, event);
+ }
+
+ return false;
+ });
+
+ treeview.popup_menu.connect (() => {
+ return show_treeview_popup (popup, null);
+ });
+
+ open_item.activate.connect (() => {
+ var selection = treeview.get_selection ();
+ Gtk.TreeIter iter;
+ if (selection.get_selected (null, out iter)) {
+ string parse_name;
+ scanner.get (iter, Scanner.Columns.PARSE_NAME, out parse_name);
+ var file = File.parse_name (parse_name);
+ try {
+ var info = file.query_info (FileAttribute.STANDARD_CONTENT_TYPE, 0, null);
+ var content = info.get_content_type ();
+ var appinfo = AppInfo.get_default_for_type (content, true);
+ var files = new List<File>();
+ files.append (file);
+ appinfo.launch(files, null);
+ } catch (Error e) {
+ warning ("Failed open file with application: %s", e.message);
+ }
+ }
+ });
+
+ trash_item.activate.connect (() => {
+ var selection = treeview.get_selection ();
+ Gtk.TreeIter iter;
+ if (selection.get_selected (null, out iter)) {
+ string parse_name;
+ scanner.get (iter, Scanner.Columns.PARSE_NAME, out parse_name);
+ var file = File.parse_name (parse_name);
+ try {
+ file.trash ();
+ scanner.remove (iter);
+ } catch (Error e) {
+ warning ("Failed to move file to the trash: %s", e.message);
+ }
+ }
+ });
+
+ var selection = treeview.get_selection ();
+ selection.changed.connect (() => {
+ Gtk.TreeIter iter;
+ if (selection.get_selected (null, out iter)) {
+ var path = scanner.get_path (iter);
+ rings_chart.set_root (path);
+ treemap_chart.set_root (path);
+ }
+ });
+ }
+
+ void message (string primary_msg, string secondary_msg, Gtk.MessageType type) {
+ infobar.message_type = type;
+ infobar_primary.set_label ("<b>%s</b>".printf (_(primary_msg)));
+ infobar_secondary.set_label ("<small>%s</small>".printf (_(secondary_msg)));
+ infobar.show ();
+ }
+
+ void clear_message () {
+ infobar.hide ();
+ }
+
+ void set_busy (bool busy) {
+ Gdk.Cursor? cursor = null;
+
+ if (busy) {
+ cursor = busy_cursor;
+ disable_drop ();
+ rings_chart.freeze_updates ();
+ treemap_chart.freeze_updates ();
+ (lookup_action ("active-chart") as SimpleAction).set_enabled (false);
+ chart_notebook.page = ChartPage.SPINNER;
+ spinner.start ();
+ toolbar_show_home_page.label = _("Cancel scan");
+ } else {
+ enable_drop ();
+ rings_chart.thaw_updates ();
+ treemap_chart.thaw_updates ();
+ (lookup_action ("active-chart") as SimpleAction).set_enabled (true);
+ spinner.stop ();
+ lookup_action ("active-chart").change_state (ui_settings.get_value ("active-chart"));
+ toolbar_show_home_page.label = _("All locations");
+ }
+
+ var window = get_window ();
+ if (window != null) {
+ window.set_cursor (cursor);
+ }
+
+ foreach (ActionState action_state in actions_while_scanning) {
+ var action = lookup_action (action_state.name) as SimpleAction;
+ action.set_enabled (busy == action_state.enable);
+ }
+ }
+
+ public bool check_dir (File directory) {
+ //if (Application.is_excluded_location (directory)) {
+ // message("", _("Cannot check an excluded folder!"), Gtk.MessageType.INFO);
+ // return false;
+ //}
+
+ try {
+ var info = directory.query_info (FileAttribute.STANDARD_TYPE, FileQueryInfoFlags.NONE, null);
+ if (info.get_file_type () != FileType.DIRECTORY/* || is_virtual_filesystem ()*/) {
+ var primary = _("\"%s\" is not a valid folder").printf (directory.get_parse_name ());
+ message (primary, _("Could not analyze disk usage."), Gtk.MessageType.ERROR);
+ return false;
+ }
+ return true;
+ } catch (Error e) {
+ message ("", e.message, Gtk.MessageType.INFO);
+ return false;
+ }
+ }
+
+ void first_row_has_child (Gtk.TreeModel model, Gtk.TreePath path, Gtk.TreeIter iter) {
+ model.row_has_child_toggled.disconnect (first_row_has_child);
+ treeview.expand_row (path, false);
+ }
+
+ void set_model (Gtk.TreeModel model) {
+ Gtk.TreeIter first;
+
+ treeview.model = model;
+
+ if (model.iter_children (out first, null) && model.iter_has_child (first)) {
+ treeview.expand_row (model.get_path (first), false);
+ } else {
+ model.row_has_child_toggled.connect (first_row_has_child);
+ }
+
+ model.bind_property ("max-depth", rings_chart, "max-depth", BindingFlags.SYNC_CREATE);
+ model.bind_property ("max-depth", treemap_chart, "max-depth", BindingFlags.SYNC_CREATE);
+ treemap_chart.set_model_with_columns (model,
+ Scanner.Columns.DISPLAY_NAME,
+ Scanner.Columns.ALLOC_SIZE,
+ Scanner.Columns.PARSE_NAME,
+ Scanner.Columns.PERCENT,
+ Scanner.Columns.ELEMENTS, null);
+ rings_chart.set_model_with_columns (model,
+ Scanner.Columns.DISPLAY_NAME,
+ Scanner.Columns.ALLOC_SIZE,
+ Scanner.Columns.PARSE_NAME,
+ Scanner.Columns.PERCENT,
+ Scanner.Columns.ELEMENTS, null);
+ }
+
+ public void scan_directory (File directory, ScanFlags flags = ScanFlags.NONE) {
+ if (!check_dir (directory)) {
+ return;
+ }
+
+ scanner = new ThreadedScanner (directory, flags);
+ set_model (scanner);
+
+ scanner.completed.connect(() => {
+ set_busy (false);
+ try {
+ scanner.finish();
+ } catch (IOError.CANCELLED e) {
+ // Handle cancellation silently
+ scanner.clear ();
+ } catch (Error e) {
+ var primary = _("Could not scan folder \"%s\" or some of the folders it contains.").printf (scanner.directory.get_parse_name ());
+ message (primary, e.message, Gtk.MessageType.WARNING);
+ }
+ });
+
+ clear_message ();
+
+ set_ui_page (UIPage.RESULT);
+ set_busy (true);
+
+ scanner.scan ();
+ }
+ }
}
diff --git a/src/main.vala b/src/main.vala
index 070e806..b5081e7 100644
--- a/src/main.vala
+++ b/src/main.vala
@@ -1,3 +1,4 @@
+/* -*- indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Baobab - disk usage analyzer
*
* Copyright (C) 2012 Ryan Lortie <desrt desrt ca>
@@ -18,10 +19,10 @@
*/
int main (string[] args) {
- Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.GNOMELOCALEDIR);
- Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
- Intl.textdomain (Config.GETTEXT_PACKAGE);
+ Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.GNOMELOCALEDIR);
+ Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
+ Intl.textdomain (Config.GETTEXT_PACKAGE);
- var baobab = new Baobab.Application ();
- return baobab.run (args);
+ var baobab = new Baobab.Application ();
+ return baobab.run (args);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]