[gnome-software] Some design updates for app folders



commit 3a32ae8da9400604526f002cd649d266a73356f9
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Jan 21 23:40:19 2014 -0500

    Some design updates for app folders
    
    Apply changes to the action bar and to the app folder
    dialog according to
    
    https://bugzilla.gnome.org/show_bug.cgi?id=722612

 src/app-folder-dialog.ui   |   57 +++++++------
 src/gnome-software.ui      |   38 ++++++++-
 src/gs-app-folder-dialog.c |  193 ++++++++++++++++++--------------------------
 src/gs-app-folder-dialog.h |    4 +-
 src/gs-app-widget.c        |   64 ++++++++++++++-
 src/gs-shell-installed.c   |   88 +++++++++++++++++++-
 6 files changed, 289 insertions(+), 155 deletions(-)
---
diff --git a/src/app-folder-dialog.ui b/src/app-folder-dialog.ui
index 083e848..e8878b8 100644
--- a/src/app-folder-dialog.ui
+++ b/src/app-folder-dialog.ui
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <!-- interface-requires gtk+ 3.10 -->
-  <template class="GsAppFolderDialog" parent="GtkWindow">
+  <template class="GsAppFolderDialog" parent="GtkDialog">
     <property name="title" translatable="yes">Add to Application Folder</property>
     <property name="default-height">500</property>
     <property name="type-hint">dialog</property>
@@ -33,12 +33,10 @@
         <child>
           <object class="GtkButton" id="done_button">
             <property name="visible">True</property>
+            <property name="sensitive">False</property>
             <property name="use_underline">True</property>
-            <property name="label" translatable="yes">_Done</property>
+            <property name="label" translatable="yes">_Add</property>
             <property name="receives_default">True</property>
-            <style>
-              <class name="suggested-action"/>
-            </style>
           </object>
           <packing>
             <property name="pack_type">end</property>
@@ -46,34 +44,41 @@
         </child>
       </object>
     </child>
-    <child>
-      <object class="GtkScrolledWindow" id="scrolledwindow">
-        <property name="visible">True</property>
-        <property name="margin-top">15</property>
-        <property name="margin-bottom">15</property>
-        <property name="margin-left">12</property>
-        <property name="margin-right">12</property>
-        <property name="hscrollbar_policy">never</property>
-        <property name="vscrollbar_policy">automatic</property>
-        <property name="shadow_type">none</property>
-        <property name="valign">fill</property>
+    <child internal-child="vbox">
+      <object class="GtkBox">
         <child>
-          <object class="GtkFrame" id="frame">
+          <object class="GtkScrolledWindow" id="scrolledwindow">
             <property name="visible">True</property>
-            <property name="shadow_type">in</property>
-            <property name="halign">fill</property>
-            <property name="valign">start</property>
-            <style>
-              <class name="view"/>
-            </style>
+            <property name="margin-top">15</property>
+            <property name="margin-bottom">15</property>
+            <property name="margin-left">12</property>
+            <property name="margin-right">12</property>
+            <property name="hscrollbar_policy">never</property>
+            <property name="vscrollbar_policy">automatic</property>
+            <property name="shadow_type">none</property>
+            <property name="valign">fill</property>
             <child>
-              <object class="GtkListBox" id="app_folder_list">
+              <object class="GtkFrame" id="frame">
                 <property name="visible">True</property>
-                <property name="activate-on-single-click">True</property>
-                <property name="selection-mode">none</property>
+                <property name="shadow_type">in</property>
+                <property name="halign">fill</property>
+                <property name="valign">start</property>
+                <style>
+                  <class name="view"/>
+                </style>
+                <child>
+                  <object class="GtkListBox" id="app_folder_list">
+                    <property name="visible">True</property>
+                    <property name="activate-on-single-click">True</property>
+                    <property name="selection-mode">none</property>
+                  </object>
+                </child>
               </object>
             </child>
           </object>
+          <packing>
+            <property name="expand">True</property>
+          </packing>
         </child>
       </object>
     </child>
diff --git a/src/gnome-software.ui b/src/gnome-software.ui
index 8d41815..b6f3c45 100644
--- a/src/gnome-software.ui
+++ b/src/gnome-software.ui
@@ -665,12 +665,30 @@
                           <object class="GtkActionBar" id="action_bar">
                             <property name="visible">True</property>
                             <child>
-                              <object class="GtkButton" id="button_folder_install">
-                                <property name="visible">True</property>
-                                <property name="label" translatable="yes">Application _Folders</property>
+                              <object class="GtkButton" id="button_folder_add">
+                                <property name="label" translatable="yes">_Add to Folder…</property>
                                 <property name="use_underline">True</property>
-                                <property name="hexpand">True</property>
-                                <property name="halign">center</property>
+                                <property name="margin">6</property>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkButton" id="button_folder_move">
+                                <property name="label" translatable="yes">_Move to Folder…</property>
+                                <property name="use_underline">True</property>
+                                <property name="margin">6</property>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkButton" id="button_folder_remove">
+                                <property name="label" translatable="yes">_Remove from Folder</property>
+                                <property name="use_underline">True</property>
+                                <property name="margin">6</property>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="button_folder_fake">
+                                <property name="visible">True</property>
+                                <property name="label"></property>
                                 <property name="margin">6</property>
                               </object>
                             </child>
@@ -1798,4 +1816,14 @@
       <widget name="button_details_launch"/>
     </widgets>
   </object>
+  <object class="GtkSizeGroup" id="sizegroup_folder_buttons">
+    <property name="ignore-hidden">False</property>
+    <property name="mode">vertical</property>
+    <widgets>
+      <widget name="button_folder_add"/>
+      <widget name="button_folder_move"/>
+      <widget name="button_folder_remove"/>
+      <widget name="button_folder_fake"/>
+    </widgets>
+  </object>
 </interface>
diff --git a/src/gs-app-folder-dialog.c b/src/gs-app-folder-dialog.c
index 3f4bf09..2e051b7 100644
--- a/src/gs-app-folder-dialog.c
+++ b/src/gs-app-folder-dialog.c
@@ -36,12 +36,13 @@ struct _GsAppFolderDialogPrivate
        GtkWidget        *cancel_button;
        GtkWidget        *done_button;
        GtkWidget        *app_folder_list;
-       GtkWidget        *none_selected;
        GtkSizeGroup     *rows;
+       GtkSizeGroup     *labels;
        GtkListBoxRow    *new_folder_button;
+       GtkListBoxRow    *selected_row;
 };
 
-G_DEFINE_TYPE_WITH_PRIVATE (GsAppFolderDialog, gs_app_folder_dialog, GTK_TYPE_WINDOW)
+G_DEFINE_TYPE_WITH_PRIVATE (GsAppFolderDialog, gs_app_folder_dialog, GTK_TYPE_DIALOG)
 
 #define PRIVATE(o) (gs_app_folder_dialog_get_instance_private (o))
 
@@ -56,6 +57,7 @@ gs_app_folder_dialog_destroy (GtkWidget *widget)
 
        g_clear_object (&priv->folders);
        g_clear_object (&priv->rows);
+       g_clear_object (&priv->labels);
 
        GTK_WIDGET_CLASS (gs_app_folder_dialog_parent_class)->destroy (widget);
 }
@@ -70,26 +72,13 @@ static void
 apply_changes (GsAppFolderDialog *dialog)
 {
        GsAppFolderDialogPrivate *priv = PRIVATE (dialog);
-       GtkListBoxRow *row;
        const gchar *folder;
-       GList *children, *l;
+       GList *l;
        
-       children = gtk_container_get_children (GTK_CONTAINER (priv->app_folder_list));
-       row = NULL;
-       for (l = children; l; l = l->next) {
-               GtkWidget *child;
-               child = gtk_bin_get_child (GTK_BIN (l->data));
-               if (GTK_IS_TOGGLE_BUTTON (child) &&
-                   gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (child))) {
-                       row = l->data;
-                       break;
-               }
-       }
-
-       if (row == NULL)
-               folder = NULL;
+       if (priv->selected_row)
+               folder = (const gchar *)g_object_get_data (G_OBJECT (priv->selected_row), "folder");
        else
-               folder = (const gchar *)g_object_get_data (G_OBJECT (row), "folder");
+               folder = NULL;
 
        for (l = priv->apps; l; l = l->next) {
                GsApp *app = l->data;
@@ -109,96 +98,45 @@ done_cb (GsAppFolderDialog *dialog)
        gtk_window_close (GTK_WINDOW (dialog));
 }
 
-static void
-delete_row (GtkWidget *child, GsAppFolderDialog *dialog)
-{
-       GsAppFolderDialogPrivate *priv = PRIVATE (dialog);
-       GtkWidget *row;
-       const gchar *folder;
-
-       row = gtk_widget_get_ancestor (child, GTK_TYPE_LIST_BOX_ROW);
-
-       folder = (const gchar *)g_object_get_data (G_OBJECT (row), "folder");
-       gs_folders_remove_folder (priv->folders, folder);
-
-       gtk_container_remove (GTK_CONTAINER (priv->app_folder_list), row);
-
-       gtk_widget_show (GTK_WIDGET (priv->new_folder_button));
-}
-
-static void
-done_editing (GtkEntry *entry, GsAppFolderDialog *dialog)
-{
-       GsAppFolderDialogPrivate *priv = PRIVATE (dialog);
-       GtkWidget *row;
-       gchar *folder;
-       const gchar *id;
-       GtkWidget *label;
-       GtkWidget *parent;
-
-       row = gtk_widget_get_ancestor (GTK_WIDGET (entry), GTK_TYPE_LIST_BOX_ROW);
-       if (gtk_entry_get_text_length (entry) == 0) {
-               delete_row (GTK_WIDGET (entry), dialog);
-               return;
-       }
-       folder = g_strdup (gtk_entry_get_text (entry));
-       parent = gtk_widget_get_parent (GTK_WIDGET (entry));
-       gtk_container_remove (GTK_CONTAINER (parent), GTK_WIDGET (entry));
-
-       label = gtk_label_new (folder);
-       gtk_widget_show (label);
-       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-       gtk_container_add (GTK_CONTAINER (parent), label);
-       g_object_set (parent, "margin", 10, NULL);
-
-       id = gs_folders_add_folder (priv->folders, folder);
-       g_object_set_data (G_OBJECT (row), "folder", (gpointer)id);
-       g_free (folder);
-
-       gtk_widget_show (GTK_WIDGET (priv->new_folder_button));
-}
-
-static gboolean
-entry_key_press (GtkWidget *entry, GdkEventKey *event, GsAppFolderDialog *dialog)
-{
-       if (event->keyval == GDK_KEY_Escape) {
-               delete_row (GTK_WIDGET (entry), dialog);
-               return TRUE;
-       }
-
-       return FALSE;
-}
+static GtkWidget *create_row (GsAppFolderDialog *dialog, const gchar *folder);
 
 static void
 new_folder_cb (GsAppFolderDialog *dialog)
 {
        GsAppFolderDialogPrivate *priv = PRIVATE (dialog);
-       GtkWidget *row, *button, *entry;
+       GtkWidget *entry;
+       GtkWidget *subdialog;
+       const gchar *folder;
 
-        button = gtk_radio_button_new (gtk_radio_button_get_group (GTK_RADIO_BUTTON (priv->none_selected)));
-       gtk_widget_set_margin_start (button, 10);
-       gtk_widget_set_margin_end (button, 10);
-       gtk_widget_set_halign (button, GTK_ALIGN_FILL);
-       gtk_widget_set_valign (button, GTK_ALIGN_FILL);
+       subdialog = gtk_dialog_new_with_buttons (_("Folder Name"),
+                                                GTK_WINDOW (dialog),
+                                                GTK_DIALOG_MODAL |
+                                                 GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                _("_Cancel"), GTK_RESPONSE_CANCEL,
+                                                 _("_Add"), GTK_RESPONSE_OK,
+                                                 NULL);
+       gtk_dialog_set_default_response (GTK_DIALOG (subdialog), GTK_RESPONSE_OK);
 
        entry = gtk_entry_new ();
-       gtk_container_add (GTK_CONTAINER (button), entry);
-
-       row = gtk_list_box_row_new ();
-       gtk_container_add (GTK_CONTAINER (row), button);
-
-       g_signal_connect (entry, "key-press-event",
-                         G_CALLBACK (entry_key_press), dialog);
-       g_signal_connect (entry, "activate",
-                         G_CALLBACK (done_editing), dialog);
-
-       gtk_widget_show_all (row);
-       gtk_list_box_insert (GTK_LIST_BOX (priv->app_folder_list), row, gtk_list_box_row_get_index 
(priv->new_folder_button));
-       gtk_size_group_add_widget (priv->rows, row);
-
-       gtk_widget_hide (GTK_WIDGET (priv->new_folder_button));
+       gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
+        g_object_set (entry, "margin", 10, NULL);
+       gtk_widget_set_halign (entry, GTK_ALIGN_FILL);
+       gtk_widget_set_valign (entry, GTK_ALIGN_CENTER);
+       gtk_widget_show (entry);
+
+       gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (subdialog))), entry);
+
+       if (gtk_dialog_run (GTK_DIALOG (subdialog)) == GTK_RESPONSE_OK) {
+               folder = gtk_entry_get_text (GTK_ENTRY (entry));
+               if (folder[0] != '\0') {
+                       gs_folders_add_folder (priv->folders, folder);
+                       gtk_list_box_insert (GTK_LIST_BOX (priv->app_folder_list), 
+                                            create_row (dialog, folder),
+                                            gtk_list_box_row_get_index (priv->new_folder_button));
+               }
+       }
 
-       gtk_widget_grab_focus (entry);
+       gtk_widget_destroy (subdialog);
 }
 
 static void
@@ -232,8 +170,8 @@ gs_app_folder_dialog_init (GsAppFolderDialog *dialog)
                                  G_CALLBACK (cancel_cb), dialog);
        g_signal_connect_swapped (priv->done_button, "clicked",
                                  G_CALLBACK (done_cb), dialog);
-       priv->none_selected = gtk_radio_button_new (NULL);
        priv->rows = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
+       priv->labels = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 
        gtk_list_box_set_header_func (GTK_LIST_BOX (priv->app_folder_list),
                                      update_header_func, NULL, NULL);
@@ -259,21 +197,34 @@ create_row (GsAppFolderDialog *dialog, const gchar *folder)
 {
        GsAppFolderDialogPrivate *priv = PRIVATE (dialog);
        GtkWidget *row;
-       GtkWidget *button;
-
-        button = gtk_radio_button_new_with_label (gtk_radio_button_get_group (GTK_RADIO_BUTTON 
(priv->none_selected)), gs_folders_get_folder_name (priv->folders, folder));
-
-       g_object_set (button, "margin", 10, NULL);
-       gtk_widget_set_halign (button, GTK_ALIGN_FILL);
-       gtk_widget_set_valign (button, GTK_ALIGN_FILL);
+       GtkWidget *box;
+       GtkWidget *label;
+       GtkWidget *image;
+
+       box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+       label = gtk_label_new (gs_folders_get_folder_name (priv->folders, folder));
+       g_object_set (label,
+                      "margin-start", 20,
+                      "margin-end", 20,
+                      "margin-top", 10,
+                      "margin-bottom", 10,
+                      NULL);
+       gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
+       gtk_widget_set_valign (label, GTK_ALIGN_START);
+       gtk_container_add (GTK_CONTAINER (box), label);
+       image = gtk_image_new_from_icon_name ("object-select-symbolic", GTK_ICON_SIZE_MENU);
+       gtk_widget_set_no_show_all (image, TRUE);
+       gtk_container_add (GTK_CONTAINER (box), image);
 
        row = gtk_list_box_row_new ();
-       gtk_container_add (GTK_CONTAINER (row), button);
+       gtk_container_add (GTK_CONTAINER (row), box);
 
        gtk_widget_show_all (row);
 
+       g_object_set_data (G_OBJECT (row), "image", image);
        g_object_set_data_full (G_OBJECT (row), "folder", g_strdup (folder), g_free);
 
+       gtk_size_group_add_widget (priv->labels, label);
        gtk_size_group_add_widget (priv->rows, row);
 
        return row;     
@@ -306,13 +257,25 @@ static void
 row_activated (GtkListBox *list_box, GtkListBoxRow *row, GsAppFolderDialog *dialog)
 {
        GsAppFolderDialogPrivate *priv = PRIVATE (dialog);
+       GtkWidget *image;
 
-       if (row == priv->new_folder_button)
+       if (row == priv->new_folder_button) {
                new_folder_cb (dialog);
-       else {
-               GtkWidget *child;
-               child = gtk_bin_get_child (GTK_BIN (row));
-               gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (child), TRUE);
+               return;
+       }
+
+       if (priv->selected_row) {
+               image = g_object_get_data (G_OBJECT (priv->selected_row), "image");
+               gtk_widget_hide (image);
+               gtk_widget_set_sensitive (priv->done_button, FALSE);
+       }
+
+       priv->selected_row = row;
+
+       if (priv->selected_row) {
+               image = g_object_get_data (G_OBJECT (priv->selected_row), "image");
+               gtk_widget_show (image);
+               gtk_widget_set_sensitive (priv->done_button, TRUE);
        }
 }
 
@@ -343,7 +306,9 @@ gs_app_folder_dialog_new (GtkWindow *parent, GList *apps)
        GsAppFolderDialog *dialog;
 
        dialog = g_object_new (GS_TYPE_APP_FOLDER_DIALOG,
+                              "use-header-bar", TRUE,
                               "transient-for", parent,
+                              "modal", TRUE,
                               NULL);
         set_apps (dialog, apps);
        populate_list (dialog);
diff --git a/src/gs-app-folder-dialog.h b/src/gs-app-folder-dialog.h
index 4f6dcae..35bf515 100644
--- a/src/gs-app-folder-dialog.h
+++ b/src/gs-app-folder-dialog.h
@@ -40,12 +40,12 @@ typedef struct _GsAppFolderDialogClass              GsAppFolderDialogClass;
 
 struct _GsAppFolderDialog
 {
-        GtkWindow      parent;
+        GtkDialog      parent;
 };
 
 struct _GsAppFolderDialogClass
 {
-        GtkWindowClass      parent_class;
+        GtkDialogClass      parent_class;
 };
 
 GType           gs_app_folder_dialog_get_type  (void);
diff --git a/src/gs-app-widget.c b/src/gs-app-widget.c
index 8a5dcd9..13d5e03 100644
--- a/src/gs-app-widget.c
+++ b/src/gs-app-widget.c
@@ -54,6 +54,11 @@ struct _GsAppWidgetPrivate
 G_DEFINE_TYPE_WITH_PRIVATE (GsAppWidget, gs_app_widget, GTK_TYPE_BIN)
 
 enum {
+       PROP_ZERO,
+       PROP_SELECTED
+};
+
+enum {
        SIGNAL_BUTTON_CLICKED,
        SIGNAL_LAST
 };
@@ -302,13 +307,51 @@ gs_app_widget_destroy (GtkWidget *object)
 }
 
 static void
+gs_app_widget_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+       GsAppWidget *app_widget = GS_APP_WIDGET (object);
+
+        switch (prop_id) {
+        case PROP_SELECTED:
+               gs_app_widget_set_selected (app_widget, g_value_get_boolean (value));
+               break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+       }
+}
+
+static void
+gs_app_widget_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+       GsAppWidget *app_widget = GS_APP_WIDGET (object);
+
+        switch (prop_id) {
+        case PROP_SELECTED:
+               g_value_set_boolean (value, gs_app_widget_get_selected (app_widget));
+               break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                       break;
+       }
+}
+
+static void
 gs_app_widget_class_init (GsAppWidgetClass *klass)
 {
+       GParamSpec *pspec;
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
+       object_class->set_property = gs_app_widget_set_property;
+       object_class->get_property = gs_app_widget_get_property;
+
        widget_class->destroy = gs_app_widget_destroy;
 
+       pspec = g_param_spec_boolean ("selected", NULL, NULL,
+                                     FALSE, G_PARAM_READWRITE);
+       g_object_class_install_property (object_class, PROP_SELECTED, pspec);
+
        signals [SIGNAL_BUTTON_CLICKED] =
                g_signal_new ("button-clicked",
                              G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
@@ -339,6 +382,12 @@ button_clicked (GtkWidget *widget, GsAppWidget *app_widget)
 }
 
 static void
+checkbox_toggled (GtkWidget *widget, GsAppWidget *app_widget)
+{
+       g_object_notify (G_OBJECT (app_widget), "selected");
+}
+
+static void
 gs_app_widget_init (GsAppWidget *app_widget)
 {
        GsAppWidgetPrivate *priv;
@@ -353,6 +402,8 @@ gs_app_widget_init (GsAppWidget *app_widget)
 
        g_signal_connect (priv->button, "clicked",
                          G_CALLBACK (button_clicked), app_widget);
+       g_signal_connect (priv->checkbox, "toggled",
+                         G_CALLBACK (checkbox_toggled), app_widget);
 }
 
 void
@@ -393,17 +444,22 @@ gs_app_widget_set_selectable (GsAppWidget *app_widget, gboolean selectable)
 void
 gs_app_widget_set_selected (GsAppWidget *app_widget, gboolean selected)
 {
-       if (app_widget->priv->selectable)
+       if (!app_widget->priv->selectable)
+               return;
+
+       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (app_widget->priv->checkbox)) != selected) {
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app_widget->priv->checkbox), selected);
+               g_object_notify (G_OBJECT (app_widget), "selected");
+       }
 }
 
 gboolean
 gs_app_widget_get_selected (GsAppWidget *app_widget)
 {
-       if (app_widget->priv->selectable)
-               return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (app_widget->priv->checkbox));
-       else
+       if (!app_widget->priv->selectable)
                return FALSE;
+
+       return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (app_widget->priv->checkbox));
 }
 
 GtkWidget *
diff --git a/src/gs-shell-installed.c b/src/gs-shell-installed.c
index 500ea77..4e6a096 100644
--- a/src/gs-shell-installed.c
+++ b/src/gs-shell-installed.c
@@ -31,6 +31,7 @@
 #include "gs-utils.h"
 #include "gs-app-widget.h"
 #include "gs-app-folder-dialog.h"
+#include "gs-folders.h"
 
 #define INSTALL_DATE_QUEUED     (G_MAXUINT - 1)
 #define INSTALL_DATE_INSTALLING (G_MAXUINT - 2)
@@ -233,6 +234,8 @@ gs_shell_installed_notify_state_changed_cb (GsApp *app,
        gtk_list_box_invalidate_sort (shell->priv->list_box_installed);
 }
 
+static void selection_changed (GsShellInstalled *shell);
+
 static void
 gs_shell_installed_add_app (GsShellInstalled *shell, GsApp *app)
 {
@@ -246,6 +249,8 @@ gs_shell_installed_add_app (GsShellInstalled *shell, GsApp *app)
        g_signal_connect_object (app, "notify::state",
                                 G_CALLBACK (gs_shell_installed_notify_state_changed_cb),
                                 shell, 0);
+       g_signal_connect_swapped (widget, "notify::selected",
+                                 G_CALLBACK (selection_changed), shell);
        gs_app_widget_set_app (GS_APP_WIDGET (widget), app);
        gtk_container_add (GTK_CONTAINER (priv->list_box_installed), widget);
        gs_app_widget_set_size_groups (GS_APP_WIDGET (widget),
@@ -586,7 +591,8 @@ set_selection_mode (GsShellInstalled *shell_installed, gboolean selection_mode)
                gtk_style_context_add_class (context, "selection-mode");
                widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_select"));
                gtk_button_set_image (GTK_BUTTON (widget), NULL);
-               gtk_button_set_label (GTK_BUTTON (widget), _("Cancel"));
+               gtk_button_set_label (GTK_BUTTON (widget), _("_Cancel"));
+               gtk_button_set_use_underline (GTK_BUTTON (widget), TRUE);
                gtk_widget_show (widget);
                widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "buttonbox_main"));
                gtk_widget_hide (widget);
@@ -605,6 +611,13 @@ set_selection_mode (GsShellInstalled *shell_installed, gboolean selection_mode)
                gtk_widget_show (widget);
                widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "header_selection_menu_button"));
                gtk_widget_hide (widget);
+
+               widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_folder_add"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_folder_move"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_folder_remove"));
+               gtk_widget_hide (widget);
        }
 
        children = gtk_container_get_children (GTK_CONTAINER (priv->list_box_installed));
@@ -647,8 +660,44 @@ get_selected_apps (GsShellInstalled *shell_installed)
        return list;
 }
 
+static void
+selection_changed (GsShellInstalled *shell_installed)
+{
+       GsShellInstalledPrivate *priv = shell_installed->priv;
+       GsFolders *folders;
+       GList *apps, *l;
+       GsApp *app;
+       gboolean has_folders, has_nonfolders;
+       GtkWidget *button;
+
+       folders = gs_folders_get ();
+       has_folders = has_nonfolders = FALSE;
+       apps = get_selected_apps (shell_installed);
+       for (l = apps; l; l = l->next) {
+               app = l->data;
+               if (gs_folders_get_app_folder (folders,
+                                              gs_app_get_id_full (app),
+                                              gs_app_get_categories (app))) {
+                       has_folders = TRUE;
+               } else {
+                       has_nonfolders = TRUE;
+               }
+       }
+       g_list_free (apps);
+       g_object_unref (folders);
+
+       button = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_folder_add"));
+       gtk_widget_set_visible (button, has_nonfolders);
+
+       button = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_folder_move"));
+       gtk_widget_set_visible (button, has_folders && !has_nonfolders);
+
+       button = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_folder_remove"));
+       gtk_widget_set_visible (button, has_folders);
+}
+
 static gboolean
-app_folder_dialog_done (GsShellInstalled *shell_installed)
+refresh_selected_rows (GsShellInstalled *shell_installed)
 {
        GsShellInstalledPrivate *priv = shell_installed->priv;
        GList *children, *l;
@@ -659,6 +708,7 @@ app_folder_dialog_done (GsShellInstalled *shell_installed)
                GsAppWidget *app_widget = GS_APP_WIDGET (gtk_bin_get_child (GTK_BIN (row)));
                if (gs_app_widget_get_selected (app_widget)) {
                        gs_app_widget_refresh (app_widget);
+                       gs_app_widget_set_selected (app_widget, FALSE);
                }
        }
        g_list_free (children);
@@ -679,7 +729,29 @@ show_folder_dialog (GtkButton *button, GsShellInstalled *shell_installed)
        g_list_free (apps);
        gtk_window_present (GTK_WINDOW (dialog));
        g_signal_connect_swapped (dialog, "delete-event",
-                                 G_CALLBACK (app_folder_dialog_done), shell_installed);
+                                 G_CALLBACK (refresh_selected_rows), shell_installed);
+}
+
+static void
+remove_folders (GtkButton *button, GsShellInstalled *shell_installed)
+{
+       GList *apps, *l;
+       GsFolders *folders;
+       GsApp *app;
+
+       folders = gs_folders_get ();
+       apps = get_selected_apps (shell_installed);
+       for (l = apps; l; l = l->next) {
+               app = l->data;
+               gs_folders_set_app_folder (folders,
+                                          gs_app_get_id_full (app),
+                                          gs_app_get_categories (app),
+                                          NULL);
+       }
+       g_list_free (apps);
+       g_object_unref (folders);
+
+       refresh_selected_rows (shell_installed);
 }
 
 static void
@@ -749,10 +821,18 @@ gs_shell_installed_setup (GsShellInstalled *shell_installed,
 
        priv->bottom_bar = GTK_REVEALER (gtk_builder_get_object (priv->builder, "bottom_install"));
 
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_folder_install"));
+       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_folder_add"));
+       g_signal_connect (widget, "clicked",
+                         G_CALLBACK (show_folder_dialog), shell_installed);
+       
+       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_folder_move"));
        g_signal_connect (widget, "clicked",
                          G_CALLBACK (show_folder_dialog), shell_installed);
        
+       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_folder_remove"));
+       g_signal_connect (widget, "clicked",
+                         G_CALLBACK (remove_folders), shell_installed);
+
        widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_select"));
        g_signal_connect (widget, "clicked",
                          G_CALLBACK (selection_mode_cb), shell_installed);


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