[gtk+/wip/gbsneto/available-space: 1/2] placesview: implement available space



commit 8eb9726805ae3ed6686fe99111fcffe20c6b569f
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Tue Nov 3 00:50:06 2015 -0200

    placesview: implement available space
    
    GtkPlacesView is a widget to display locations
    in the computer, such as root ("/") and volumes,
    separating the persistent devices from removable
    ones.
    
    From the latest mockups[1], GtkPlacesView would
    display the available space of local drives like
    partitions. This, however, is not implemented in
    the current codebase.
    
    Fix that by implementing the measurement of disk
    space, and adding a new property GtkPlacesView::show-disk-usage
    which controls the visibility of measured disks.
    
    [1] 
https://raw.githubusercontent.com/gnome-design-team/gnome-mockups/master/nautilus/nautilus-next/other-locations.png
    
    https://bugzilla.gnome.org/show_bug.cgi?id=759225

 gtk/gtkplacesview.c           |   66 +++++++++++++++++
 gtk/gtkplacesviewprivate.h    |    8 ++
 gtk/gtkplacesviewrow.c        |  159 +++++++++++++++++++++++++++++++++++++++++
 gtk/gtkplacesviewrowprivate.h |    8 ++
 gtk/ui/gtkplacesviewrow.ui    |   19 ++++-
 5 files changed, 257 insertions(+), 3 deletions(-)
---
diff --git a/gtk/gtkplacesview.c b/gtk/gtkplacesview.c
index 011334b..9efb10c 100644
--- a/gtk/gtkplacesview.c
+++ b/gtk/gtkplacesview.c
@@ -73,6 +73,7 @@ struct _GtkPlacesViewPrivate
   GtkWidget                     *network_placeholder_label;
 
   GtkSizeGroup                  *path_size_group;
+  GtkSizeGroup                  *space_size_group;
 
   GtkEntryCompletion            *address_entry_completion;
   GtkListStore                  *completion_store;
@@ -88,6 +89,8 @@ struct _GtkPlacesViewPrivate
   guint                          unmounting_mount : 1;
   guint                          fetching_networks : 1;
   guint                          loading : 1;
+
+  gboolean                       show_disk_usage : 1;
 };
 
 static void        mount_volume                                  (GtkPlacesView *view,
@@ -122,6 +125,7 @@ enum {
   PROP_OPEN_FLAGS,
   PROP_FETCHING_NETWORKS,
   PROP_LOADING,
+  PROP_SHOW_DISK_USAGE,
   LAST_PROP
 };
 
@@ -405,6 +409,7 @@ gtk_places_view_finalize (GObject *object)
   g_clear_object (&priv->cancellable);
   g_clear_object (&priv->networks_fetching_cancellable);
   g_clear_object (&priv->path_size_group);
+  g_clear_object (&priv->space_size_group);
 
   G_OBJECT_CLASS (gtk_places_view_parent_class)->finalize (object);
 }
@@ -431,6 +436,10 @@ gtk_places_view_get_property (GObject    *object,
       g_value_set_boolean (value, gtk_places_view_get_fetching_networks (self));
       break;
 
+    case PROP_SHOW_DISK_USAGE:
+      g_value_set_boolean (value, gtk_places_view_get_show_disk_usage (self));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -450,6 +459,10 @@ gtk_places_view_set_property (GObject      *object,
       gtk_places_view_set_local_only (self, g_value_get_boolean (value));
       break;
 
+    case PROP_SHOW_DISK_USAGE:
+      gtk_places_view_set_show_disk_usage (self, g_value_get_boolean (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -674,6 +687,8 @@ insert_row (GtkPlacesView *view,
                     row);
 
   gtk_places_view_row_set_path_size_group (GTK_PLACES_VIEW_ROW (row), priv->path_size_group);
+  gtk_places_view_row_set_space_size_group (GTK_PLACES_VIEW_ROW (row), priv->space_size_group);
+  gtk_places_view_row_set_show_disk_usage (GTK_PLACES_VIEW_ROW (row), priv->show_disk_usage);
 
   gtk_container_add (GTK_CONTAINER (priv->listbox), row);
 }
@@ -2222,6 +2237,13 @@ gtk_places_view_class_init (GtkPlacesViewClass *klass)
                               GTK_PLACES_OPEN_NORMAL,
                               G_PARAM_READWRITE);
 
+  properties[PROP_SHOW_DISK_USAGE] =
+          g_param_spec_boolean ("show-disk-usage",
+                                P_("Disk usage"),
+                                P_("Whether it should show disk usage"),
+                                FALSE,
+                                G_PARAM_READWRITE);
+
   g_object_class_install_properties (object_class, LAST_PROP, properties);
 
   /* Bind class to template */
@@ -2258,6 +2280,7 @@ gtk_places_view_init (GtkPlacesView *self)
   priv->volume_monitor = g_volume_monitor_get ();
   priv->open_flags = GTK_PLACES_OPEN_NORMAL;
   priv->path_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+  priv->space_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 
   gtk_widget_init_template (GTK_WIDGET (self));
 }
@@ -2529,3 +2552,46 @@ gtk_places_view_set_local_only (GtkPlacesView *view,
       g_object_notify_by_pspec (G_OBJECT (view), properties [PROP_LOCAL_ONLY]);
     }
 }
+
+gboolean
+gtk_places_view_get_show_disk_usage (GtkPlacesView *view)
+{
+  GtkPlacesViewPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_PLACES_VIEW (view), FALSE);
+
+  priv = gtk_places_view_get_instance_private (view);
+
+  return priv->show_disk_usage;
+}
+
+void
+gtk_places_view_set_show_disk_usage (GtkPlacesView *view,
+                                     gboolean       show_disk_usage)
+{
+  GtkPlacesViewPrivate *priv;
+
+  g_return_if_fail (GTK_IS_PLACES_VIEW (view));
+
+  priv = gtk_places_view_get_instance_private (view);
+
+  if (priv->show_disk_usage != !!show_disk_usage)
+    {
+      GList *children;
+      GList *l;
+
+      priv->show_disk_usage = !!show_disk_usage;
+
+      children = gtk_container_get_children (GTK_CONTAINER (priv->listbox));
+
+      for (l = children; l != NULL; l = l->next)
+        {
+          if (GTK_IS_PLACES_VIEW_ROW (l->data))
+            gtk_places_view_row_set_show_disk_usage (l->data, show_disk_usage);
+        }
+
+      g_object_notify_by_pspec (G_OBJECT (view), properties [PROP_SHOW_DISK_USAGE]);
+
+      g_list_free (children);
+    }
+}
diff --git a/gtk/gtkplacesviewprivate.h b/gtk/gtkplacesviewprivate.h
index 526b09f..4eabf45 100644
--- a/gtk/gtkplacesviewprivate.h
+++ b/gtk/gtkplacesviewprivate.h
@@ -77,6 +77,14 @@ gboolean           gtk_places_view_get_local_only                (GtkPlacesView
 void               gtk_places_view_set_local_only                (GtkPlacesView         *view,
                                                                   gboolean               local_only);
 
+GDK_AVAILABLE_IN_3_20
+gboolean           gtk_places_view_get_show_disk_usage           (GtkPlacesView         *view);
+
+GDK_AVAILABLE_IN_3_20
+void               gtk_places_view_set_show_disk_usage           (GtkPlacesView         *view,
+                                                                  gboolean               show_disk_usage);
+
+GDK_AVAILABLE_IN_3_18
 gboolean           gtk_places_view_get_loading                   (GtkPlacesView         *view);
 
 GtkWidget *        gtk_places_view_new                           (void);
diff --git a/gtk/gtkplacesviewrow.c b/gtk/gtkplacesviewrow.c
index f6d5658..1e66dd1 100644
--- a/gtk/gtkplacesviewrow.c
+++ b/gtk/gtkplacesviewrow.c
@@ -42,6 +42,7 @@ struct _GtkPlacesViewRow
 {
   GtkListBoxRow  parent_instance;
 
+  GtkLabel      *available_space_label;
   GtkSpinner    *busy_spinner;
   GtkButton     *eject_button;
   GtkImage      *eject_icon;
@@ -54,6 +55,9 @@ struct _GtkPlacesViewRow
   GMount        *mount;
   GFile         *file;
 
+  GCancellable  *cancellable;
+
+  gboolean       show_disk_usage : 1;
   gint           is_network : 1;
 };
 
@@ -68,19 +72,106 @@ enum {
   PROP_MOUNT,
   PROP_FILE,
   PROP_IS_NETWORK,
+  PROP_SHOW_DISK_USAGE,
   LAST_PROP
 };
 
 static GParamSpec *properties [LAST_PROP];
 
 static void
+measure_available_space_finished (GObject      *object,
+                                  GAsyncResult *res,
+                                  gpointer      user_data)
+{
+  GtkPlacesViewRow *row = user_data;
+  GFileInfo *info;
+  GError *error;
+  guint64 free_space;
+  guint64 total_space;
+  gchar *formatted_free_size;
+  gchar *formatted_total_size;
+  gchar *label;
+
+  error = NULL;
+
+  info = g_file_query_filesystem_info_finish (G_FILE (object),
+                                              res,
+                                              &error);
+
+  if (error)
+    {
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        g_warning ("Failed to measure available space: %s", error->message);
+
+      g_clear_error (&error);
+      goto out;
+    }
+
+  if (!g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE) ||
+      !g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE))
+    {
+      g_object_unref (info);
+      goto out;
+    }
+
+  free_space = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
+  total_space = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE);
+
+  formatted_free_size = g_format_size (free_space);
+  formatted_total_size = g_format_size (total_space);
+  /* Translators: respectively, free and total space of the drive */
+  label = g_strdup_printf (_("%s / %s available"), formatted_free_size, formatted_total_size);
+
+  gtk_label_set_label (row->available_space_label, label);
+
+  g_object_unref (info);
+  g_free (formatted_total_size);
+  g_free (formatted_free_size);
+  g_free (label);
+out:
+  g_object_unref (object);
+}
+
+static void
+measure_available_space (GtkPlacesViewRow *row)
+{
+  gboolean should_measure;
+
+  should_measure = (!row->is_network && (row->volume || row->mount || row->file));
+
+  gtk_label_set_label (row->available_space_label, "");
+  gtk_widget_set_visible (GTK_WIDGET (row->available_space_label), should_measure);
+
+  if (should_measure)
+    {
+      GFile *file;
+
+      file = row->file ? g_object_ref (row->file) : g_mount_get_root (row->mount);
+
+      g_cancellable_cancel (row->cancellable);
+      g_clear_object (&row->cancellable);
+      row->cancellable = g_cancellable_new ();
+
+      g_file_query_filesystem_info_async (file,
+                                          G_FILE_ATTRIBUTE_FILESYSTEM_FREE "," 
G_FILE_ATTRIBUTE_FILESYSTEM_SIZE,
+                                          G_PRIORITY_DEFAULT,
+                                          row->cancellable,
+                                          measure_available_space_finished,
+                                          row);
+    }
+}
+
+static void
 gtk_places_view_row_finalize (GObject *object)
 {
   GtkPlacesViewRow *self = GTK_PLACES_VIEW_ROW (object);
 
+  g_cancellable_cancel (self->cancellable);
+
   g_clear_object (&self->volume);
   g_clear_object (&self->mount);
   g_clear_object (&self->file);
+  g_clear_object (&self->cancellable);
 
   G_OBJECT_CLASS (gtk_places_view_row_parent_class)->finalize (object);
 }
@@ -128,6 +219,10 @@ gtk_places_view_row_get_property (GObject    *object,
       g_value_set_boolean (value, self->is_network);
       break;
 
+    case PROP_SHOW_DISK_USAGE:
+      g_value_set_boolean (value, self->show_disk_usage);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -172,14 +267,30 @@ gtk_places_view_row_set_property (GObject      *object,
        * size but it stays hidden when needed.
        */
       gtk_widget_set_child_visible (GTK_WIDGET (self->eject_button), self->mount != NULL);
+
+      if (self->show_disk_usage)
+        measure_available_space (self);
+
       break;
 
     case PROP_FILE:
       g_set_object (&self->file, g_value_get_object (value));
+
+      if (self->show_disk_usage)
+        measure_available_space (self);
+
       break;
 
     case PROP_IS_NETWORK:
       gtk_places_view_row_set_is_network (self, g_value_get_boolean (value));
+
+      if (self->show_disk_usage)
+        measure_available_space (self);
+
+      break;
+
+    case PROP_SHOW_DISK_USAGE:
+      gtk_places_view_row_set_show_disk_usage (self, g_value_get_boolean (value));
       break;
 
     default:
@@ -246,10 +357,18 @@ gtk_places_view_row_class_init (GtkPlacesViewRowClass *klass)
                                 FALSE,
                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
 
+  properties[PROP_SHOW_DISK_USAGE] =
+          g_param_spec_boolean ("show-disk-usage",
+                                P_("Whether the row show local disks' usage"),
+                                P_("Whether the row show local disks' usage"),
+                                FALSE,
+                                G_PARAM_READWRITE);
+
   g_object_class_install_properties (object_class, LAST_PROP, properties);
 
   gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/ui/gtkplacesviewrow.ui");
 
+  gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, available_space_label);
   gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, busy_spinner);
   gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, eject_button);
   gtk_widget_class_bind_template_child (widget_class, GtkPlacesViewRow, eject_icon);
@@ -340,6 +459,8 @@ gtk_places_view_row_set_is_network (GtkPlacesViewRow *row,
     {
       row->is_network = is_network;
 
+      gtk_widget_set_visible (GTK_WIDGET (row->path_label), !is_network);
+
       gtk_image_set_from_icon_name (row->eject_icon, "media-eject-symbolic", GTK_ICON_SIZE_BUTTON);
       gtk_widget_set_tooltip_text (GTK_WIDGET (row->eject_button), is_network ? _("Disconnect") : 
_("Unmount"));
     }
@@ -352,3 +473,41 @@ gtk_places_view_row_set_path_size_group (GtkPlacesViewRow *row,
   if (group)
     gtk_size_group_add_widget (group, GTK_WIDGET (row->path_label));
 }
+
+void
+gtk_places_view_row_set_space_size_group (GtkPlacesViewRow *row,
+                                          GtkSizeGroup     *group)
+{
+  if (group)
+    gtk_size_group_add_widget (group, GTK_WIDGET (row->available_space_label));
+}
+
+gboolean
+gtk_places_view_row_get_show_disk_usage (GtkPlacesViewRow *row)
+{
+  g_return_val_if_fail (GTK_IS_PLACES_VIEW_ROW (row), FALSE);
+
+  return row->is_network;
+}
+
+void
+gtk_places_view_row_set_show_disk_usage (GtkPlacesViewRow *row,
+                                         gboolean          show_disk_usage)
+{
+  if (row->show_disk_usage != show_disk_usage)
+    {
+      row->show_disk_usage = !!show_disk_usage;
+
+      gtk_widget_set_visible (GTK_WIDGET (row->available_space_label), show_disk_usage);
+
+      if (show_disk_usage)
+        {
+          measure_available_space (row);
+        }
+      else
+        {
+          g_cancellable_cancel (row->cancellable);
+          g_clear_object (&row->cancellable);
+        }
+    }
+}
diff --git a/gtk/gtkplacesviewrowprivate.h b/gtk/gtkplacesviewrowprivate.h
index 5389676..0233188 100644
--- a/gtk/gtkplacesviewrowprivate.h
+++ b/gtk/gtkplacesviewrowprivate.h
@@ -54,9 +54,17 @@ gboolean           gtk_places_view_row_get_is_network            (GtkPlacesViewR
 void               gtk_places_view_row_set_is_network            (GtkPlacesViewRow   *row,
                                                                   gboolean            is_network);
 
+gboolean           gtk_places_view_row_get_show_disk_usage       (GtkPlacesViewRow   *row);
+
+void               gtk_places_view_row_set_show_disk_usage       (GtkPlacesViewRow   *row,
+                                                                  gboolean            show_disk_usage);
+
 void               gtk_places_view_row_set_path_size_group       (GtkPlacesViewRow   *row,
                                                                   GtkSizeGroup       *group);
 
+void               gtk_places_view_row_set_space_size_group      (GtkPlacesViewRow   *row,
+                                                                  GtkSizeGroup       *group);
+
 G_END_DECLS
 
 #endif /* GTK_PLACES_VIEW_ROW_H */
diff --git a/gtk/ui/gtkplacesviewrow.ui b/gtk/ui/gtkplacesviewrow.ui
index 8c888f0..89c8404 100644
--- a/gtk/ui/gtkplacesviewrow.ui
+++ b/gtk/ui/gtkplacesviewrow.ui
@@ -27,12 +27,25 @@
                 <property name="visible">1</property>
                 <property name="hexpand">1</property>
                 <property name="xalign">0</property>
+                <property name="ellipsize">end</property>
               </object>
               <packing>
                 <property name="position">1</property>
               </packing>
             </child>
             <child>
+              <object class="GtkLabel" id="available_space_label">
+                <property name="visible">False</property>
+                <property name="xalign">1</property>
+                <style>
+                  <class name="dim-label" />
+                </style>
+              </object>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
               <object class="GtkLabel" id="path_label">
                 <property name="visible">1</property>
                 <property name="justify">right</property>
@@ -44,7 +57,7 @@
                 </style>
               </object>
               <packing>
-                <property name="position">2</property>
+                <property name="position">3</property>
               </packing>
             </child>
             <child>
@@ -66,7 +79,7 @@
                 </style>
               </object>
               <packing>
-                <property name="position">3</property>
+                <property name="position">4</property>
               </packing>
             </child>
             <child>
@@ -74,7 +87,7 @@
                 <property name="active">1</property>
               </object>
               <packing>
-                <property name="position">4</property>
+                <property name="position">5</property>
               </packing>
             </child>
           </object>


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