[gnome-builder/wip/project-selector] project-selector: extract row into GbRecentProjectRow



commit 70e15b8f6a8137a7cf61839b6d5415f3c2eb89a1
Author: Christian Hergert <christian hergert me>
Date:   Tue Apr 7 22:32:31 2015 -0700

    project-selector: extract row into GbRecentProjectRow

 data/ui/gb-recent-project-row.ui          |   78 ++++++++
 src/dialogs/gb-projects-dialog.c          |  304 +++++------------------------
 src/dialogs/gb-recent-project-row.c       |  264 +++++++++++++++++++++++++
 src/dialogs/gb-recent-project-row.h       |   47 +++++
 src/gnome-builder.mk                      |    2 +
 src/resources/gnome-builder.gresource.xml |    1 +
 6 files changed, 445 insertions(+), 251 deletions(-)
---
diff --git a/data/ui/gb-recent-project-row.ui b/data/ui/gb-recent-project-row.ui
new file mode 100644
index 0000000..bfb65f1
--- /dev/null
+++ b/data/ui/gb-recent-project-row.ui
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.15 -->
+  <template class="GbRecentProjectRow" parent="GtkListBoxRow">
+    <child>
+      <object class="GtkBox">
+        <property name="margin">12</property>
+        <property name="orientation">horizontal</property>
+        <property name="visible">true</property>
+        <child>
+          <object class="GtkRevealer" id="revealer">
+            <property name="reveal-child">false</property>
+            <property name="transition-type">slide-right</property>
+            <property name="visible">true</property>
+            <child>
+              <object class="GtkCheckButton" id="check_button">
+                <property name="valign">center</property>
+                <property name="vexpand">false</property>
+                <property name="visible">true</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkImage" id="image">
+            <property name="icon-name">folder</property>
+            <property name="margin-end">12</property>
+            <property name="margin-start">12</property>
+            <property name="pixel-size">64</property>
+            <property name="visible">true</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkBox">
+            <property name="orientation">vertical</property>
+            <property name="valign">center</property>
+            <property name="vexpand">true</property>
+            <property name="visible">true</property>
+            <child>
+              <object class="GtkLabel" id="name_label">
+                <property name="hexpand">true</property>
+                <property name="visible">true</property>
+                <property name="xalign">0.0</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkLabel" id="location_label">
+                <property name="hexpand">true</property>
+                <property name="visible">true</property>
+                <property name="xalign">0.0</property>
+                <style>
+                  <class name="dim-label"/>
+                </style>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkLabel" id="date_label">
+            <property name="margin">12</property>
+            <property name="valign">center</property>
+            <property name="visible">true</property>
+            <property name="xalign">1.0f</property>
+            <style>
+              <class name="dim-label"/>
+            </style>
+          </object>
+        </child>
+        <child>
+          <object class="GtkArrow">
+            <property name="arrow-type">right</property>
+            <property name="visible">true</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/dialogs/gb-projects-dialog.c b/src/dialogs/gb-projects-dialog.c
index 79617db..26ee7ec 100644
--- a/src/dialogs/gb-projects-dialog.c
+++ b/src/dialogs/gb-projects-dialog.c
@@ -30,6 +30,7 @@
 #include "gb-glib.h"
 #include "gb-new-project-dialog.h"
 #include "gb-projects-dialog.h"
+#include "gb-recent-project-row.h"
 #include "gb-scrolled-window.h"
 #include "gb-string.h"
 #include "gb-widget.h"
@@ -41,7 +42,6 @@ struct _GbProjectsDialog
 
   IdeRecentProjects *recent_projects;
   IdePatternSpec    *search_pattern;
-  GList             *selected;
 
   GtkActionBar      *action_bar;
   GtkButton         *cancel_button;
@@ -58,43 +58,16 @@ struct _GbProjectsDialog
 G_DEFINE_TYPE (GbProjectsDialog, gb_projects_dialog, GTK_TYPE_APPLICATION_WINDOW)
 
 static void
-gb_projects_dialog__check_toggled (GbProjectsDialog *self,
-                                  GtkCheckButton  *check_button)
-{
-  GtkWidget *row;
-
-  g_assert (GB_IS_PROJECTS_DIALOG (self));
-  g_assert (GTK_IS_CHECK_BUTTON (check_button));
-
-  for (row = GTK_WIDGET (check_button);
-       (row != NULL) && !GTK_IS_LIST_BOX_ROW (row);
-       row = gtk_widget_get_parent (row))
-    {
-      /* Do Nothing */
-    }
-
-  if (row == NULL)
-    return;
-
-  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_button)))
-    self->selected = g_list_prepend (self->selected, row);
-  else
-    self->selected = g_list_remove (self->selected, row);
-
-  gtk_widget_set_sensitive (GTK_WIDGET (self->delete_button), !!self->selected);
-}
-
-static void
 gb_projects_dialog__listbox_row_activated_cb (GbProjectsDialog *self,
-                                             GtkListBoxRow   *row,
-                                             GtkListBox      *listbox)
+                                              GtkListBoxRow    *row,
+                                              GtkListBox       *listbox)
 {
   IdeProjectInfo *project_info;
   GApplication *app;
   GFile *file;
 
   g_assert (GB_IS_PROJECTS_DIALOG (self));
-  g_assert (GTK_IS_LIST_BOX_ROW (row));
+  g_assert (GB_IS_RECENT_PROJECT_ROW (row));
   g_assert (GTK_IS_LIST_BOX (listbox));
 
   /*
@@ -102,30 +75,15 @@ gb_projects_dialog__listbox_row_activated_cb (GbProjectsDialog *self,
    */
   if (gtk_toggle_button_get_active (self->select_button))
     {
-      GtkToggleButton *check;
-
-      check = g_object_get_data (G_OBJECT (row), "CHECK_BUTTON");
-
-      if (check != NULL)
-        {
-          gboolean active;
-
-          active = gtk_toggle_button_get_active (check);
-          gtk_toggle_button_set_active (check, !active);
-        }
+      gboolean selected;
 
+      selected = gb_recent_project_row_get_selected (GB_RECENT_PROJECT_ROW (row));
+      gb_recent_project_row_set_selected (GB_RECENT_PROJECT_ROW (row), !selected);
       return;
     }
 
-  project_info = g_object_get_data (G_OBJECT (row), "IDE_PROJECT_INFO");
-  g_assert (!project_info || IDE_IS_PROJECT_INFO (project_info));
-
-  if (project_info == NULL)
-    {
-      gtk_container_foreach (GTK_CONTAINER (listbox), (GtkCallback)gtk_widget_show, NULL);
-      gtk_widget_hide (GTK_WIDGET (row));
-      return;
-    }
+  project_info = gb_recent_project_row_get_project_info (GB_RECENT_PROJECT_ROW (row));
+  g_assert (IDE_IS_PROJECT_INFO (project_info));
 
   app = g_application_get_default ();
   file = ide_project_info_get_file (project_info);
@@ -135,142 +93,6 @@ gb_projects_dialog__listbox_row_activated_cb (GbProjectsDialog *self,
   gtk_widget_destroy (GTK_WIDGET (self));
 }
 
-static GtkWidget *
-create_row (GbProjectsDialog *self,
-            IdeProjectInfo  *project_info)
-{
-  g_autofree gchar *relative_path = NULL;
-  g_autofree gchar *date_str = NULL;
-  const gchar *name;
-  GDateTime *last_modified_at;
-  GtkListBoxRow *row;
-  GtkBox *box;
-  GtkBox *vbox;
-  GtkImage *image;
-  GtkArrow *arrow;
-  GtkLabel *label;
-  GtkLabel *label2;
-  GtkCheckButton *check;
-  GtkLabel *date_label;
-  GtkRevealer *revealer;
-  GFile *directory;
-  const gchar *icon_name = "folder";
-  g_autoptr(GFile) home = NULL;
-
-  g_assert (GB_IS_PROJECTS_DIALOG (self));
-  g_assert (IDE_IS_PROJECT_INFO (project_info));
-
-  name = ide_project_info_get_name (project_info);
-  directory = ide_project_info_get_directory (project_info);
-
-  last_modified_at = ide_project_info_get_last_modified_at (project_info);
-  if (last_modified_at != NULL)
-    date_str = gb_date_time_format_for_display (last_modified_at);
-
-  home = g_file_new_for_path (g_get_home_dir ());
-  relative_path = g_file_get_relative_path (home, directory);
-
-  row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
-                      "visible", TRUE,
-                      NULL);
-  g_object_set_data_full (G_OBJECT (row),
-                          "IDE_PROJECT_INFO",
-                          g_object_ref (project_info),
-                          g_object_unref);
-
-  box = g_object_new (GTK_TYPE_BOX,
-                      "margin", 12,
-                      "orientation", GTK_ORIENTATION_HORIZONTAL,
-                      "visible", TRUE,
-                      NULL);
-
-  check = g_object_new (GTK_TYPE_CHECK_BUTTON,
-                        "vexpand", FALSE,
-                        "valign", GTK_ALIGN_CENTER,
-                        "visible", TRUE,
-                        NULL);
-  g_signal_connect_object (check,
-                           "toggled",
-                           G_CALLBACK (gb_projects_dialog__check_toggled),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  if (!g_file_is_native (directory))
-    icon_name = "folder-remote";
-
-  image = g_object_new (GTK_TYPE_IMAGE,
-                        "icon-name", icon_name,
-                        "pixel-size", 64,
-                        "margin-end", 12,
-                        "margin-start", 12,
-                        "visible", TRUE,
-                        NULL);
-
-  vbox = g_object_new (GTK_TYPE_BOX,
-                       "orientation", GTK_ORIENTATION_VERTICAL,
-                       "valign", GTK_ALIGN_CENTER,
-                       "vexpand", TRUE,
-                       "visible", TRUE,
-                       NULL);
-
-  label = g_object_new (GTK_TYPE_LABEL,
-                        "label", name,
-                        "hexpand", TRUE,
-                        "use-markup", TRUE,
-                        "visible", TRUE,
-                        "xalign", 0.0f,
-                        NULL);
-  gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (label)), "title");
-
-  label2 = g_object_new (GTK_TYPE_LABEL,
-                         "label", relative_path,
-                         "hexpand", TRUE,
-                         "use-markup", TRUE,
-                         "visible", TRUE,
-                         "xalign", 0.0f,
-                         NULL);
-  gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (label2)), "dim-label");
-
-  revealer = g_object_new (GTK_TYPE_REVEALER,
-                           "reveal-child", FALSE,
-                           "transition-type", GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT,
-                           "visible", TRUE,
-                           NULL);
-  g_object_bind_property (self->select_button, "active",
-                          revealer, "reveal-child",
-                          G_BINDING_SYNC_CREATE);
-
-  date_label = g_object_new (GTK_TYPE_LABEL,
-                             "label", date_str,
-                             "margin", 12,
-                             "valign", GTK_ALIGN_CENTER,
-                             "visible", TRUE,
-                             "xalign", 1.0f,
-                             NULL);
-  gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (date_label)), "dim-label");
-
-  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-  arrow = g_object_new (GTK_TYPE_ARROW,
-                        "arrow-type", GTK_ARROW_RIGHT,
-                        "visible", TRUE,
-                        NULL);
-  G_GNUC_END_IGNORE_DEPRECATIONS
-
-  gtk_container_add (GTK_CONTAINER (revealer), GTK_WIDGET (check));
-  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (revealer));
-  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (image));
-  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (vbox));
-  gtk_container_add (GTK_CONTAINER (vbox), GTK_WIDGET (label));
-  gtk_container_add (GTK_CONTAINER (vbox), GTK_WIDGET (label2));
-  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (date_label));
-  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (arrow));
-  gtk_container_add (GTK_CONTAINER (row), GTK_WIDGET (box));
-
-  g_object_set_data (G_OBJECT (row), "CHECK_BUTTON", check);
-
-  return GTK_WIDGET (row);
-}
-
 static void
 gb_projects_dialog__recent_projects_added (GbProjectsDialog  *self,
                                            IdeProjectInfo    *project_info,
@@ -282,11 +104,12 @@ gb_projects_dialog__recent_projects_added (GbProjectsDialog  *self,
   g_assert (IDE_IS_PROJECT_INFO (project_info));
   g_assert (IDE_IS_RECENT_PROJECTS (recent_projects));
 
-  row = create_row (self, project_info);
-#if 0
-  if (!is_recent_project (self, project_info))
-    gtk_widget_set_visible (row, FALSE);
-#endif
+  row = g_object_new (GB_TYPE_RECENT_PROJECT_ROW,
+                      "project-info", project_info,
+                      "visible", TRUE,
+                      NULL);
+  g_object_bind_property (self->select_button, "active", row, "selection-mode",
+                          G_BINDING_SYNC_CREATE);
   gtk_container_add (GTK_CONTAINER (self->listbox), row);
 }
 
@@ -311,24 +134,28 @@ gb_projects_dialog__recent_projects_discover_cb (GObject      *object,
 
 static void
 gb_projects_dialog__listbox_header_cb (GtkListBoxRow *row,
-                                      GtkListBoxRow *before,
-                                      gpointer       user_data)
+                                       GtkListBoxRow *before,
+                                       gpointer       user_data)
 {
   g_assert (GTK_IS_LIST_BOX_ROW (row));
   g_assert (!before || GTK_IS_LIST_BOX_ROW (before));
 
   if (before != NULL)
-    gtk_list_box_row_set_header (row,
-                                 g_object_new (GTK_TYPE_SEPARATOR,
-                                               "orientation", GTK_ORIENTATION_HORIZONTAL,
-                                               "visible", TRUE,
-                                               NULL));
+    {
+      GtkWidget *header;
+
+      header =  g_object_new (GTK_TYPE_SEPARATOR,
+                              "orientation", GTK_ORIENTATION_HORIZONTAL,
+                              "visible", TRUE,
+                              NULL);
+      gtk_list_box_row_set_header (row, header);
+    }
 }
 
 static gint
-gb_projects_dialog__listbox_sort (GtkListBoxRow *row1,
-                                 GtkListBoxRow *row2,
-                                 gpointer       user_data)
+gb_projects_dialog__listbox_sort_cb (GtkListBoxRow *row1,
+                                     GtkListBoxRow *row2,
+                                     gpointer       user_data)
 {
   IdeProjectInfo *info1;
   IdeProjectInfo *info2;
@@ -338,20 +165,14 @@ gb_projects_dialog__listbox_sort (GtkListBoxRow *row1,
   GDateTime *dt2;
   gint ret;
 
-  g_assert (GTK_IS_LIST_BOX_ROW (row1));
-  g_assert (GTK_IS_LIST_BOX_ROW (row2));
+  g_assert (GB_IS_RECENT_PROJECT_ROW (row1));
+  g_assert (GB_IS_RECENT_PROJECT_ROW (row2));
 
-  info1 = g_object_get_data (G_OBJECT (row1), "IDE_PROJECT_INFO");
-  info2 = g_object_get_data (G_OBJECT (row2), "IDE_PROJECT_INFO");
+  info1 = gb_recent_project_row_get_project_info (GB_RECENT_PROJECT_ROW (row1));
+  info2 = gb_recent_project_row_get_project_info (GB_RECENT_PROJECT_ROW (row2));
 
-  g_assert (!info1 || IDE_IS_PROJECT_INFO (info1));
-  g_assert (!info2 || IDE_IS_PROJECT_INFO (info2));
-
-  if (!info1)
-    return 1;
-
-  if (!info2)
-    return -1;
+  g_assert (IDE_IS_PROJECT_INFO (info1));
+  g_assert (IDE_IS_PROJECT_INFO (info2));
 
   dt1 = ide_project_info_get_last_modified_at (info1);
   dt2 = ide_project_info_get_last_modified_at (info2);
@@ -373,8 +194,8 @@ gb_projects_dialog__listbox_sort (GtkListBoxRow *row1,
 }
 
 static gboolean
-gb_projects_dialog__listbox_filter (GtkListBoxRow *row,
-                                   gpointer       user_data)
+gb_projects_dialog__listbox_filter_cb (GtkListBoxRow *row,
+                                       gpointer       user_data)
 {
   GbProjectsDialog *self = user_data;
   IdeProjectInfo *info;
@@ -383,9 +204,10 @@ gb_projects_dialog__listbox_filter (GtkListBoxRow *row,
   g_assert (GTK_IS_LIST_BOX_ROW (row));
   g_assert (GB_IS_PROJECTS_DIALOG (self));
 
-  info = g_object_get_data (G_OBJECT (row), "IDE_PROJECT_INFO");
+  info = gb_recent_project_row_get_project_info (GB_RECENT_PROJECT_ROW (row));
+  g_assert (IDE_IS_PROJECT_INFO (info));
 
-  if (info == NULL || self->search_pattern == NULL)
+  if (self->search_pattern == NULL)
     return TRUE;
 
   name = ide_project_info_get_name (info);
@@ -395,8 +217,8 @@ gb_projects_dialog__listbox_filter (GtkListBoxRow *row,
 
 static void
 gb_projects_dialog__select_button_notify_active (GbProjectsDialog *self,
-                                                GParamSpec      *pspec,
-                                                GtkToggleButton *select_button)
+                                                 GParamSpec       *pspec,
+                                                 GtkToggleButton  *select_button)
 {
   GtkStyleContext *style_context;
   gboolean active;
@@ -431,7 +253,7 @@ gb_projects_dialog__select_button_notify_active (GbProjectsDialog *self,
 
 static void
 gb_projects_dialog__cancel_button_clicked (GbProjectsDialog *self,
-                                          GtkButton       *cancel_button)
+                                           GtkButton        *cancel_button)
 {
   GList *rows;
   GList *iter;
@@ -445,23 +267,13 @@ gb_projects_dialog__cancel_button_clicked (GbProjectsDialog *self,
   /* uncheck rows */
   rows = gtk_container_get_children (GTK_CONTAINER (self->listbox));
   for (iter = rows; iter; iter = iter->next)
-    {
-      GtkToggleButton *check;
-
-      check = g_object_get_data (iter->data, "CHECK_BUTTON");
-
-      if (check != NULL)
-        gtk_toggle_button_set_active (check, FALSE);
-    }
+    gb_recent_project_row_set_selected (iter->data, FALSE);
   g_list_free (rows);
-
-  /* clear selection list */
-  g_clear_pointer (&self->selected, (GDestroyNotify)g_list_free);
 }
 
 static void
 gb_projects_dialog__search_entry_activate (GbProjectsDialog *self,
-                                          GtkEntry        *entry)
+                                           GtkEntry         *entry)
 {
   GtkListBoxRow *row;
 
@@ -472,16 +284,13 @@ gb_projects_dialog__search_entry_activate (GbProjectsDialog *self,
    *        the first row taking the sort/filter into account.
    */
   row = gtk_list_box_get_row_at_y (self->listbox, 1);
-
   if (row != NULL)
-    {
-      g_signal_emit_by_name (row, "activate");
-    }
+    g_signal_emit_by_name (row, "activate");
 }
 
 static void
 gb_projects_dialog__search_entry_changed (GbProjectsDialog *self,
-                                         GtkEntry        *entry)
+                                          GtkEntry         *entry)
 {
   const gchar *text;
 
@@ -491,7 +300,6 @@ gb_projects_dialog__search_entry_changed (GbProjectsDialog *self,
   g_clear_pointer (&self->search_pattern, (GDestroyNotify)ide_pattern_spec_unref);
 
   text = gtk_entry_get_text (entry);
-
   if (!gb_str_empty0 (text))
     self->search_pattern = ide_pattern_spec_new (text);
 
@@ -499,9 +307,9 @@ gb_projects_dialog__search_entry_changed (GbProjectsDialog *self,
 }
 
 static void
-gb_projects_dialog__window_open_project (GbProjectsDialog    *self,
-                                        GFile              *project_file,
-                                        GbNewProjectDialog *dialog)
+gb_projects_dialog__window_open_project (GbProjectsDialog   *self,
+                                         GFile              *project_file,
+                                         GbNewProjectDialog *dialog)
 {
   GApplication *app = g_application_get_default ();
 
@@ -544,11 +352,8 @@ static void
 gb_projects_dialog_constructed (GObject *object)
 {
   GbProjectsDialog *self = (GbProjectsDialog *)object;
-  g_autoptr(IdeProjectMiner) miner = NULL;
 
-  miner = g_object_new (IDE_TYPE_AUTOTOOLS_PROJECT_MINER,
-                        "root-directory", NULL,
-                        NULL);
+  G_OBJECT_CLASS (gb_projects_dialog_parent_class)->constructed (object);
 
   g_signal_connect_object (self->recent_projects,
                            "added",
@@ -595,19 +400,17 @@ gb_projects_dialog_constructed (GObject *object)
                                 NULL, NULL);
 
   gtk_list_box_set_sort_func (self->listbox,
-                              gb_projects_dialog__listbox_sort,
+                              gb_projects_dialog__listbox_sort_cb,
                               NULL, NULL);
 
   gtk_list_box_set_filter_func (self->listbox,
-                                gb_projects_dialog__listbox_filter,
+                                gb_projects_dialog__listbox_filter_cb,
                                 self, NULL);
 
   ide_recent_projects_discover_async (self->recent_projects,
                                       NULL, /* TODO: cancellable */
                                       gb_projects_dialog__recent_projects_discover_cb,
                                       g_object_ref (self));
-
-  G_OBJECT_CLASS (gb_projects_dialog_parent_class)->constructed (object);
 }
 
 static gboolean
@@ -659,7 +462,6 @@ gb_projects_dialog_finalize (GObject *object)
   GbProjectsDialog *self = (GbProjectsDialog *)object;
 
   g_clear_object (&self->recent_projects);
-  g_clear_pointer (&self->selected, (GDestroyNotify)g_list_free);
   g_clear_pointer (&self->search_pattern, (GDestroyNotify)ide_pattern_spec_unref);
 
   G_OBJECT_CLASS (gb_projects_dialog_parent_class)->finalize (object);
diff --git a/src/dialogs/gb-recent-project-row.c b/src/dialogs/gb-recent-project-row.c
new file mode 100644
index 0000000..63a6cf3
--- /dev/null
+++ b/src/dialogs/gb-recent-project-row.c
@@ -0,0 +1,264 @@
+/* gb-recent-project-row.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gi18n.h>
+
+#include "gb-glib.h"
+#include "gb-recent-project-row.h"
+#include "gb-widget.h"
+
+struct _GbRecentProjectRow
+{
+  GtkListBoxRow   parent_instance;
+
+  IdeProjectInfo *project_info;
+
+  GtkCheckButton *check_button;
+  GtkImage       *image;
+  GtkLabel       *date_label;
+  GtkLabel       *location_label;
+  GtkLabel       *name_label;
+  GtkRevealer    *revealer;
+};
+
+struct _GbRecentProjectRowClass
+{
+  GtkListBoxRowClass parent_class;
+};
+
+enum
+{
+  PROP_0,
+  PROP_PROJECT_INFO,
+  PROP_SELECTED,
+  PROP_SELECTION_MODE,
+  LAST_PROP
+};
+
+G_DEFINE_TYPE (GbRecentProjectRow, gb_recent_project_row, GTK_TYPE_LIST_BOX_ROW)
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+
+static void
+gb_recent_project_row_set_selection_mode (GbRecentProjectRow *self,
+                                          gboolean            selection_mode)
+{
+  g_return_if_fail (GB_IS_RECENT_PROJECT_ROW (self));
+
+  if (selection_mode != gtk_revealer_get_reveal_child (self->revealer))
+    gtk_revealer_set_reveal_child (self->revealer, selection_mode);
+}
+
+static gboolean
+gb_recent_project_row_get_selection_mode (GbRecentProjectRow *self)
+{
+  g_return_val_if_fail (GB_IS_RECENT_PROJECT_ROW (self), FALSE);
+
+  return gtk_revealer_get_reveal_child (self->revealer);
+}
+
+static void
+gb_recent_project_row_set_project_info (GbRecentProjectRow *self,
+                                        IdeProjectInfo     *project_info)
+{
+  g_assert (GB_IS_RECENT_PROJECT_ROW (self));
+  g_assert (IDE_IS_PROJECT_INFO (project_info));
+
+  if (g_set_object (&self->project_info, project_info))
+    {
+      if (project_info != NULL)
+        {
+          g_autofree gchar *relpath = NULL;
+          g_autofree gchar *datestr = NULL;
+          g_autoptr(GFile) home = NULL;
+          GDateTime *last_modified_at;
+          const gchar *name;
+          GFile *directory;
+
+          name = ide_project_info_get_name (project_info);
+          directory = ide_project_info_get_directory (project_info);
+          last_modified_at = ide_project_info_get_last_modified_at (project_info);
+
+          home = g_file_new_for_path (g_get_home_dir ());
+          relpath = g_file_get_relative_path (home, directory);
+          if (relpath == NULL)
+            relpath = g_file_get_path (directory);
+
+          if (!g_file_is_native (directory))
+            {
+              gtk_image_set_from_icon_name (self->image, "folder-remote", GTK_ICON_SIZE_DIALOG);
+              gtk_image_set_pixel_size (self->image, 64);
+            }
+
+          datestr = gb_date_time_format_for_display (last_modified_at);
+
+          gtk_label_set_label (self->name_label, name);
+          gtk_label_set_label (self->location_label, relpath);
+          gtk_label_set_label (self->date_label, datestr);
+        }
+
+      g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_PROJECT_INFO]);
+    }
+}
+
+static void
+gb_recent_project_row_finalize (GObject *object)
+{
+  GbRecentProjectRow *self = (GbRecentProjectRow *)object;
+
+  g_clear_object (&self->project_info);
+
+  G_OBJECT_CLASS (gb_recent_project_row_parent_class)->finalize (object);
+}
+
+static void
+gb_recent_project_row_get_property (GObject    *object,
+                                    guint       prop_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  GbRecentProjectRow *self = GB_RECENT_PROJECT_ROW (object);
+
+  switch (prop_id)
+    {
+    case PROP_PROJECT_INFO:
+      g_value_set_object (value, gb_recent_project_row_get_project_info (self));
+      break;
+
+    case PROP_SELECTED:
+      g_value_set_boolean (value, gb_recent_project_row_get_selected (self));
+      break;
+
+    case PROP_SELECTION_MODE:
+      g_value_set_boolean (value, gb_recent_project_row_get_selection_mode (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gb_recent_project_row_set_property (GObject      *object,
+                                    guint         prop_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
+{
+  GbRecentProjectRow *self = GB_RECENT_PROJECT_ROW (object);
+
+  switch (prop_id)
+    {
+    case PROP_PROJECT_INFO:
+      gb_recent_project_row_set_project_info (self, g_value_get_object (value));
+      break;
+
+    case PROP_SELECTED:
+      gb_recent_project_row_set_selected (self, g_value_get_boolean (value));
+      break;
+
+    case PROP_SELECTION_MODE:
+      gb_recent_project_row_set_selection_mode (self, g_value_get_boolean (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gb_recent_project_row_class_init (GbRecentProjectRowClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gb_recent_project_row_finalize;
+  object_class->get_property = gb_recent_project_row_get_property;
+  object_class->set_property = gb_recent_project_row_set_property;
+
+  GB_WIDGET_CLASS_TEMPLATE (klass, "gb-recent-project-row.ui");
+  GB_WIDGET_CLASS_BIND (klass, GbRecentProjectRow, check_button);
+  GB_WIDGET_CLASS_BIND (klass, GbRecentProjectRow, date_label);
+  GB_WIDGET_CLASS_BIND (klass, GbRecentProjectRow, image);
+  GB_WIDGET_CLASS_BIND (klass, GbRecentProjectRow, location_label);
+  GB_WIDGET_CLASS_BIND (klass, GbRecentProjectRow, name_label);
+  GB_WIDGET_CLASS_BIND (klass, GbRecentProjectRow, revealer);
+
+  gParamSpecs [PROP_PROJECT_INFO] =
+    g_param_spec_object ("project-info",
+                         _("Project Info"),
+                         _("The project info for the row."),
+                         IDE_TYPE_PROJECT_INFO,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_PROJECT_INFO,
+                                   gParamSpecs [PROP_PROJECT_INFO]);
+
+  gParamSpecs [PROP_SELECTED] =
+    g_param_spec_boolean ("selected",
+                          _("Selected"),
+                          _("Selected"),
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_SELECTED, gParamSpecs [PROP_SELECTED]);
+
+  gParamSpecs [PROP_SELECTION_MODE] =
+    g_param_spec_boolean ("selection-mode",
+                          _("Selection Mode"),
+                          _("Selection Mode"),
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_SELECTION_MODE,
+                                   gParamSpecs [PROP_SELECTION_MODE]);
+}
+
+static void
+gb_recent_project_row_init (GbRecentProjectRow *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+IdeProjectInfo *
+gb_recent_project_row_get_project_info (GbRecentProjectRow *self)
+{
+  g_return_val_if_fail (GB_IS_RECENT_PROJECT_ROW (self), NULL);
+
+  return self->project_info;
+}
+
+GtkWidget *
+gb_recent_project_row_new (IdeProjectInfo *project_info)
+{
+  return g_object_new (IDE_TYPE_PROJECT_INFO,
+                       "project-info", project_info,
+                       NULL);
+}
+
+gboolean
+gb_recent_project_row_get_selected (GbRecentProjectRow *self)
+{
+  g_return_val_if_fail (GB_IS_RECENT_PROJECT_ROW (self), FALSE);
+
+  return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->check_button));
+}
+
+void
+gb_recent_project_row_set_selected (GbRecentProjectRow *self,
+                                    gboolean            selected)
+{
+  g_return_if_fail (GB_IS_RECENT_PROJECT_ROW (self));
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->check_button), selected);
+}
diff --git a/src/dialogs/gb-recent-project-row.h b/src/dialogs/gb-recent-project-row.h
new file mode 100644
index 0000000..9ad84d4
--- /dev/null
+++ b/src/dialogs/gb-recent-project-row.h
@@ -0,0 +1,47 @@
+/* gb-recent-project-row.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GB_RECENT_PROJECT_ROW_H
+#define GB_RECENT_PROJECT_ROW_H
+
+#include <gtk/gtk.h>
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_RECENT_PROJECT_ROW            (gb_recent_project_row_get_type())
+#define GB_RECENT_PROJECT_ROW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GB_TYPE_RECENT_PROJECT_ROW, GbRecentProjectRow))
+#define GB_RECENT_PROJECT_ROW_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GB_TYPE_RECENT_PROJECT_ROW, GbRecentProjectRow const))
+#define GB_RECENT_PROJECT_ROW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  
GB_TYPE_RECENT_PROJECT_ROW, GbRecentProjectRowClass))
+#define GB_IS_RECENT_PROJECT_ROW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GB_TYPE_RECENT_PROJECT_ROW))
+#define GB_IS_RECENT_PROJECT_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  
GB_TYPE_RECENT_PROJECT_ROW))
+#define GB_RECENT_PROJECT_ROW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  
GB_TYPE_RECENT_PROJECT_ROW, GbRecentProjectRowClass))
+
+typedef struct _GbRecentProjectRow      GbRecentProjectRow;
+typedef struct _GbRecentProjectRowClass GbRecentProjectRowClass;
+
+GType           gb_recent_project_row_get_type         (void);
+GtkWidget      *gb_recent_project_row_new              (IdeProjectInfo     *project_info);
+IdeProjectInfo *gb_recent_project_row_get_project_info (GbRecentProjectRow *self);
+gboolean        gb_recent_project_row_get_selected     (GbRecentProjectRow *self);
+void            gb_recent_project_row_set_selected     (GbRecentProjectRow *self,
+                                                        gboolean            selected);
+
+G_END_DECLS
+
+#endif /* GB_RECENT_PROJECT_ROW_H */
diff --git a/src/gnome-builder.mk b/src/gnome-builder.mk
index a0c1d82..395f131 100644
--- a/src/gnome-builder.mk
+++ b/src/gnome-builder.mk
@@ -39,6 +39,8 @@ libgnome_builder_la_SOURCES = \
        src/dialogs/gb-new-project-dialog.h \
        src/dialogs/gb-projects-dialog.c \
        src/dialogs/gb-projects-dialog.h \
+       src/dialogs/gb-recent-project-row.c \
+       src/dialogs/gb-recent-project-row.h \
        src/documents/gb-document.c \
        src/documents/gb-document.h \
        src/editor/gb-editor-document.c \
diff --git a/src/resources/gnome-builder.gresource.xml b/src/resources/gnome-builder.gresource.xml
index d272e76..7a058f9 100644
--- a/src/resources/gnome-builder.gresource.xml
+++ b/src/resources/gnome-builder.gresource.xml
@@ -49,6 +49,7 @@
     <file alias="ui/gb-preferences-page-language.ui">../../data/ui/gb-preferences-page-language.ui</file>
     <file alias="ui/gb-preferences-window.ui">../../data/ui/gb-preferences-window.ui</file>
     <file alias="ui/gb-projects-dialog.ui">../../data/ui/gb-projects-dialog.ui</file>
+    <file alias="ui/gb-recent-project-row.ui">../../data/ui/gb-recent-project-row.ui</file>
     <file alias="ui/gb-search-box.ui">../../data/ui/gb-search-box.ui</file>
     <file alias="ui/gb-search-display-group.ui">../../data/ui/gb-search-display-group.ui</file>
     <file alias="ui/gb-search-display-row.ui">../../data/ui/gb-search-display-row.ui</file>


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