[gnome-software/wip/folders: 5/10] Add a dialog to edit app folders
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/wip/folders: 5/10] Add a dialog to edit app folders
- Date: Thu, 14 Nov 2013 02:05:41 +0000 (UTC)
commit 280262fcb54bf90f81ebfbc8d6768b79da1c428e
Author: Matthias Clasen <mclasen redhat com>
Date: Wed Nov 13 20:30:30 2013 -0500
Add a dialog to edit app folders
This will be used in subsequent commits.
src/Makefile.am | 3 +
src/app-folder-dialog.ui | 86 +++++++++
src/gnome-software.gresource.xml | 1 +
src/gs-app-folder-dialog.c | 359 ++++++++++++++++++++++++++++++++++++++
src/gs-app-folder-dialog.h | 59 ++++++
5 files changed, 508 insertions(+), 0 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 39eb9fb..e19a53e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,6 +23,7 @@ desktop_in_files = \
desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
UI_FILES = \
+ app-folder-dialog.ui \
app-menu.ui \
app-tile.ui \
app-widget.ui \
@@ -108,6 +109,8 @@ gnome_software_service_SOURCES = \
gs-category-tile.h \
gs-app-tile.c \
gs-app-tile.h \
+ gs-app-folder-dialog.c \
+ gs-app-folder-dialog.h \
gs-box.h \
gs-box.c \
gs-plugin.c \
diff --git a/src/app-folder-dialog.ui b/src/app-folder-dialog.ui
new file mode 100644
index 0000000..aedcf6a
--- /dev/null
+++ b/src/app-folder-dialog.ui
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.10 -->
+ <template class="GsAppFolderDialog" parent="GtkWindow">
+ <property name="title" translatable="yes">Application Folders</property>
+ <property name="type-hint">dialog</property>
+ <property name="modal">True</property>
+ <property name="resizable">False</property>
+ <child type="titlebar">
+ <object class="GtkHeaderBar" id="header">
+ <property name="visible">True</property>
+ <child type="title">
+ <object class="GtkLabel" id="title_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Application Folders</property>
+ <style>
+ <class name="title"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="label" translatable="True">_Cancel</property>
+ </object>
+ <packing>
+ <property name="pack_type">start</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="done_button">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="label" translatable="True">_Done</property>
+ <property name="receives_default">True</property>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="content">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="margin">12</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="description_label">
+ <property name="visible">True</property>
+ <property name="wrap">True</property>
+ <property name="width_chars">50</property>
+ <property name="max_width_chars">55</property>
+ </object>
+ <packing>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkListBox" id="app_folder_list">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="fill">True</property>
+ <property name="expand">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="new_folder_button">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="label" translatable="yes">_New Folder</property>
+ </object>
+ <packing>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/gnome-software.gresource.xml b/src/gnome-software.gresource.xml
index 9bdbbd9..56028b2 100644
--- a/src/gnome-software.gresource.xml
+++ b/src/gnome-software.gresource.xml
@@ -8,6 +8,7 @@
<file preprocess="xml-stripblanks">category-tile.ui</file>
<file preprocess="xml-stripblanks">app-tile.ui</file>
<file preprocess="xml-stripblanks">app-widget.ui</file>
+ <file preprocess="xml-stripblanks">app-folder-dialog.ui</file>
<file preprocess="xml-stripblanks">screenshot-image.ui</file>
<file preprocess="xml-stripblanks">gs-star-widget.ui</file>
<file>gtk-style.css</file>
diff --git a/src/gs-app-folder-dialog.c b/src/gs-app-folder-dialog.c
new file mode 100644
index 0000000..08598f1
--- /dev/null
+++ b/src/gs-app-folder-dialog.c
@@ -0,0 +1,359 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Matthias Clasen <mclasen redhat com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "gs-folders.h"
+#include "gs-app-folder-dialog.h"
+
+typedef struct _GsAppFolderDialogPrivate GsAppFolderDialogPrivate;
+struct _GsAppFolderDialogPrivate
+{
+ GList *apps;
+ GsFolders *folders;
+ GtkWidget *header;
+ GtkWidget *cancel_button;
+ GtkWidget *done_button;
+ GtkWidget *description_label;
+ GtkWidget *app_folder_list;
+ GtkWidget *new_folder_button;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GsAppFolderDialog, gs_app_folder_dialog, GTK_TYPE_WINDOW)
+
+#define PRIVATE(o) (gs_app_folder_dialog_get_instance_private (o))
+
+static void
+gs_app_folder_dialog_destroy (GtkWidget *widget)
+{
+ GsAppFolderDialog *dialog = GS_APP_FOLDER_DIALOG (widget);
+ GsAppFolderDialogPrivate *priv = PRIVATE (dialog);
+
+ g_list_free (priv->apps);
+ priv->apps = NULL;
+
+ g_clear_object (&priv->folders);
+
+ GTK_WIDGET_CLASS (gs_app_folder_dialog_parent_class)->destroy (widget);
+}
+
+static void
+cancel_cb (GsAppFolderDialog *dialog)
+{
+ gtk_window_close (GTK_WINDOW (dialog));
+}
+
+static void
+apply_changes (GsAppFolderDialog *dialog)
+{
+ GsAppFolderDialogPrivate *priv = PRIVATE (dialog);
+ GtkListBoxRow *row;
+ const gchar *folder;
+ GList *l;
+
+ row = gtk_list_box_get_selected_row (GTK_LIST_BOX (priv->app_folder_list));
+ if (row == NULL)
+ folder = NULL;
+ else
+ folder = (const gchar *)g_object_get_data (G_OBJECT (row), "folder");
+
+ for (l = priv->apps; l; l = l->next) {
+ GsApp *app = l->data;
+ gs_folders_set_app_folder (priv->folders, gs_app_get_id (app), folder);
+ }
+
+ gs_folders_save (priv->folders);
+}
+
+static void
+done_cb (GsAppFolderDialog *dialog)
+{
+ apply_changes (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);
+}
+
+static void
+done_editing (GtkEntry *entry, GsAppFolderDialog *dialog)
+{
+ GsAppFolderDialogPrivate *priv = PRIVATE (dialog);
+ GtkWidget *row;
+ gchar *folder;
+ 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_widget_set_margin_left (label, 10);
+ gtk_widget_set_margin_right (label, 10);
+ gtk_widget_set_halign (label, GTK_ALIGN_START);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+
+ gtk_box_pack_start (GTK_BOX (parent), label, TRUE, TRUE, 0);
+ gtk_box_reorder_child (GTK_BOX (parent), label, 0);
+
+ g_object_set_data_full (G_OBJECT (row), "folder", folder, g_free);
+ gs_folders_add_folder (priv->folders, folder);
+}
+
+static void
+new_folder_cb (GsAppFolderDialog *dialog)
+{
+ GsAppFolderDialogPrivate *priv = PRIVATE (dialog);
+ GtkWidget *row;
+ GtkWidget *box;
+ GtkWidget *entry;
+ GtkWidget *button;
+
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ entry = gtk_entry_new ();
+ gtk_widget_set_margin_left (entry, 10);
+ gtk_widget_set_margin_right (entry, 10);
+ gtk_widget_set_halign (entry, GTK_ALIGN_START);
+ gtk_box_pack_start (GTK_BOX (box), entry, TRUE, TRUE, 0);
+
+ button = gtk_button_new_from_icon_name ("edit-delete-symbolic", GTK_ICON_SIZE_MENU);
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
+
+ row = gtk_list_box_row_new ();
+ gtk_container_add (GTK_CONTAINER (row), box);
+
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (delete_row), 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, -1);
+
+ gtk_widget_grab_focus (entry);
+}
+
+static void
+update_header_func (GtkListBoxRow *row,
+ GtkListBoxRow *before,
+ gpointer user_data)
+{
+ GtkWidget *current;
+
+ if (before == NULL)
+ return;
+
+ current = gtk_list_box_row_get_header (row);
+ if (current == NULL)
+ {
+ current = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+ gtk_widget_show (current);
+ gtk_list_box_row_set_header (row, current);
+ }
+}
+
+static void
+gs_app_folder_dialog_init (GsAppFolderDialog *dialog)
+{
+ GsAppFolderDialogPrivate *priv = PRIVATE (dialog);
+
+ priv->folders = gs_folders_get ();
+
+ gtk_widget_init_template (GTK_WIDGET (dialog));
+
+ g_signal_connect_swapped (priv->cancel_button, "clicked",
+ G_CALLBACK (cancel_cb), dialog);
+ g_signal_connect_swapped (priv->done_button, "clicked",
+ G_CALLBACK (done_cb), dialog);
+ g_signal_connect_swapped (priv->new_folder_button, "clicked",
+ G_CALLBACK (new_folder_cb), dialog);
+
+ gtk_list_box_set_header_func (GTK_LIST_BOX (priv->app_folder_list),
+ update_header_func, NULL, NULL);
+}
+
+static void
+gs_app_folder_dialog_class_init (GsAppFolderDialogClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ widget_class->destroy = gs_app_folder_dialog_destroy;
+
+ gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/software/app-folder-dialog.ui");
+
+ gtk_widget_class_bind_template_child_private (widget_class, GsAppFolderDialog, header);
+ gtk_widget_class_bind_template_child_private (widget_class, GsAppFolderDialog, cancel_button);
+ gtk_widget_class_bind_template_child_private (widget_class, GsAppFolderDialog, done_button);
+ gtk_widget_class_bind_template_child_private (widget_class, GsAppFolderDialog, description_label);
+ gtk_widget_class_bind_template_child_private (widget_class, GsAppFolderDialog, app_folder_list);
+ gtk_widget_class_bind_template_child_private (widget_class, GsAppFolderDialog, new_folder_button);
+}
+
+static GtkWidget *
+create_row (GsAppFolderDialog *dialog, const gchar *folder)
+{
+ GsAppFolderDialogPrivate *priv = PRIVATE (dialog);
+ GtkWidget *row;
+ GtkWidget *box;
+ GtkWidget *label;
+ GtkWidget *button;
+ GString *s;
+ GList *l;
+
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ label = gtk_label_new (gs_folders_get_folder_name (priv->folders, folder));
+ gtk_widget_set_margin_left (label, 10);
+ gtk_widget_set_margin_right (label, 10);
+ gtk_widget_set_halign (label, GTK_ALIGN_START);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
+
+ s = g_string_new ("");
+ for (l = priv->apps; l; l = l->next) {
+ GsApp *app = l->data;
+ const gchar *app_folder;
+
+ app_folder = gs_folders_get_app_folder (priv->folders, gs_app_get_id (app));
+ if (g_strcmp0 (folder, app_folder) == 0) {
+ if (s->len > 0)
+ g_string_append (s, ", ");
+ g_string_append (s, gs_app_get_name (app));
+ }
+ }
+ if (s->len > 0) {
+ label = gtk_label_new (s->str);
+ gtk_widget_set_margin_left (label, 10);
+ gtk_widget_set_margin_right (label, 10);
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+ gtk_label_set_max_width_chars (GTK_LABEL (label), 30);
+ gtk_widget_set_halign (label, GTK_ALIGN_END);
+ gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 0);
+ }
+ g_string_free (s, TRUE);
+
+ button = gtk_button_new_from_icon_name ("edit-delete-symbolic", GTK_ICON_SIZE_MENU);
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
+
+ row = gtk_list_box_row_new ();
+ gtk_container_add (GTK_CONTAINER (row), box);
+
+ gtk_widget_show_all (row);
+
+ g_object_set_data_full (G_OBJECT (row), "folder", g_strdup (folder), g_free);
+
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (delete_row), dialog);
+
+ return row;
+}
+
+static void
+populate_list (GsAppFolderDialog *dialog)
+{
+ GsAppFolderDialogPrivate *priv = PRIVATE (dialog);
+ gchar **folders;
+ guint i;
+
+ folders = gs_folders_get_folders (priv->folders);
+ for (i = 0; folders[i]; i++) {
+ gtk_list_box_insert (GTK_LIST_BOX (priv->app_folder_list), create_row (dialog, folders[i]),
-1);
+ }
+ g_free (folders);
+}
+
+static void
+gs_app_folder_dialog_set_apps (GsAppFolderDialog *dialog,
+ GList *apps)
+{
+ GsAppFolderDialogPrivate *priv = PRIVATE (dialog);
+ gchar *label;
+ const gchar *app1, *app2, *app3;
+
+ priv->apps = g_list_copy (apps);
+
+ switch (g_list_length (priv->apps)) {
+ case 0:
+ label = g_strdup (_("Add or remove folders. Your application folders can be found in the
Activities Overview."));
+ break;
+ case 1:
+ app1 = gs_app_get_name (GS_APP (priv->apps->data));
+ label = g_strdup_printf (_("Choose a folder for %s. Your application folders can be found in
the Activities Overview."), app1);
+ break;
+ case 2:
+ app1 = gs_app_get_name (GS_APP (priv->apps->data));
+ app2 = gs_app_get_name (GS_APP (priv->apps->next->data));
+ label = g_strdup_printf (_("Choose a folder for %s and %s. Your application folders can be
found in the Activities Overview."), app1, app2);
+ break;
+ case 3:
+ app1 = gs_app_get_name (GS_APP (priv->apps->data));
+ app2 = gs_app_get_name (GS_APP (priv->apps->next->data));
+ app3 = gs_app_get_name (GS_APP (priv->apps->next->next->data));
+ label = g_strdup_printf (_("Choose a folder for %s, %s and %s. Your application folders can
be found in the Activities Overview."), app1, app2, app3);
+ break;
+ default:
+ label = g_strdup (_("Choose a folder for the selected applications. Your application folders
can be found in the Activities Overview."));
+ break;
+ }
+ gtk_label_set_label (GTK_LABEL (priv->description_label), label);
+ g_free (label);
+}
+
+GtkWidget *
+gs_app_folder_dialog_new (GtkWindow *parent, GList *apps)
+{
+ GsAppFolderDialog *dialog;
+
+ dialog = g_object_new (GS_TYPE_APP_FOLDER_DIALOG,
+ "transient-for", parent,
+ NULL);
+ gs_app_folder_dialog_set_apps (dialog, apps);
+ populate_list (dialog);
+
+ return GTK_WIDGET (dialog);
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-app-folder-dialog.h b/src/gs-app-folder-dialog.h
new file mode 100644
index 0000000..4f6dcae
--- /dev/null
+++ b/src/gs-app-folder-dialog.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Matthias Clasen <mclasen redhat com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef GS_APP_FOLDER_DIALOG_H
+#define GS_APP_FOLDER_DIALOG_H
+
+#include <gtk/gtk.h>
+
+#include "gs-app.h"
+
+#define GS_TYPE_APP_FOLDER_DIALOG (gs_app_folder_dialog_get_type())
+#define GS_APP_FOLDER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GS_TYPE_APP_FOLDER_DIALOG,
GsAppFolderDialog))
+#define GS_APP_FOLDER_DIALOG_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST((cls),
GS_TYPE_APP_FOLDER_DIALOG, GsAppFolderDialogClass))
+#define GS_IS_APP_FOLDER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GS_TYPE_APP_FOLDER_DIALOG))
+#define GS_IS_APP_FOLDER_DIALOG_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE((cls), GS_TYPE_APP_FOLDER_DIALOG))
+#define GS_APP_FOLDER_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GS_TYPE_APP_FOLDER_DIALOG,
GsAppFolderDialogClass))
+
+G_BEGIN_DECLS
+
+typedef struct _GsAppFolderDialog GsAppFolderDialog;
+typedef struct _GsAppFolderDialogClass GsAppFolderDialogClass;
+
+struct _GsAppFolderDialog
+{
+ GtkWindow parent;
+};
+
+struct _GsAppFolderDialogClass
+{
+ GtkWindowClass parent_class;
+};
+
+GType gs_app_folder_dialog_get_type (void);
+GtkWidget *gs_app_folder_dialog_new (GtkWindow *parent,
+ GList *apps);
+
+G_END_DECLS
+
+#endif /* GS_APP_FOLDER_DIALOG_H */
+
+/* vim: set noexpandtab: */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]