[libpeas] Split the PeasUIPluginManager into a manager, view and store
- From: Garrett Regier <gregier src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libpeas] Split the PeasUIPluginManager into a manager, view and store
- Date: Mon, 19 Jul 2010 18:51:40 +0000 (UTC)
commit 209d74c14af821ef88686f4bd5eebab92e8d03f1
Author: Garrett Regier <alias301 gmail com>
Date: Mon Jul 19 11:49:36 2010 -0700
Split the PeasUIPluginManager into a manager, view and store
https://bugzilla.gnome.org/show_bug.cgi?id=624309
libpeasui/Makefile.am | 16 +-
libpeasui/peas-ui-plugin-manager-store.c | 505 ++++++++++++++++
libpeasui/peas-ui-plugin-manager-store.h | 96 +++
libpeasui/peas-ui-plugin-manager-view.c | 877 ++++++++++++++++++++++++++++
libpeasui/peas-ui-plugin-manager-view.h | 79 +++
libpeasui/peas-ui-plugin-manager.c | 931 +++++++-----------------------
libpeasui/peas-ui-plugin-manager.h | 6 +-
libpeasui/peas-ui.h | 1 +
8 files changed, 1788 insertions(+), 723 deletions(-)
---
diff --git a/libpeasui/Makefile.am b/libpeasui/Makefile.am
index bfbb515..fcbf548 100644
--- a/libpeasui/Makefile.am
+++ b/libpeasui/Makefile.am
@@ -21,13 +21,23 @@ INST_H_FILES = \
peas-ui-configurable.h \
peas-ui-plugin-info.h \
peas-ui-plugin-manager.h \
+ peas-ui-plugin-manager-view.h \
peas-ui.h
-libpeasui_1_0_la_SOURCES = \
+NOINST_H_FILES = \
+ peas-ui-plugin-manager-store.h
+
+C_FILES = \
peas-ui-configurable.c \
peas-ui-plugin-info.c \
peas-ui-plugin-manager.c \
- $(INST_H_FILES)
+ peas-ui-plugin-manager-store.c \
+ peas-ui-plugin-manager-view.c
+
+libpeasui_1_0_la_SOURCES = \
+ $(INST_H_FILES) \
+ $(NOINST_H_FILES) \
+ $(C_FILES)
headerdir = $(prefix)/include/libpeas-1.0/libpeasui
header_DATA = $(INST_H_FILES)
@@ -41,7 +51,7 @@ if HAVE_INTROSPECTION
--warn-all
INTROSPECTION_COMPILER_ARGS = --includedir=$(top_srcdir)/libpeas
- introspection_sources = $(libpeasui_1_0_la_SOURCES)
+ introspection_sources = $(INST_H_FILES) $(C_FILES)
PeasUI-1.0.gir: libpeasui-1.0.la
PeasUI_1_0_gir_INCLUDES = GObject-2.0 $(GTK_TYPELIB) Peas-1.0
diff --git a/libpeasui/peas-ui-plugin-manager-store.c b/libpeasui/peas-ui-plugin-manager-store.c
new file mode 100644
index 0000000..61b268c
--- /dev/null
+++ b/libpeasui/peas-ui-plugin-manager-store.c
@@ -0,0 +1,505 @@
+/*
+ * peas-plugin-manager-store.c
+ * This file is part of libpeas
+ *
+ * Copyright (C) 2002 Paolo Maggi and James Willcox
+ * Copyright (C) 2003-2006 Paolo Maggi, Paolo Borelli
+ * Copyright (C) 2007-2009 Paolo Maggi, Paolo Borelli, Steve Frécinaux
+ * Copyright (C) 2010 Garrett Regier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <libpeas/peas-plugin-info.h>
+
+#include "peas-ui-plugin-manager-store.h"
+#include "peas-ui-plugin-info.h"
+
+static const GType ColumnTypes[] = {
+ G_TYPE_BOOLEAN, /* Enabled */
+ G_TYPE_BOOLEAN, /* Enabled Visible */
+ G_TYPE_STRING, /* Icon */
+ G_TYPE_BOOLEAN, /* Icon Visible */
+ G_TYPE_STRING, /* Info */
+ G_TYPE_BOOLEAN, /* Info Visible */
+ G_TYPE_POINTER /* PeasPluginInfo */
+};
+
+/* G_STATIC_ASSERT is in glib >= 2.20 and we only depend on 2.18.0 */
+#ifdef G_STATIC_ASSERT
+G_STATIC_ASSERT (G_N_ELEMENTS (ColumnTypes) == PEAS_UI_PLUGIN_MANAGER_STORE_N_COLUMNS);
+#endif
+
+struct _PeasUIPluginManagerStorePrivate {
+ PeasEngine *engine;
+};
+
+/* Properties */
+enum {
+ PROP_0,
+ PROP_ENGINE
+};
+
+G_DEFINE_TYPE (PeasUIPluginManagerStore, peas_ui_plugin_manager_store, GTK_TYPE_LIST_STORE);
+
+static void
+update_plugin (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter,
+ PeasPluginInfo *info)
+{
+ gboolean loaded;
+ gboolean available;
+ gboolean builtin;
+ gchar *markup;
+ const gchar *icon_name;
+
+ loaded = peas_plugin_info_is_loaded (info);
+ available = peas_plugin_info_is_available (info);
+ builtin = peas_plugin_info_is_builtin (info);
+
+ markup = g_markup_printf_escaped ("<b>%s</b>\n%s",
+ peas_plugin_info_get_name (info),
+ peas_plugin_info_get_description (info));
+
+ if (peas_plugin_info_is_available (info))
+ icon_name = peas_ui_plugin_info_get_icon_name (info);
+ else
+ icon_name = GTK_STOCK_DIALOG_ERROR;
+
+ gtk_list_store_set (GTK_LIST_STORE (store), iter,
+ PEAS_UI_PLUGIN_MANAGER_STORE_ENABLED_COLUMN, loaded,
+ PEAS_UI_PLUGIN_MANAGER_STORE_CAN_ENABLE_COLUMN, !builtin && available,
+ PEAS_UI_PLUGIN_MANAGER_STORE_ICON_COLUMN, icon_name,
+ PEAS_UI_PLUGIN_MANAGER_STORE_ICON_VISIBLE_COLUMN, !available,
+ PEAS_UI_PLUGIN_MANAGER_STORE_INFO_COLUMN, markup,
+ PEAS_UI_PLUGIN_MANAGER_STORE_INFO_SENSITIVE_COLUMN, available && (!builtin || loaded),
+ PEAS_UI_PLUGIN_MANAGER_STORE_PLUGIN_COLUMN, info,
+ -1);
+
+ g_free (markup);
+}
+
+static void
+plugin_loaded_toggled_cb (PeasEngine *engine,
+ PeasPluginInfo *info,
+ PeasUIPluginManagerStore *store)
+{
+ GtkTreeIter iter;
+
+ if (peas_ui_plugin_manager_store_get_iter_from_plugin (store, &iter, info))
+ update_plugin (store, &iter, info);
+}
+
+static gint
+model_name_sort_func (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter1,
+ GtkTreeIter *iter2,
+ gpointer user_data)
+{
+ PeasPluginInfo *info1;
+ PeasPluginInfo *info2;
+
+ info1 = peas_ui_plugin_manager_store_get_plugin (store, iter1);
+ info2 = peas_ui_plugin_manager_store_get_plugin (store, iter2);
+
+ return g_utf8_collate (peas_plugin_info_get_name (info1),
+ peas_plugin_info_get_name (info2));
+}
+
+static void
+peas_ui_plugin_manager_store_init (PeasUIPluginManagerStore *store)
+{
+ store->priv = G_TYPE_INSTANCE_GET_PRIVATE (store,
+ PEAS_UI_TYPE_PLUGIN_MANAGER_STORE,
+ PeasUIPluginManagerStorePrivate);
+
+ gtk_list_store_set_column_types (GTK_LIST_STORE (store),
+ PEAS_UI_PLUGIN_MANAGER_STORE_N_COLUMNS,
+ (GType *) ColumnTypes);
+
+ /* Sort on the plugin names */
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store),
+ (GtkTreeIterCompareFunc) model_name_sort_func,
+ NULL, NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+ GTK_SORT_ASCENDING);
+}
+
+static void
+peas_ui_plugin_manager_store_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PeasUIPluginManagerStore *store = PEAS_UI_PLUGIN_MANAGER_STORE (object);
+
+ switch (prop_id)
+ {
+ case PROP_ENGINE:
+ store->priv->engine = g_value_get_object (value);
+ g_object_ref (store->priv->engine);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+peas_ui_plugin_manager_store_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PeasUIPluginManagerStore *store = PEAS_UI_PLUGIN_MANAGER_STORE (object);
+
+ switch (prop_id)
+ {
+ case PROP_ENGINE:
+ g_value_set_object (value, store->priv->engine);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+peas_ui_plugin_manager_store_constructed (GObject *object)
+{
+ PeasUIPluginManagerStore *store = PEAS_UI_PLUGIN_MANAGER_STORE (object);
+
+ g_signal_connect_after (store->priv->engine,
+ "load-plugin",
+ G_CALLBACK (plugin_loaded_toggled_cb),
+ store);
+ g_signal_connect_after (store->priv->engine,
+ "unload-plugin",
+ G_CALLBACK (plugin_loaded_toggled_cb),
+ store);
+
+ peas_ui_plugin_manager_store_reload (store);
+
+ if (G_OBJECT_CLASS (peas_ui_plugin_manager_store_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (peas_ui_plugin_manager_store_parent_class)->constructed (object);
+}
+
+static void
+peas_ui_plugin_manager_store_dispose (GObject *object)
+{
+ PeasUIPluginManagerStore *store = PEAS_UI_PLUGIN_MANAGER_STORE (object);
+
+ if (store->priv->engine != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (store->priv->engine,
+ plugin_loaded_toggled_cb,
+ store);
+
+ g_object_unref (store->priv->engine);
+ store->priv->engine = NULL;
+ }
+
+ G_OBJECT_CLASS (peas_ui_plugin_manager_store_parent_class)->dispose (object);
+}
+
+static void
+peas_ui_plugin_manager_store_class_init (PeasUIPluginManagerStoreClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = peas_ui_plugin_manager_store_set_property;
+ object_class->get_property = peas_ui_plugin_manager_store_get_property;
+ object_class->constructed = peas_ui_plugin_manager_store_constructed;
+ object_class->dispose = peas_ui_plugin_manager_store_dispose;
+
+ /*
+ * PeasUIPLuginManagerStore:engine:
+ *
+ * The #PeasEngine this store is attached to.
+ */
+ g_object_class_install_property (object_class,
+ PROP_ENGINE,
+ g_param_spec_object ("engine",
+ "engine",
+ "The PeasEngine this store is attached to",
+ PEAS_TYPE_ENGINE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_type_class_add_private (object_class, sizeof (PeasUIPluginManagerStorePrivate));
+}
+
+/*
+ * peas_ui_plugin_manager_store_new:
+ * @engine: A #PeasEngine.
+ *
+ * Creates a new plugin manager store for the given #PeasEngine.
+ *
+ * Returns: the new #PeasUIPluginManagerStore.
+ */
+PeasUIPluginManagerStore *
+peas_ui_plugin_manager_store_new (PeasEngine *engine)
+{
+ g_return_val_if_fail (PEAS_IS_ENGINE (engine), NULL);
+
+ return PEAS_UI_PLUGIN_MANAGER_STORE (g_object_new (PEAS_UI_TYPE_PLUGIN_MANAGER_STORE,
+ "engine", engine,
+ NULL));
+}
+
+/*
+ * peas_ui_plugin_manager_store_reload:
+ * @store: A #PeasUIPluginManagerStore.
+ *
+ * Reloads the list of plugins.
+ */
+void
+peas_ui_plugin_manager_store_reload (PeasUIPluginManagerStore *store)
+{
+ GtkListStore *list_store;
+ const GList *plugins;
+ GtkTreeIter iter;
+
+ g_return_if_fail (PEAS_UI_IS_PLUGIN_MANAGER_STORE (store));
+
+ list_store = GTK_LIST_STORE (store);
+
+ gtk_list_store_clear (list_store);
+
+ plugins = peas_engine_get_plugin_list (store->priv->engine);
+
+ while (plugins != NULL)
+ {
+ PeasPluginInfo *info;
+
+ info = PEAS_PLUGIN_INFO (plugins->data);
+
+ gtk_list_store_append (list_store, &iter);
+ update_plugin (store, &iter, info);
+
+ plugins = plugins->next;
+ }
+}
+
+/*
+ * peas_ui_plugin_manager_store_set_enabled:
+ * @store: A #PeasUIPluginManagerStore.
+ * @iter: A #GtkTreeIter.
+ * @enabled: If the plugin should be enabled.
+ *
+ * Sets if the plugin at @iter should be enabled.
+ */
+void
+peas_ui_plugin_manager_store_set_enabled (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter,
+ gboolean enabled)
+{
+ PeasPluginInfo *info;
+ gboolean success = TRUE;
+
+ g_return_if_fail (PEAS_UI_IS_PLUGIN_MANAGER_STORE (store));
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (peas_ui_plugin_manager_store_can_enable (store, iter));
+
+ info = peas_ui_plugin_manager_store_get_plugin (store, iter);
+ g_return_if_fail (info != NULL);
+
+ if (enabled)
+ {
+ /* load the plugin */
+ if (!peas_engine_load_plugin (store->priv->engine, info))
+ success = FALSE;
+ }
+ else
+ {
+ /* unload the plugin */
+ if (!peas_engine_unload_plugin (store->priv->engine, info))
+ success = FALSE;
+ }
+
+ if (success)
+ update_plugin (store, iter, info);
+}
+
+/*
+ * peas_ui_plugin_manager_store_set_enabled:
+ * @store: A #PeasUIPluginManagerStore.
+ * @iter: A #GtkTreeIter.
+ *
+ * Returns if the plugin at @iter is enabled.
+ *
+ * Returns: if the plugin at @iter is enabled.
+ */
+gboolean
+peas_ui_plugin_manager_store_get_enabled (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter)
+{
+ gboolean enabled;
+
+ g_return_val_if_fail (PEAS_UI_IS_PLUGIN_MANAGER_STORE (store), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ PEAS_UI_PLUGIN_MANAGER_STORE_ENABLED_COLUMN, &enabled,
+ -1);
+
+ return enabled;
+}
+
+/*
+ * peas_ui_plugin_manager_store_set_all_enabled:
+ * @store: A #PeasUIPluginManagerStore.
+ * @enabled: If all the plugins should be enabled.
+ *
+ * Sets if all the plugins should be enabled.
+ */
+void
+peas_ui_plugin_manager_store_set_all_enabled (PeasUIPluginManagerStore *store,
+ gboolean enabled)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ g_return_if_fail (PEAS_UI_IS_PLUGIN_MANAGER_STORE (store));
+
+ model = GTK_TREE_MODEL (store);
+
+ if (!gtk_tree_model_get_iter_first (model, &iter))
+ return;
+
+ do
+ {
+ if (peas_ui_plugin_manager_store_can_enable (store, &iter))
+ peas_ui_plugin_manager_store_set_enabled (store, &iter, enabled);
+ }
+ while (gtk_tree_model_iter_next (model, &iter));
+}
+
+/*
+ * peas_ui_plugin_manager_store_toggle_enabled:
+ * @store: A #PeasUIPluginManagerStore.
+ * @iter: A #GtkTreeIter.
+ *
+ * Toggles the if the plugin should should be enabled.
+ */
+void
+peas_ui_plugin_manager_store_toggle_enabled (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter)
+{
+ gboolean enabled;
+
+ g_return_if_fail (PEAS_UI_IS_PLUGIN_MANAGER_STORE (store));
+ g_return_if_fail (iter != NULL);
+
+ enabled = peas_ui_plugin_manager_store_get_enabled (store, iter);
+
+ peas_ui_plugin_manager_store_set_enabled (store, iter, !enabled);
+}
+
+/*
+ * peas_ui_plugin_manager_store_can_enabled:
+ * @store: A #PeasUIPluginManagerStore.
+ * @iter: A #GtkTreeIter.
+ *
+ * Returns if the plugin at @iter can be enabled.
+ * Note: that while a plugin may be enableable there are other factors
+ * that can cause it to not be enabled.
+ *
+ * Returns: if the plugin can be enabled.
+ */
+gboolean
+peas_ui_plugin_manager_store_can_enable (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter)
+{
+ gboolean can_enable;
+
+ g_return_val_if_fail (PEAS_UI_IS_PLUGIN_MANAGER_STORE (store), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ PEAS_UI_PLUGIN_MANAGER_STORE_CAN_ENABLE_COLUMN, &can_enable,
+ -1);
+
+ return can_enable;
+}
+
+/*
+ * peas_ui_plugin_manager_store_get_plugin:
+ * @store: A #PeasUIPluginManagerStore.
+ * @iter: A #GtkTreeIter.
+ *
+ * Returns the plugin at @iter.
+ *
+ * Returns: the plugin at @iter.
+ */
+PeasPluginInfo *
+peas_ui_plugin_manager_store_get_plugin (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter)
+{
+ PeasPluginInfo *info;
+
+ g_return_val_if_fail (PEAS_UI_IS_PLUGIN_MANAGER_STORE (store), NULL);
+ g_return_val_if_fail (iter != NULL, NULL);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ PEAS_UI_PLUGIN_MANAGER_STORE_PLUGIN_COLUMN, &info,
+ -1);
+
+ return info;
+}
+
+/*
+ * peas_ui_plugin_manager_store_get_iter_from_plugin:
+ * @store: A #PeasUIPluginManagerStore.
+ * @iter: A #GtkTreeIter.
+ * @info: A #PeasPluginInfo.
+ *
+ * Sets @iter to the @info.
+ *
+ * Returns: if @iter was set.
+ */
+gboolean
+peas_ui_plugin_manager_store_get_iter_from_plugin (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter,
+ const PeasPluginInfo *info)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL (store);
+ gboolean found = FALSE;
+
+ g_return_val_if_fail (PEAS_UI_IS_PLUGIN_MANAGER_STORE (store), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ if (gtk_tree_model_get_iter_first (model, iter))
+ {
+ PeasPluginInfo *current_info;
+
+ do
+ {
+ current_info = peas_ui_plugin_manager_store_get_plugin (store, iter);
+
+ found = (info == current_info);
+ }
+ while (!found && gtk_tree_model_iter_next (model, iter));
+ }
+
+ return found;
+}
diff --git a/libpeasui/peas-ui-plugin-manager-store.h b/libpeasui/peas-ui-plugin-manager-store.h
new file mode 100644
index 0000000..293e919
--- /dev/null
+++ b/libpeasui/peas-ui-plugin-manager-store.h
@@ -0,0 +1,96 @@
+/*
+ * peas-plugin-manager-store.h
+ * This file is part of libpeas
+ *
+ * Copyright (C) 2002 Paolo Maggi and James Willcox
+ * Copyright (C) 2003-2006 Paolo Maggi, Paolo Borelli
+ * Copyright (C) 2007-2009 Paolo Maggi, Paolo Borelli, Steve Frécinaux
+ * Copyright (C) 2010 Garrett Regier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PEAS_UI_PLUGIN_MANAGER_STORE_H__
+#define __PEAS_UI_PLUGIN_MANAGER_STORE_H__
+
+#include <gtk/gtk.h>
+#include <libpeas/peas-engine.h>
+#include <libpeas/peas-plugin-info.h>
+
+G_BEGIN_DECLS
+
+enum {
+ PEAS_UI_PLUGIN_MANAGER_STORE_ENABLED_COLUMN = 0,
+ PEAS_UI_PLUGIN_MANAGER_STORE_CAN_ENABLE_COLUMN,
+ PEAS_UI_PLUGIN_MANAGER_STORE_ICON_COLUMN,
+ PEAS_UI_PLUGIN_MANAGER_STORE_ICON_VISIBLE_COLUMN,
+ PEAS_UI_PLUGIN_MANAGER_STORE_INFO_COLUMN,
+ PEAS_UI_PLUGIN_MANAGER_STORE_INFO_SENSITIVE_COLUMN,
+ PEAS_UI_PLUGIN_MANAGER_STORE_PLUGIN_COLUMN,
+ PEAS_UI_PLUGIN_MANAGER_STORE_N_COLUMNS
+} PeasUIPluginManagerStoreColumns;
+
+/*
+ * Type checking and casting macros
+ */
+#define PEAS_UI_TYPE_PLUGIN_MANAGER_STORE (peas_ui_plugin_manager_store_get_type())
+#define PEAS_UI_PLUGIN_MANAGER_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PEAS_UI_TYPE_PLUGIN_MANAGER_STORE, PeasUIPluginManagerStore))
+#define PEAS_UI_PLUGIN_MANAGER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PEAS_UI_TYPE_PLUGIN_MANAGER_STORE, PeasUIPluginManagerStoreClass))
+#define PEAS_UI_IS_PLUGIN_MANAGER_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PEAS_UI_TYPE_PLUGIN_MANAGER_STORE))
+#define PEAS_UI_IS_PLUGIN_MANAGER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PEAS_UI_TYPE_PLUGIN_MANAGER_STORE))
+#define PEAS_UI_PLUGIN_MANAGER_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PEAS_UI_TYPE_PLUGIN_MANAGER_STORE, PeasUIPluginManagerStoreClass))
+
+typedef struct _PeasUIPluginManagerStore PeasUIPluginManagerStore;
+typedef struct _PeasUIPluginManagerStoreClass PeasUIPluginManagerStoreClass;
+typedef struct _PeasUIPluginManagerStorePrivate PeasUIPluginManagerStorePrivate;
+
+struct _PeasUIPluginManagerStore {
+ GtkListStore parent;
+
+ /*< private > */
+ PeasUIPluginManagerStorePrivate *priv;
+};
+
+struct _PeasUIPluginManagerStoreClass {
+ GtkListStoreClass parent_class;
+};
+
+GType peas_ui_plugin_manager_store_get_type (void) G_GNUC_CONST;
+PeasUIPluginManagerStore *peas_ui_plugin_manager_store_new (PeasEngine *engine);
+
+void peas_ui_plugin_manager_store_reload (PeasUIPluginManagerStore *store);
+
+void peas_ui_plugin_manager_store_set_enabled (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter,
+ gboolean enabled);
+gboolean peas_ui_plugin_manager_store_get_enabled (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter);
+void peas_ui_plugin_manager_store_set_all_enabled (PeasUIPluginManagerStore *store,
+ gboolean enabled);
+void peas_ui_plugin_manager_store_toggle_enabled (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter);
+
+gboolean peas_ui_plugin_manager_store_can_enable (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter);
+
+PeasPluginInfo *peas_ui_plugin_manager_store_get_plugin (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter);
+
+gboolean peas_ui_plugin_manager_store_get_iter_from_plugin (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter,
+ const PeasPluginInfo *info);
+G_END_DECLS
+
+#endif /* __PEAS_UI_PLUGIN_MANAGER_STORE_H__ */
diff --git a/libpeasui/peas-ui-plugin-manager-view.c b/libpeasui/peas-ui-plugin-manager-view.c
new file mode 100644
index 0000000..e31cbb3
--- /dev/null
+++ b/libpeasui/peas-ui-plugin-manager-view.c
@@ -0,0 +1,877 @@
+/*
+ * peas-plugin-manager-view.c
+ * This file is part of libpeas
+ *
+ * Copyright (C) 2002 Paolo Maggi and James Willcox
+ * Copyright (C) 2003-2006 Paolo Maggi, Paolo Borelli
+ * Copyright (C) 2007-2009 Paolo Maggi, Paolo Borelli, Steve Frécinaux
+ * Copyright (C) 2010 Garrett Regier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <libpeas/peas-i18n.h>
+
+#include "peas-ui-plugin-manager-view.h"
+#include "peas-ui-plugin-manager-store.h"
+#include "peas-ui-configurable.h"
+
+/**
+ * SECTION:peas-ui-plugin-manager-view
+ * @short_description: Management tree view for plugins.
+ *
+ * The #PeasUIPluginManagerView is a tree view that can be used to manage
+ * plugins, i.e. load or unload them, and see some pieces of information.
+ *
+ * The only thing you need to do as an application writer if you wish
+ * to use the view to configure your plugins is to instantiate it using
+ * peas_ui_plugin_manager_view_new() and pack it into another
+ * widget or a window.
+ *
+ * Note: Changing the model of the view is not supported.
+ *
+ **/
+
+struct _PeasUIPluginManagerViewPrivate {
+ PeasEngine *engine;
+
+ PeasUIPluginManagerStore *store;
+
+ GtkWidget *popup_menu;
+
+ guint show_builtin : 1;
+};
+
+/* Properties */
+enum {
+ PROP_0,
+ PROP_ENGINE,
+ PROP_SHOW_BUILTIN
+};
+
+/* Signals */
+enum {
+ POPULATE_POPUP,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (PeasUIPluginManagerView, peas_ui_plugin_manager_view, GTK_TYPE_TREE_VIEW);
+
+static void
+convert_iter_to_child_iter (PeasUIPluginManagerView *view,
+ GtkTreeIter *iter)
+{
+ if (!view->priv->show_builtin)
+ {
+ GtkTreeModel *model;
+ GtkTreeIter child_iter;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
+
+ gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
+ &child_iter, iter);
+
+ *iter = child_iter;
+ }
+}
+
+static gboolean
+convert_child_iter_to_iter (PeasUIPluginManagerView *view,
+ GtkTreeIter *child_iter)
+{
+ gboolean success = TRUE;
+
+ if (!view->priv->show_builtin)
+ {
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
+
+ success = gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (model),
+ &iter, child_iter);
+
+ if (success)
+ *child_iter = iter;
+ }
+
+ return success;
+}
+
+static void
+plugin_list_changed_cb (PeasEngine *engine,
+ GParamSpec *pspec,
+ PeasUIPluginManagerView *view)
+{
+ PeasPluginInfo *info;
+
+ info = peas_ui_plugin_manager_view_get_selected_plugin (view);
+
+ peas_ui_plugin_manager_store_reload (view->priv->store);
+
+ if (info == NULL)
+ {
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
+
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ {
+ PeasUIPluginManagerStore *store;
+
+ store = PEAS_UI_PLUGIN_MANAGER_STORE (view->priv->store);
+
+ convert_iter_to_child_iter (view, &iter);
+ info = peas_ui_plugin_manager_store_get_plugin (store, &iter);
+ }
+ }
+
+ if (info != NULL)
+ peas_ui_plugin_manager_view_set_selected_plugin (view, info);
+}
+
+static gboolean
+filter_builtins_visible (PeasUIPluginManagerStore *store,
+ GtkTreeIter *iter,
+ PeasUIPluginManagerView *view)
+{
+ PeasPluginInfo *info;
+
+ /* We never filter showing builtins */
+ g_assert (view->priv->show_builtin == FALSE);
+
+ info = peas_ui_plugin_manager_store_get_plugin (store, iter);
+
+ if (info == NULL)
+ return FALSE;
+
+ return !peas_plugin_info_is_builtin (info);
+}
+
+static void
+enabled_toggled_cb (GtkCellRendererToggle *cell,
+ gchar *path_str,
+ PeasUIPluginManagerView *view)
+{
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
+ path = gtk_tree_path_new_from_string (path_str);
+
+ if (gtk_tree_model_get_iter (model, &iter, path))
+ {
+ convert_iter_to_child_iter (view, &iter);
+ peas_ui_plugin_manager_store_toggle_enabled (view->priv->store, &iter);
+ }
+
+ gtk_tree_path_free (path);
+}
+
+static void
+row_activated_cb (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ PeasUIPluginManagerView *view)
+{
+ GtkTreeIter iter;
+
+ g_return_if_fail (gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
+ &iter, path));
+
+ convert_iter_to_child_iter (view, &iter);
+
+ if (peas_ui_plugin_manager_store_can_enable (view->priv->store, &iter))
+ peas_ui_plugin_manager_store_toggle_enabled (view->priv->store, &iter);
+}
+
+/* Callback used as the interactive search comparison function */
+static gboolean
+name_search_cb (GtkTreeModel *model,
+ gint column,
+ const gchar *key,
+ GtkTreeIter *iter,
+ PeasUIPluginManagerView *view)
+{
+ PeasPluginInfo *info;
+ gchar *normalized_string;
+ gchar *normalized_key;
+ gchar *case_normalized_string;
+ gchar *case_normalized_key;
+ gint key_len;
+ gboolean retval;
+
+ info = peas_ui_plugin_manager_store_get_plugin (view->priv->store, iter);
+
+ if (info == NULL)
+ return FALSE;
+
+ normalized_string = g_utf8_normalize (peas_plugin_info_get_name (info), -1, G_NORMALIZE_ALL);
+ normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
+ case_normalized_string = g_utf8_casefold (normalized_string, -1);
+ case_normalized_key = g_utf8_casefold (normalized_key, -1);
+
+ key_len = strlen (case_normalized_key);
+
+ /* Oddly enough, this callback must return whether to stop the search
+ * because we found a match, not whether we actually matched.
+ */
+ retval = strncmp (case_normalized_key, case_normalized_string, key_len) != 0;
+
+ g_free (normalized_key);
+ g_free (normalized_string);
+ g_free (case_normalized_key);
+ g_free (case_normalized_string);
+
+ return retval;
+}
+
+static void
+enabled_menu_cb (GtkMenu *menu,
+ PeasUIPluginManagerView *view)
+{
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
+
+ g_return_if_fail (gtk_tree_selection_get_selected (selection, NULL, &iter));
+
+ convert_iter_to_child_iter (view, &iter);
+
+ peas_ui_plugin_manager_store_toggle_enabled (view->priv->store, &iter);
+}
+
+static void
+enable_all_menu_cb (GtkMenu *menu,
+ PeasUIPluginManagerView *view)
+{
+ peas_ui_plugin_manager_store_set_all_enabled (view->priv->store, TRUE);
+}
+
+static void
+disable_all_menu_cb (GtkMenu *menu,
+ PeasUIPluginManagerView *view)
+{
+ peas_ui_plugin_manager_store_set_all_enabled (view->priv->store, FALSE);
+}
+
+static GtkWidget *
+create_popup_menu (PeasUIPluginManagerView *view)
+{
+ PeasPluginInfo *info;
+ GtkWidget *menu;
+ GtkWidget *item;
+
+ info = peas_ui_plugin_manager_view_get_selected_plugin (view);
+
+ if (info == NULL)
+ return NULL;
+
+ menu = gtk_menu_new ();
+
+ item = gtk_check_menu_item_new_with_mnemonic (_("_Enabled"));
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
+ peas_plugin_info_is_loaded (info));
+ g_signal_connect (item, "toggled", G_CALLBACK (enabled_menu_cb), view);
+ gtk_widget_set_sensitive (item, peas_plugin_info_is_available (info) &&
+ !peas_plugin_info_is_builtin (info));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_menu_item_new_with_mnemonic (_("E_nable All"));
+ g_signal_connect (item, "activate", G_CALLBACK (enable_all_menu_cb), view);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_menu_item_new_with_mnemonic (_("_Disable All"));
+ g_signal_connect (item, "activate", G_CALLBACK (disable_all_menu_cb), view);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ g_signal_emit (view, signals[POPULATE_POPUP], 0, menu);
+
+ gtk_widget_show_all (menu);
+
+ return menu;
+}
+
+static void
+popup_menu_detach (PeasUIPluginManagerView *view,
+ GtkMenu *menu)
+{
+ view->priv->popup_menu = NULL;
+}
+
+static void
+menu_position_under_tree_view (GtkMenu *menu,
+ gint *x,
+ gint *y,
+ gboolean *push_in,
+ GtkTreeView *tree_view)
+{
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ GdkWindow *window;
+
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ window = gtk_widget_get_window (GTK_WIDGET (tree_view));
+ gdk_window_get_origin (window, x, y);
+
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter))
+ {
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GdkRectangle rect;
+
+ model = gtk_tree_view_get_model (tree_view);
+ path = gtk_tree_model_get_path (model, &iter);
+ gtk_tree_view_get_cell_area (tree_view,
+ path,
+ gtk_tree_view_get_column (tree_view, 0), /* FIXME 0 for RTL ? */
+ &rect);
+ gtk_tree_path_free (path);
+
+ *x += rect.x;
+ *y += rect.y + rect.height;
+
+ if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
+ {
+ GtkRequisition requisition;
+ gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
+ *x += rect.width - requisition.width;
+ }
+ }
+ else
+ {
+ GtkAllocation allocation;
+ gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
+ *x += allocation.x;
+ *y += allocation.y;
+
+ if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
+ {
+ GtkRequisition requisition;
+ gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
+ *x += allocation.width - requisition.width;
+ }
+ }
+
+ *push_in = TRUE;
+}
+
+static void
+show_popup_menu (GtkTreeView *tree_view,
+ PeasUIPluginManagerView *view,
+ GdkEventButton *event)
+{
+ if (view->priv->popup_menu)
+ gtk_widget_destroy (view->priv->popup_menu);
+
+ view->priv->popup_menu = create_popup_menu (view);
+
+ if (view->priv->popup_menu == NULL)
+ return;
+
+ gtk_menu_attach_to_widget (GTK_MENU (view->priv->popup_menu),
+ GTK_WIDGET (view),
+ (GtkMenuDetachFunc) popup_menu_detach);
+
+ if (event != NULL)
+ {
+ gtk_menu_popup (GTK_MENU (view->priv->popup_menu), NULL, NULL,
+ NULL, NULL, event->button, event->time);
+ }
+ else
+ {
+ gtk_menu_popup (GTK_MENU (view->priv->popup_menu), NULL, NULL,
+ (GtkMenuPositionFunc) menu_position_under_tree_view,
+ view, 0, gtk_get_current_event_time ());
+
+ gtk_menu_shell_select_first (GTK_MENU_SHELL (view->priv->popup_menu),
+ FALSE);
+ }
+}
+
+static gboolean
+button_press_event_cb (GtkWidget *tree_view,
+ GdkEventButton *event,
+ PeasUIPluginManagerView *view)
+{
+ GtkWidgetClass *widget_class;
+ gboolean handled;
+
+ if (event->type != GDK_BUTTON_PRESS || event->button != 3)
+ return FALSE;
+
+ widget_class = GTK_WIDGET_CLASS (peas_ui_plugin_manager_view_parent_class);
+
+ /* The selection must by updated */
+ handled = widget_class->button_press_event (tree_view, event);
+
+ if (!handled)
+ return FALSE;
+
+ show_popup_menu (GTK_TREE_VIEW (tree_view), view, event);
+
+ return TRUE;
+}
+
+static gboolean
+popup_menu_cb (GtkTreeView *tree_view,
+ PeasUIPluginManagerView *view)
+{
+ show_popup_menu (tree_view, view, NULL);
+
+ return TRUE;
+}
+
+static void
+peas_ui_plugin_manager_view_init (PeasUIPluginManagerView *view)
+{
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell;
+
+ view->priv = G_TYPE_INSTANCE_GET_PRIVATE (view,
+ PEAS_UI_TYPE_PLUGIN_MANAGER_VIEW,
+ PeasUIPluginManagerViewPrivate);
+
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
+
+ /* first column */
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, _("Enabled"));
+ gtk_tree_view_column_set_resizable (column, FALSE);
+
+ cell = gtk_cell_renderer_toggle_new ();
+ gtk_tree_view_column_pack_start (column, cell, FALSE);
+ g_object_set (cell, "xpad", 6, NULL);
+ gtk_tree_view_column_set_attributes (column, cell,
+ "active", PEAS_UI_PLUGIN_MANAGER_STORE_ENABLED_COLUMN,
+ "activatable", PEAS_UI_PLUGIN_MANAGER_STORE_CAN_ENABLE_COLUMN,
+ "sensitive", PEAS_UI_PLUGIN_MANAGER_STORE_CAN_ENABLE_COLUMN,
+ "visible", PEAS_UI_PLUGIN_MANAGER_STORE_CAN_ENABLE_COLUMN,
+ NULL);
+ g_signal_connect (cell,
+ "toggled",
+ G_CALLBACK (enabled_toggled_cb),
+ view);
+
+ gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
+
+ /* second column */
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, _("Plugin"));
+ gtk_tree_view_column_set_resizable (column, FALSE);
+
+ cell = gtk_cell_renderer_pixbuf_new ();
+ gtk_tree_view_column_pack_start (column, cell, FALSE);
+ g_object_set (cell, "stock-size", GTK_ICON_SIZE_SMALL_TOOLBAR, NULL);
+ gtk_tree_view_column_set_attributes (column, cell,
+ //"sensitive", PEAS_UI_PLUGIN_MANAGER_STORE_CAN_ENABLE_COLUMN,
+ "icon-name", PEAS_UI_PLUGIN_MANAGER_STORE_ICON_COLUMN,
+ NULL);
+
+ cell = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, cell, TRUE);
+ g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+ gtk_tree_view_column_set_attributes (column, cell,
+ "sensitive", PEAS_UI_PLUGIN_MANAGER_STORE_INFO_SENSITIVE_COLUMN,
+ "markup", PEAS_UI_PLUGIN_MANAGER_STORE_INFO_COLUMN,
+ NULL);
+
+ gtk_tree_view_column_set_spacing (column, 6);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
+
+ /* Enable search for our non-string column */
+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (view),
+ PEAS_UI_PLUGIN_MANAGER_STORE_PLUGIN_COLUMN);
+ gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (view),
+ (GtkTreeViewSearchEqualFunc) name_search_cb,
+ view,
+ NULL);
+
+ gtk_widget_show (GTK_WIDGET (view));
+
+ g_signal_connect (view,
+ "row-activated",
+ G_CALLBACK (row_activated_cb),
+ view);
+ g_signal_connect (view,
+ "button-press-event",
+ G_CALLBACK (button_press_event_cb),
+ view);
+ g_signal_connect (view,
+ "popup-menu",
+ G_CALLBACK (popup_menu_cb),
+ view);
+}
+
+static void
+peas_ui_plugin_manager_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PeasUIPluginManagerView *view = PEAS_UI_PLUGIN_MANAGER_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_ENGINE:
+ view->priv->engine = g_value_get_object (value);
+ g_object_ref (view->priv->engine);
+ break;
+ case PROP_SHOW_BUILTIN:
+ peas_ui_plugin_manager_view_set_show_builtin (view,
+ g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+peas_ui_plugin_manager_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PeasUIPluginManagerView *view = PEAS_UI_PLUGIN_MANAGER_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_ENGINE:
+ g_value_set_object (value, view->priv->engine);
+ break;
+ case PROP_SHOW_BUILTIN:
+ g_value_set_boolean (value,
+ peas_ui_plugin_manager_view_get_show_builtin (view));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+peas_ui_plugin_manager_view_constructed (GObject *object)
+{
+ PeasUIPluginManagerView *view = PEAS_UI_PLUGIN_MANAGER_VIEW (object);
+
+ view->priv->store = peas_ui_plugin_manager_store_new (view->priv->engine);
+
+ /* Properly set the model */
+ view->priv->show_builtin = TRUE;
+ peas_ui_plugin_manager_view_set_show_builtin (view, FALSE);
+
+ g_signal_connect (view->priv->engine,
+ "notify::plugin-list",
+ G_CALLBACK (plugin_list_changed_cb),
+ view);
+
+ if (G_OBJECT_CLASS (peas_ui_plugin_manager_view_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (peas_ui_plugin_manager_view_parent_class)->constructed (object);
+}
+
+static void
+peas_ui_plugin_manager_view_dispose (GObject *object)
+{
+ PeasUIPluginManagerView *view = PEAS_UI_PLUGIN_MANAGER_VIEW (object);
+
+ if (view->priv->popup_menu != NULL)
+ {
+ gtk_widget_destroy (view->priv->popup_menu);
+ view->priv->popup_menu = NULL;
+ }
+
+ if (view->priv->store != NULL)
+ {
+ g_object_unref (view->priv->store);
+ view->priv->store = NULL;
+ }
+
+ if (view->priv->engine != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (view->priv->engine,
+ plugin_list_changed_cb,
+ view);
+
+ g_object_unref (view->priv->engine);
+ view->priv->engine = NULL;
+ }
+
+ G_OBJECT_CLASS (peas_ui_plugin_manager_view_parent_class)->dispose (object);
+}
+
+static void
+peas_ui_plugin_manager_view_class_init (PeasUIPluginManagerViewClass *klass)
+{
+ GType the_type = G_TYPE_FROM_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = peas_ui_plugin_manager_view_set_property;
+ object_class->get_property = peas_ui_plugin_manager_view_get_property;
+ object_class->constructed = peas_ui_plugin_manager_view_constructed;
+ object_class->dispose = peas_ui_plugin_manager_view_dispose;
+
+ /**
+ * PeasUIPLuginManagerView:engine:
+ *
+ * The #PeasEngine this view is attached to.
+ */
+ g_object_class_install_property (object_class,
+ PROP_ENGINE,
+ g_param_spec_object ("engine",
+ "engine",
+ "The PeasEngine this view is attached to",
+ PEAS_TYPE_ENGINE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * PeasUIPLuginManagerView:show-builtin:
+ *
+ * If builtin plugins should be shown.
+ */
+ g_object_class_install_property (object_class,
+ PROP_ENGINE,
+ g_param_spec_boolean ("show-builtin",
+ "show-builtin",
+ "If builtin plugins should be shown",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * PeasUIPluginManagerView::populate-popup:
+ * @view: A #PeasUIPluginManagerView.
+ * @menu: A #GtkMenu.
+ *
+ * The populate-popup signal is emitted before showing the context
+ * menu of the view. If you need to add items to the context menu,
+ * connect to this signal and add your menuitems to the @menu.
+ */
+ signals[POPULATE_POPUP] =
+ g_signal_new ("populate-popup",
+ the_type,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PeasUIPluginManagerViewClass, populate_popup),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ GTK_TYPE_MENU);
+
+ g_type_class_add_private (object_class, sizeof (PeasUIPluginManagerViewPrivate));
+}
+
+/**
+ * peas_ui_plugin_manager_view_new:
+ * @engine: A #PeasEngine.
+ *
+ * Creates a new plugin manager view for the given #PeasEngine.
+ *
+ * Returns: the new #PeasUIPluginManagerView.
+ */
+GtkWidget *
+peas_ui_plugin_manager_view_new (PeasEngine *engine)
+{
+ g_return_val_if_fail (PEAS_IS_ENGINE (engine), NULL);
+
+ return GTK_WIDGET (g_object_new (PEAS_UI_TYPE_PLUGIN_MANAGER_VIEW,
+ "engine", engine,
+ NULL));
+}
+
+/**
+ * peas_ui_plugin_manager_view_set_show_builtin:
+ * @view: A #PeasUIPluginManagerView.
+ * @show_builtin: If builtin plugins should be shown.
+ *
+ * Sets if builtin plugins should be shown.
+ */
+void
+peas_ui_plugin_manager_view_set_show_builtin (PeasUIPluginManagerView *view,
+ gboolean show_builtin)
+{
+ GtkTreeIter iter;
+ gboolean iter_set;
+
+ g_return_if_fail (PEAS_UI_IS_PLUGIN_MANAGER_VIEW (view));
+
+ show_builtin = (show_builtin != FALSE);
+
+ if (view->priv->show_builtin == show_builtin)
+ return;
+
+ /* We must get the selected iter before setting if builtin
+ plugins should be shown so the proper model is set */
+ iter_set = peas_ui_plugin_manager_view_get_selected_iter (view, &iter);
+
+ view->priv->show_builtin = show_builtin;
+
+ if (show_builtin == TRUE)
+ {
+ gtk_tree_view_set_model (GTK_TREE_VIEW (view),
+ GTK_TREE_MODEL (view->priv->store));
+ }
+ else
+ {
+ GtkTreeModel *model;
+
+ model = gtk_tree_model_filter_new (GTK_TREE_MODEL (view->priv->store), NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model),
+ (GtkTreeModelFilterVisibleFunc) filter_builtins_visible,
+ view,
+ NULL);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (view), model);
+
+ g_object_unref (model);
+ }
+
+ if (iter_set)
+ peas_ui_plugin_manager_view_set_selected_iter (view, &iter);
+}
+
+/**
+ * peas_ui_plugin_manager_view_get_show_builtin:
+ * @view: A #PeasUIPluginManagerView.
+ *
+ * Returns if builtin plugins should be shown.
+ *
+ * Returns: if builtin plugins should be shown.
+ */
+gboolean
+peas_ui_plugin_manager_view_get_show_builtin (PeasUIPluginManagerView *view)
+{
+ g_return_val_if_fail (PEAS_UI_IS_PLUGIN_MANAGER_VIEW (view), FALSE);
+
+ return view->priv->show_builtin;
+}
+
+/**
+ * peas_ui_plugin_manager_view_set_selected_iter:
+ * @view: A #PeasUIPluginManagerView.
+ * @iter: A #GtkTreeIter.
+ *
+ * Selects @iter.
+ */
+void
+peas_ui_plugin_manager_view_set_selected_iter (PeasUIPluginManagerView *view,
+ GtkTreeIter *iter)
+{
+ GtkTreeSelection *selection;
+
+ g_return_if_fail (PEAS_UI_IS_PLUGIN_MANAGER_VIEW (view));
+ g_return_if_fail (iter != NULL);
+
+ if (!convert_child_iter_to_iter (view, iter))
+ return;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
+ gtk_tree_selection_select_iter (selection, iter);
+}
+
+/**
+ * peas_ui_plugin_manager_view_get_selected_iter:
+ * @view: A #PeasUIPluginManagerView.
+ * @iter: A #GtkTreeIter.
+ *
+ * Returns if @iter was set to the selected plugin.
+ *
+ * Returns: if @iter was set.
+ */
+gboolean
+peas_ui_plugin_manager_view_get_selected_iter (PeasUIPluginManagerView *view,
+ GtkTreeIter *iter)
+{
+ GtkTreeSelection *selection;
+
+ g_return_val_if_fail (PEAS_UI_IS_PLUGIN_MANAGER_VIEW (view), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
+
+ if (!gtk_tree_selection_get_selected (selection, NULL, iter))
+ return FALSE;
+
+ convert_iter_to_child_iter (view, iter);
+
+ return TRUE;
+}
+
+/**
+ * peas_ui_plugin_manager_view_set_selected_plugin:
+ * @view: A #PeasUIPluginManagerView.
+ * @info: A #PeasPluginInfo.
+ *
+ * Selects the given plugin.
+ */
+void
+peas_ui_plugin_manager_view_set_selected_plugin (PeasUIPluginManagerView *view,
+ PeasPluginInfo *info)
+{
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+
+ g_return_if_fail (PEAS_UI_IS_PLUGIN_MANAGER_VIEW (view));
+ g_return_if_fail (info != NULL);
+
+ g_return_if_fail (peas_ui_plugin_manager_store_get_iter_from_plugin (view->priv->store,
+ &iter, info));
+
+ if (!convert_child_iter_to_iter (view, &iter))
+ return;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
+ gtk_tree_selection_select_iter (selection, &iter);
+}
+
+/**
+ * peas_ui_plugin_manager_view_get_selected_plugin:
+ * @view: A #PeasUIPluginManagerView.
+ *
+ * Returns the currently selected plugin, or %NULL if a plugin is not selected.
+ *
+ * Returns: the selected plugin.
+ */
+PeasPluginInfo *
+peas_ui_plugin_manager_view_get_selected_plugin (PeasUIPluginManagerView *view)
+{
+ GtkTreeIter iter;
+ PeasPluginInfo *info = NULL;
+
+ g_return_val_if_fail (PEAS_UI_IS_PLUGIN_MANAGER_VIEW (view), NULL);
+
+ if (peas_ui_plugin_manager_view_get_selected_iter (view, &iter))
+ info = peas_ui_plugin_manager_store_get_plugin (view->priv->store, &iter);
+
+ return info;
+}
diff --git a/libpeasui/peas-ui-plugin-manager-view.h b/libpeasui/peas-ui-plugin-manager-view.h
new file mode 100644
index 0000000..414e2a4
--- /dev/null
+++ b/libpeasui/peas-ui-plugin-manager-view.h
@@ -0,0 +1,79 @@
+/*
+ * peas-plugin-manager-view.h
+ * This file is part of libpeas
+ *
+ * Copyright (C) 2002 Paolo Maggi and James Willcox
+ * Copyright (C) 2003-2006 Paolo Maggi, Paolo Borelli
+ * Copyright (C) 2007-2009 Paolo Maggi, Paolo Borelli, Steve Frécinaux
+ * Copyright (C) 2010 Garrett Regier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PEAS_UI_PLUGIN_MANAGER_VIEW_H__
+#define __PEAS_UI_PLUGIN_MANAGER_VIEW_H__
+
+#include <gtk/gtk.h>
+#include <libpeas/peas-engine.h>
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define PEAS_UI_TYPE_PLUGIN_MANAGER_VIEW (peas_ui_plugin_manager_view_get_type())
+#define PEAS_UI_PLUGIN_MANAGER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PEAS_UI_TYPE_PLUGIN_MANAGER_VIEW, PeasUIPluginManagerView))
+#define PEAS_UI_PLUGIN_MANAGER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PEAS_UI_TYPE_PLUGIN_MANAGER_VIEW, PeasUIPluginManagerViewClass))
+#define PEAS_UI_IS_PLUGIN_MANAGER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PEAS_UI_TYPE_PLUGIN_MANAGER_VIEW))
+#define PEAS_UI_IS_PLUGIN_MANAGER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PEAS_UI_TYPE_PLUGIN_MANAGER_VIEW))
+#define PEAS_UI_PLUGIN_MANAGER_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PEAS_UI_TYPE_PLUGIN_MANAGER_VIEW, PeasUIPluginManagerViewClass))
+
+typedef struct _PeasUIPluginManagerView PeasUIPluginManagerView;
+typedef struct _PeasUIPluginManagerViewClass PeasUIPluginManagerViewClass;
+typedef struct _PeasUIPluginManagerViewPrivate PeasUIPluginManagerViewPrivate;
+
+struct _PeasUIPluginManagerView {
+ GtkTreeView parent;
+
+ /*< private > */
+ PeasUIPluginManagerViewPrivate *priv;
+};
+
+struct _PeasUIPluginManagerViewClass {
+ GtkTreeViewClass parent_class;
+
+ void (*populate_popup) (PeasUIPluginManagerView *view,
+ GtkMenu *menu);
+};
+
+GType peas_ui_plugin_manager_view_get_type (void) G_GNUC_CONST;
+GtkWidget *peas_ui_plugin_manager_view_new (PeasEngine *engine);
+
+void peas_ui_plugin_manager_view_set_show_builtin (PeasUIPluginManagerView *view,
+ gboolean show_builtin);
+gboolean peas_ui_plugin_manager_view_get_show_builtin (PeasUIPluginManagerView *view);
+
+void peas_ui_plugin_manager_view_set_selected_iter (PeasUIPluginManagerView *view,
+ GtkTreeIter *iter);
+gboolean peas_ui_plugin_manager_view_get_selected_iter (PeasUIPluginManagerView *view,
+ GtkTreeIter *iter);
+
+void peas_ui_plugin_manager_view_set_selected_plugin (PeasUIPluginManagerView *view,
+ PeasPluginInfo *info);
+PeasPluginInfo *peas_ui_plugin_manager_view_get_selected_plugin (PeasUIPluginManagerView *view);
+
+G_END_DECLS
+
+#endif /* __PEAS_UI_PLUGIN_MANAGER_VIEW_H__ */
diff --git a/libpeasui/peas-ui-plugin-manager.c b/libpeasui/peas-ui-plugin-manager.c
index be787a9..eb4ba16 100644
--- a/libpeasui/peas-ui-plugin-manager.c
+++ b/libpeasui/peas-ui-plugin-manager.c
@@ -5,6 +5,7 @@
* Copyright (C) 2002 Paolo Maggi and James Willcox
* Copyright (C) 2003-2006 Paolo Maggi, Paolo Borelli
* Copyright (C) 2007-2009 Paolo Maggi, Paolo Borelli, Steve Frécinaux
+ * Copyright (C) 2010 Garrett Regier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
@@ -28,9 +29,11 @@
#include <string.h>
#include <libpeas/peas-engine.h>
+#include <libpeas/peas-plugin-info.h>
#include <libpeas/peas-i18n.h>
#include "peas-ui-plugin-manager.h"
+#include "peas-ui-plugin-manager-view.h"
#include "peas-ui-plugin-info.h"
#include "peas-ui-configurable.h"
@@ -44,32 +47,25 @@
* <inlinegraphic fileref="peas-ui-plugin-manager.png" format="PNG" />
*
* The only thing you need to do as an application writer if you wish to use
- * the manager to configure * your plugins is to instantiate it using
+ * the manager to configure your plugins is to instantiate it using
* peas_ui_plugin_manager_new() and pack it into another widget or a window
* (as in the screenshot above).
*
**/
-#define PLUGIN_MANAGER_NAME_TITLE _("Plugin")
-#define PLUGIN_MANAGER_ACTIVE_TITLE _("Enabled")
-
-enum {
- ACTIVE_COLUMN,
- AVAILABLE_COLUMN,
- INFO_COLUMN,
- N_COLUMNS
-};
-
struct _PeasUIPluginManagerPrivate {
PeasEngine *engine;
- GtkWidget *tree;
+ GtkWidget *sw;
+ GtkWidget *view;
+
+ GtkWidget *about;
+
GtkWidget *about_button;
GtkWidget *configure_button;
- GtkWidget *about;
- GtkWidget *popup_menu;
};
+/* Properties */
enum {
PROP_0,
PROP_ENGINE
@@ -77,90 +73,37 @@ enum {
G_DEFINE_TYPE (PeasUIPluginManager, peas_ui_plugin_manager, GTK_TYPE_VBOX);
-static PeasPluginInfo *plugin_manager_get_selected_plugin (PeasUIPluginManager *pm);
-static void plugin_manager_toggle_active (PeasUIPluginManager *pm,
- GtkTreeIter *iter,
- GtkTreeModel *model);
-static void peas_ui_plugin_manager_constructed (GObject *object);
-static void peas_ui_plugin_manager_finalize (GObject *object);
-
static gboolean
plugin_is_configurable (PeasUIPluginManager *pm,
PeasPluginInfo *info)
{
+ if (info == NULL || !peas_plugin_info_is_loaded (info))
+ return FALSE;
+
return peas_engine_provides_extension (pm->priv->engine,
info,
PEAS_UI_TYPE_CONFIGURABLE);
}
static void
-peas_ui_plugin_manager_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
+update_button_sensitivity (PeasUIPluginManager *pm,
+ PeasPluginInfo *info)
{
- PeasUIPluginManager *pm = PEAS_UI_PLUGIN_MANAGER (object);
-
- switch (prop_id)
- {
- case PROP_ENGINE:
- pm->priv->engine = g_value_get_object (value);
- g_object_ref (pm->priv->engine);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
+ gtk_widget_set_sensitive (pm->priv->about_button, info != NULL);
+ gtk_widget_set_sensitive (pm->priv->configure_button,
+ plugin_is_configurable (pm, info));
}
static void
-peas_ui_plugin_manager_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- PeasUIPluginManager *pm = PEAS_UI_PLUGIN_MANAGER (object);
-
- switch (prop_id)
- {
- case PROP_ENGINE:
- g_value_set_object (value, pm->priv->engine);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-peas_ui_plugin_manager_class_init (PeasUIPluginManagerClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->set_property = peas_ui_plugin_manager_set_property;
- object_class->get_property = peas_ui_plugin_manager_get_property;
- object_class->constructed = peas_ui_plugin_manager_constructed;
- object_class->finalize = peas_ui_plugin_manager_finalize;
-
- g_object_class_install_property (object_class, PROP_ENGINE,
- g_param_spec_object ("engine",
- "engine",
- "The PeasEngine this manager is attached to",
- PEAS_TYPE_ENGINE,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-
- g_type_class_add_private (object_class, sizeof (PeasUIPluginManagerPrivate));
-}
-
-static void
-about_button_cb (GtkWidget *button,
- PeasUIPluginManager *pm)
+show_about_cb (GtkWidget *widget,
+ PeasUIPluginManager *pm)
{
+ PeasUIPluginManagerView *view;
PeasPluginInfo *info;
- info = plugin_manager_get_selected_plugin (pm);
+ view = PEAS_UI_PLUGIN_MANAGER_VIEW (pm->priv->view);
+
+ info = peas_ui_plugin_manager_view_get_selected_plugin (view);
g_return_if_fail (info != NULL);
/* if there is another about dialog already open destroy it */
@@ -194,9 +137,10 @@ about_button_cb (GtkWidget *button,
}
static void
-configure_button_cb (GtkWidget *button,
- PeasUIPluginManager *pm)
+show_configure_cb (GtkWidget *widget,
+ PeasUIPluginManager *pm)
{
+ PeasUIPluginManagerView *view = PEAS_UI_PLUGIN_MANAGER_VIEW (pm->priv->view);
PeasPluginInfo *info;
PeasExtension *exten;
GtkWindow *toplevel;
@@ -205,15 +149,15 @@ configure_button_cb (GtkWidget *button,
GtkWidget *vbox;
GtkWindowGroup *wg;
- info = plugin_manager_get_selected_plugin (pm);
+ info = peas_ui_plugin_manager_view_get_selected_plugin (view);
g_return_if_fail (info != NULL);
- exten = peas_engine_get_extension (pm->priv->engine, info, PEAS_UI_TYPE_CONFIGURABLE);
- g_return_if_fail (exten != NULL);
+ exten = peas_engine_get_extension (pm->priv->engine, info, PEAS_UI_TYPE_CONFIGURABLE);
+ g_return_if_fail (PEAS_IS_EXTENSION (exten));
peas_extension_call (exten, "create_configure_widget", &conf_widget);
-
g_object_unref (exten);
+
g_return_if_fail (GTK_IS_WIDGET (conf_widget));
g_return_if_fail (!gtk_widget_is_toplevel (conf_widget));
@@ -225,7 +169,6 @@ configure_button_cb (GtkWidget *button,
GTK_STOCK_CLOSE,
GTK_RESPONSE_CLOSE,
NULL);
- g_signal_connect (conf_dlg, "response", G_CALLBACK (gtk_widget_destroy), NULL);
vbox = gtk_dialog_get_content_area (GTK_DIALOG (conf_dlg));
gtk_box_pack_start (GTK_BOX (vbox), conf_widget, TRUE, TRUE, 0);
@@ -245,669 +188,114 @@ configure_button_cb (GtkWidget *button,
gtk_window_set_transient_for (GTK_WINDOW (conf_dlg), toplevel);
gtk_window_set_modal (GTK_WINDOW (conf_dlg), TRUE);
gtk_widget_show_all (conf_dlg);
-}
-
-static void
-plugin_manager_view_info_cell_cb (GtkTreeViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gpointer data)
-{
- PeasPluginInfo *info;
- gchar *text;
-
- g_return_if_fail (tree_model != NULL);
- g_return_if_fail (tree_column != NULL);
-
- gtk_tree_model_get (tree_model, iter, INFO_COLUMN, &info, -1);
-
- if (info == NULL)
- return;
-
- text = g_markup_printf_escaped ("<b>%s</b>\n%s",
- peas_plugin_info_get_name (info),
- peas_plugin_info_get_description (info));
- g_object_set (G_OBJECT (cell),
- "markup", text,
- "sensitive", peas_plugin_info_is_available (info),
- NULL);
-
- g_free (text);
-}
-
-static void
-plugin_manager_view_icon_cell_cb (GtkTreeViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gpointer data)
-{
- PeasPluginInfo *info;
-
- g_return_if_fail (tree_model != NULL);
- g_return_if_fail (tree_column != NULL);
- gtk_tree_model_get (tree_model, iter, INFO_COLUMN, &info, -1);
-
- if (info == NULL)
- return;
-
- g_object_set (G_OBJECT (cell),
- "icon-name", peas_ui_plugin_info_get_icon_name (info),
- "sensitive", peas_plugin_info_is_available (info),
- NULL);
+ g_signal_connect (conf_dlg,
+ "response",
+ G_CALLBACK (gtk_widget_destroy),
+ NULL);
}
-
static void
-active_toggled_cb (GtkCellRendererToggle *cell,
- gchar *path_str,
- PeasUIPluginManager *pm)
+plugin_loaded_toggled_cb (PeasEngine *engine,
+ PeasPluginInfo *info,
+ PeasUIPluginManager *pm)
{
- GtkTreeIter iter;
- GtkTreePath *path;
- GtkTreeModel *model;
-
- path = gtk_tree_path_new_from_string (path_str);
+ PeasUIPluginManagerView *view;
+ PeasPluginInfo *selected;
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
- g_return_if_fail (model != NULL);
+ view = PEAS_UI_PLUGIN_MANAGER_VIEW (pm->priv->view);
+ selected = peas_ui_plugin_manager_view_get_selected_plugin (view);
- if (gtk_tree_model_get_iter (model, &iter, path))
- plugin_manager_toggle_active (pm, &iter, model);
-
- gtk_tree_path_free (path);
+ if (selected == info)
+ update_button_sensitivity (pm, info);
}
static void
-cursor_changed_cb (GtkTreeView *view,
- PeasUIPluginManager *pm)
+selection_changed_cb (GtkTreeSelection *selection,
+ PeasUIPluginManager *pm)
{
+ PeasUIPluginManagerView *view;
PeasPluginInfo *info;
- info = plugin_manager_get_selected_plugin (pm);
+ view = PEAS_UI_PLUGIN_MANAGER_VIEW (pm->priv->view);
+ info = peas_ui_plugin_manager_view_get_selected_plugin (view);
- gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->about_button),
- info != NULL);
- gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->configure_button),
- info != NULL && plugin_is_configurable (pm, info));
+ update_button_sensitivity (pm, info);
}
static void
-row_activated_cb (GtkTreeView *tree_view,
- GtkTreePath *path,
- GtkTreeViewColumn *column,
- PeasUIPluginManager *pm)
-{
- GtkTreeIter iter;
- GtkTreeModel *model;
-
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
- g_return_if_fail (model != NULL);
-
- if (gtk_tree_model_get_iter (model, &iter, path))
- plugin_manager_toggle_active (pm, &iter, model);
-}
-
-static void
-plugin_manager_populate_lists (PeasUIPluginManager *pm)
-{
- const GList *plugins;
- GtkListStore *model;
- GtkTreeIter iter;
-
- plugins = peas_engine_get_plugin_list (pm->priv->engine);
-
- model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree)));
-
- while (plugins)
- {
- PeasPluginInfo *info;
- info = (PeasPluginInfo *) plugins->data;
-
- if (!peas_plugin_info_is_builtin (info))
- {
- gtk_list_store_append (model, &iter);
- gtk_list_store_set (model, &iter,
- ACTIVE_COLUMN, peas_plugin_info_is_loaded (info),
- AVAILABLE_COLUMN, peas_plugin_info_is_available (info),
- INFO_COLUMN, info,
- -1);
- }
-
- plugins = plugins->next;
- }
-
- if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter))
- {
- GtkTreeSelection *selection;
- PeasPluginInfo *info;
-
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
- g_return_if_fail (selection != NULL);
-
- gtk_tree_selection_select_iter (selection, &iter);
-
- gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
- INFO_COLUMN, &info, -1);
-
- gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->configure_button),
- plugin_is_configurable (pm, info));
- }
-}
-
-static gboolean
-plugin_manager_set_active (PeasUIPluginManager *pm,
- GtkTreeIter *iter,
- GtkTreeModel *model,
- gboolean active)
+cursor_changed_cb (GtkTreeView *tree_view,
+ PeasUIPluginManager *pm)
{
+ PeasUIPluginManagerView *view;
PeasPluginInfo *info;
- gboolean res = TRUE;
- gtk_tree_model_get (model, iter, INFO_COLUMN, &info, -1);
- g_return_val_if_fail (info != NULL, FALSE);
+ view = PEAS_UI_PLUGIN_MANAGER_VIEW (pm->priv->view);
+ info = peas_ui_plugin_manager_view_get_selected_plugin (view);
- if (active)
- {
- /* load the plugin */
- if (!peas_engine_load_plugin (pm->priv->engine, info))
- res = FALSE;
- }
- else
- {
- /* unload the plugin */
- if (!peas_engine_unload_plugin (pm->priv->engine, info))
- res = FALSE;
- }
-
- /* cause the configure button sensitivity to be updated */
- cursor_changed_cb (GTK_TREE_VIEW (pm->priv->tree), pm);
-
- return res;
+ update_button_sensitivity (pm, info);
}
static void
-plugin_manager_toggle_active (PeasUIPluginManager *pm,
- GtkTreeIter *iter,
- GtkTreeModel *model)
-{
- gboolean active;
-
- gtk_tree_model_get (model, iter, ACTIVE_COLUMN, &active, -1);
-
- active ^= 1;
-
- plugin_manager_set_active (pm, iter, model, active);
-}
-
-static PeasPluginInfo *
-plugin_manager_get_selected_plugin (PeasUIPluginManager *pm)
-{
- PeasPluginInfo *info = NULL;
- GtkTreeModel *model;
- GtkTreeIter iter;
- GtkTreeSelection *selection;
-
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
- g_return_val_if_fail (model != NULL, NULL);
-
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
- g_return_val_if_fail (selection != NULL, NULL);
-
- if (gtk_tree_selection_get_selected (selection, NULL, &iter))
- gtk_tree_model_get (model, &iter, INFO_COLUMN, &info, -1);
-
- return info;
-}
-
-static void
-plugin_manager_set_active_all (PeasUIPluginManager *pm,
- gboolean active)
-{
- GtkTreeModel *model;
- GtkTreeIter iter;
-
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
- g_return_if_fail (model != NULL);
-
- if (!gtk_tree_model_get_iter_first (model, &iter))
- return;
-
- do
- plugin_manager_set_active (pm, &iter, model, active);
- while (gtk_tree_model_iter_next (model, &iter));
-}
-
-/* Callback used as the interactive search comparison function */
-static gboolean
-name_search_cb (GtkTreeModel *model,
- gint column,
- const gchar *key,
- GtkTreeIter *iter,
- gpointer data)
+populate_popup_cb (PeasUIPluginManagerView *view,
+ GtkMenu *menu,
+ PeasUIPluginManager *pm)
{
PeasPluginInfo *info;
- gchar *normalized_string;
- gchar *normalized_key;
- gchar *case_normalized_string;
- gchar *case_normalized_key;
- gint key_len;
- gboolean retval;
-
- gtk_tree_model_get (model, iter, INFO_COLUMN, &info, -1);
- if (!info)
- return FALSE;
-
- normalized_string = g_utf8_normalize (peas_plugin_info_get_name (info), -1, G_NORMALIZE_ALL);
- normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
- case_normalized_string = g_utf8_casefold (normalized_string, -1);
- case_normalized_key = g_utf8_casefold (normalized_key, -1);
-
- key_len = strlen (case_normalized_key);
-
- /* Oddly enough, this callback must return whether to stop the search
- * because we found a match, not whether we actually matched.
- */
- retval = strncmp (case_normalized_key, case_normalized_string, key_len) != 0;
-
- g_free (normalized_key);
- g_free (normalized_string);
- g_free (case_normalized_key);
- g_free (case_normalized_string);
-
- return retval;
-}
-
-static void
-enable_plugin_menu_cb (GtkMenu *menu,
- PeasUIPluginManager *pm)
-{
- GtkTreeModel *model;
- GtkTreeIter iter;
- GtkTreeSelection *selection;
-
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
- g_return_if_fail (model != NULL);
-
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
- g_return_if_fail (selection != NULL);
-
- if (gtk_tree_selection_get_selected (selection, NULL, &iter))
- plugin_manager_toggle_active (pm, &iter, model);
-}
-
-static void
-enable_all_menu_cb (GtkMenu *menu,
- PeasUIPluginManager *pm)
-{
- plugin_manager_set_active_all (pm, TRUE);
-}
-
-static void
-disable_all_menu_cb (GtkMenu *menu,
- PeasUIPluginManager *pm)
-{
- plugin_manager_set_active_all (pm, FALSE);
-}
-
-static GtkWidget *
-create_tree_popup_menu (PeasUIPluginManager *pm)
-{
- GtkWidget *menu;
GtkWidget *item;
GtkWidget *image;
- PeasPluginInfo *info;
- info = plugin_manager_get_selected_plugin (pm);
+ info = peas_ui_plugin_manager_view_get_selected_plugin (view);
if (info == NULL)
- return NULL;
-
- menu = gtk_menu_new ();
-
- item = gtk_image_menu_item_new_with_mnemonic (_("_About"));
- image = gtk_image_new_from_stock (GTK_STOCK_ABOUT, GTK_ICON_SIZE_MENU);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
- g_signal_connect (item, "activate", G_CALLBACK (about_button_cb), pm);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ return;
item = gtk_image_menu_item_new_with_mnemonic (_("C_onfigure"));
image = gtk_image_new_from_stock (GTK_STOCK_PREFERENCES,
GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
- g_signal_connect (item, "activate", G_CALLBACK (configure_button_cb), pm);
+ g_signal_connect (item, "activate", G_CALLBACK (show_configure_cb), pm);
gtk_widget_set_sensitive (item, plugin_is_configurable (pm, info));
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-
- item = gtk_check_menu_item_new_with_mnemonic (_("A_ctivate"));
- gtk_widget_set_sensitive (item, peas_plugin_info_is_available (info));
- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
- peas_plugin_info_is_loaded (info));
- g_signal_connect (item, "toggled", G_CALLBACK (enable_plugin_menu_cb), pm);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-
- item = gtk_separator_menu_item_new ();
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-
- item = gtk_menu_item_new_with_mnemonic (_("Ac_tivate All"));
- g_signal_connect (item, "activate", G_CALLBACK (enable_all_menu_cb), pm);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-
- item = gtk_menu_item_new_with_mnemonic (_("_Deactivate All"));
- g_signal_connect (item, "activate", G_CALLBACK (disable_all_menu_cb), pm);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-
- gtk_widget_show_all (menu);
-
- return menu;
-}
-
-static void
-tree_popup_menu_detach (PeasUIPluginManager *pm,
- GtkMenu *menu)
-{
- pm->priv->popup_menu = NULL;
-}
-
-static void
-menu_position_under_tree_view (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- gpointer user_data)
-{
- GtkTreeView *tree = GTK_TREE_VIEW (user_data);
- GtkTreeModel *model;
- GtkTreeSelection *selection;
- GtkTreeIter iter;
- GdkWindow *window;
+ gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
- model = gtk_tree_view_get_model (tree);
- g_return_if_fail (model != NULL);
-
- selection = gtk_tree_view_get_selection (tree);
- g_return_if_fail (selection != NULL);
-
- window = gtk_widget_get_window (GTK_WIDGET (tree));
- gdk_window_get_origin (window, x, y);
-
- if (gtk_tree_selection_get_selected (selection, NULL, &iter))
- {
- GtkTreePath *path;
- GdkRectangle rect;
-
- path = gtk_tree_model_get_path (model, &iter);
- gtk_tree_view_get_cell_area (tree,
- path,
- gtk_tree_view_get_column (tree, 0), /* FIXME 0 for RTL ? */
- &rect);
- gtk_tree_path_free (path);
-
- *x += rect.x;
- *y += rect.y + rect.height;
-
- if (gtk_widget_get_direction (GTK_WIDGET (tree)) == GTK_TEXT_DIR_RTL)
- {
- GtkRequisition requisition;
- gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
- *x += rect.width - requisition.width;
- }
- }
- else
- {
- GtkAllocation allocation;
- gtk_widget_get_allocation (GTK_WIDGET (tree), &allocation);
- *x += allocation.x;
- *y += allocation.y;
-
- if (gtk_widget_get_direction (GTK_WIDGET (tree)) == GTK_TEXT_DIR_RTL)
- {
- GtkRequisition requisition;
- gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
- *x += allocation.width - requisition.width;
- }
- }
-
- *push_in = TRUE;
-}
-
-static void
-show_tree_popup_menu (GtkTreeView *tree,
- PeasUIPluginManager *pm,
- GdkEventButton *event)
-{
- if (pm->priv->popup_menu)
- gtk_widget_destroy (pm->priv->popup_menu);
-
- pm->priv->popup_menu = create_tree_popup_menu (pm);
-
- if (pm->priv->popup_menu == NULL)
- return;
-
- gtk_menu_attach_to_widget (GTK_MENU (pm->priv->popup_menu),
- GTK_WIDGET (pm),
- (GtkMenuDetachFunc) tree_popup_menu_detach);
-
- if (event != NULL)
- {
- gtk_menu_popup (GTK_MENU (pm->priv->popup_menu), NULL, NULL,
- NULL, NULL, event->button, event->time);
- }
- else
- {
- gtk_menu_popup (GTK_MENU (pm->priv->popup_menu), NULL, NULL,
- menu_position_under_tree_view, tree,
- 0, gtk_get_current_event_time ());
-
- gtk_menu_shell_select_first (GTK_MENU_SHELL (pm->priv->popup_menu),
- FALSE);
- }
-}
-
-static gboolean
-button_press_event_cb (GtkWidget *tree,
- GdkEventButton *event,
- PeasUIPluginManager *pm)
-{
- /* We want the treeview selection to be updated before showing the menu.
- * This code is evil, thanks to Federico Mena Quintero's black magic.
- * See: http://mail.gnome.org/archives/gtk-devel-list/2006-February/msg00168.html
- * FIXME: Let's remove it asap.
- */
-
- static gboolean in_press = FALSE;
- gboolean handled;
-
- if (in_press)
- return FALSE; /* we re-entered */
-
- if (GDK_BUTTON_PRESS != event->type || 3 != event->button)
- return FALSE; /* let the normal handler run */
-
- in_press = TRUE;
- handled = gtk_widget_event (tree, (GdkEvent *) event);
- in_press = FALSE;
-
- if (!handled)
- return FALSE;
-
- /* The selection is fully updated by now */
- show_tree_popup_menu (GTK_TREE_VIEW (tree), pm, event);
- return TRUE;
-}
-
-static gboolean
-popup_menu_cb (GtkTreeView *tree,
- PeasUIPluginManager *pm)
-{
- show_tree_popup_menu (tree, pm, NULL);
- return TRUE;
-}
-
-static gint
-model_name_sort_func (GtkTreeModel *model,
- GtkTreeIter *iter1,
- GtkTreeIter *iter2,
- gpointer user_data)
-{
- PeasPluginInfo *info1, *info2;
-
- gtk_tree_model_get (model, iter1, INFO_COLUMN, &info1, -1);
- gtk_tree_model_get (model, iter2, INFO_COLUMN, &info2, -1);
-
- return g_utf8_collate (peas_plugin_info_get_name (info1),
- peas_plugin_info_get_name (info2));
-}
-
-static void
-plugin_manager_construct_tree (PeasUIPluginManager *pm)
-{
- GtkTreeViewColumn *column;
- GtkCellRenderer *cell;
- GtkListStore *model;
-
- model = gtk_list_store_new (N_COLUMNS,
- G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_POINTER);
-
- gtk_tree_view_set_model (GTK_TREE_VIEW (pm->priv->tree),
- GTK_TREE_MODEL (model));
- g_object_unref (model);
-
- gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (pm->priv->tree), TRUE);
- gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (pm->priv->tree), FALSE);
-
- /* first column */
- cell = gtk_cell_renderer_toggle_new ();
- g_object_set (cell, "xpad", 6, NULL);
- g_signal_connect (cell, "toggled", G_CALLBACK (active_toggled_cb), pm);
- column = gtk_tree_view_column_new_with_attributes (PLUGIN_MANAGER_ACTIVE_TITLE, cell,
- "active", ACTIVE_COLUMN,
- "activatable", AVAILABLE_COLUMN,
- "sensitive", AVAILABLE_COLUMN,
- NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (pm->priv->tree), column);
-
- /* second column */
- column = gtk_tree_view_column_new ();
- gtk_tree_view_column_set_title (column, PLUGIN_MANAGER_NAME_TITLE);
- gtk_tree_view_column_set_resizable (column, TRUE);
-
- cell = gtk_cell_renderer_pixbuf_new ();
- gtk_tree_view_column_pack_start (column, cell, FALSE);
- g_object_set (cell, "stock-size", GTK_ICON_SIZE_SMALL_TOOLBAR, NULL);
- gtk_tree_view_column_set_cell_data_func (column, cell,
- plugin_manager_view_icon_cell_cb,
- pm, NULL);
-
- cell = gtk_cell_renderer_text_new ();
- gtk_tree_view_column_pack_start (column, cell, TRUE);
- g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
- gtk_tree_view_column_set_cell_data_func (column, cell,
- plugin_manager_view_info_cell_cb,
- pm, NULL);
-
-
- gtk_tree_view_column_set_spacing (column, 6);
- gtk_tree_view_append_column (GTK_TREE_VIEW (pm->priv->tree), column);
-
- /* Sort on the plugin names */
- gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model),
- model_name_sort_func, NULL, NULL);
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
- GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
- GTK_SORT_ASCENDING);
-
- /* Enable search for our non-string column */
- gtk_tree_view_set_search_column (GTK_TREE_VIEW (pm->priv->tree),
- INFO_COLUMN);
- gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (pm->priv->tree),
- name_search_cb, NULL, NULL);
-
- g_signal_connect (pm->priv->tree, "cursor_changed", G_CALLBACK (cursor_changed_cb), pm);
- g_signal_connect (pm->priv->tree, "row_activated", G_CALLBACK (row_activated_cb), pm);
- g_signal_connect (pm->priv->tree, "button-press-event", G_CALLBACK (button_press_event_cb), pm);
- g_signal_connect (pm->priv->tree, "popup-menu", G_CALLBACK (popup_menu_cb), pm);
- gtk_widget_show (pm->priv->tree);
-}
-
-static void
-plugin_toggled_cb (PeasEngine *engine,
- PeasPluginInfo *info,
- PeasUIPluginManager *pm)
-{
- GtkTreeSelection *selection;
- GtkTreeModel *model;
- GtkTreeIter iter;
- gboolean info_found = FALSE;
-
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
-
- if (gtk_tree_selection_get_selected (selection, &model, &iter))
- {
- /* There is an item selected: it's probably the one we want! */
- PeasPluginInfo *tinfo;
- gtk_tree_model_get (model, &iter, INFO_COLUMN, &tinfo, -1);
- info_found = info == tinfo;
- }
-
- if (!info_found && gtk_tree_model_get_iter_first (model, &iter))
- {
- do
- {
- PeasPluginInfo *tinfo;
- gtk_tree_model_get (model, &iter, INFO_COLUMN, &tinfo, -1);
- info_found = info == tinfo;
- }
- while (!info_found && gtk_tree_model_iter_next (model, &iter));
- }
-
- if (!info_found)
- {
- g_warning ("PeasUIPluginManager: plugin '%s' not found in the tree model",
- peas_plugin_info_get_name (info));
- return;
- }
-
- gtk_list_store_set (GTK_LIST_STORE (model), &iter, ACTIVE_COLUMN,
- peas_plugin_info_is_loaded (info), -1);
+ item = gtk_image_menu_item_new_with_mnemonic (_("_About"));
+ image = gtk_image_new_from_stock (GTK_STOCK_ABOUT, GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ g_signal_connect (item, "activate", G_CALLBACK (show_about_cb), pm);
+ gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
}
static void
peas_ui_plugin_manager_init (PeasUIPluginManager *pm)
{
GtkWidget *label;
- GtkWidget *viewport;
GtkWidget *hbuttonbox;
- pm->priv = G_TYPE_INSTANCE_GET_PRIVATE (pm, PEAS_UI_TYPE_PLUGIN_MANAGER, PeasUIPluginManagerPrivate);
+ pm->priv = G_TYPE_INSTANCE_GET_PRIVATE (pm,
+ PEAS_UI_TYPE_PLUGIN_MANAGER,
+ PeasUIPluginManagerPrivate);
gtk_box_set_spacing (GTK_BOX (pm), 6);
- label = gtk_label_new_with_mnemonic (_("Active _Plugins:"));
+ gtk_widget_push_composite_child ();
+
+ label = gtk_label_new_with_mnemonic (_("_Plugins:"));
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-
gtk_box_pack_start (GTK_BOX (pm), label, FALSE, TRUE, 0);
- viewport = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (viewport),
+ pm->priv->sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (pm->priv->sw),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (viewport),
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (pm->priv->sw),
GTK_SHADOW_IN);
-
- gtk_box_pack_start (GTK_BOX (pm), viewport, TRUE, TRUE, 0);
-
- pm->priv->tree = gtk_tree_view_new ();
- gtk_container_add (GTK_CONTAINER (viewport), pm->priv->tree);
-
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), pm->priv->tree);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), pm->priv->sw);
+ gtk_box_pack_start (GTK_BOX (pm), pm->priv->sw, TRUE, TRUE, 0);
hbuttonbox = gtk_hbutton_box_new ();
- gtk_box_pack_start (GTK_BOX (pm), hbuttonbox, FALSE, FALSE, 0);
gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_END);
- gtk_box_set_spacing (GTK_BOX (hbuttonbox), 8); /* should use the default or HIG */
+ gtk_box_set_spacing (GTK_BOX (hbuttonbox), 6);
+ gtk_box_pack_start (GTK_BOX (pm), hbuttonbox, FALSE, FALSE, 0);
pm->priv->about_button = gtk_button_new_from_stock (GTK_STOCK_ABOUT);
gtk_container_add (GTK_CONTAINER (hbuttonbox), pm->priv->about_button);
@@ -915,61 +303,152 @@ peas_ui_plugin_manager_init (PeasUIPluginManager *pm)
pm->priv->configure_button = gtk_button_new_from_stock (GTK_STOCK_PREFERENCES);
gtk_container_add (GTK_CONTAINER (hbuttonbox), pm->priv->configure_button);
+ gtk_widget_pop_composite_child ();
+
/* setup a window of a sane size. */
- gtk_widget_set_size_request (GTK_WIDGET (viewport), 270, 100);
+ gtk_widget_set_size_request (GTK_WIDGET (pm->priv->sw), 270, 100);
+
+ g_signal_connect (pm->priv->about_button,
+ "clicked",
+ G_CALLBACK (show_about_cb),
+ pm);
+ g_signal_connect (pm->priv->configure_button,
+ "clicked",
+ G_CALLBACK (show_configure_cb),
+ pm);
+}
+
+static void
+peas_ui_plugin_manager_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PeasUIPluginManager *pm = PEAS_UI_PLUGIN_MANAGER (object);
- g_signal_connect (pm->priv->about_button, "clicked", G_CALLBACK (about_button_cb), pm);
- g_signal_connect (pm->priv->configure_button, "clicked", G_CALLBACK (configure_button_cb), pm);
+ switch (prop_id)
+ {
+ case PROP_ENGINE:
+ pm->priv->engine = g_value_get_object (value);
+ g_object_ref (pm->priv->engine);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
- plugin_manager_construct_tree (pm);
+static void
+peas_ui_plugin_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PeasUIPluginManager *pm = PEAS_UI_PLUGIN_MANAGER (object);
+
+ switch (prop_id)
+ {
+ case PROP_ENGINE:
+ g_value_set_object (value, pm->priv->engine);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
}
static void
peas_ui_plugin_manager_constructed (GObject *object)
{
PeasUIPluginManager *pm = PEAS_UI_PLUGIN_MANAGER (object);
+ GtkTreeSelection *selection;
- /* When we create the manager, we always rescan the plugins directory */
+ /* When we create the manager, we always rescan the plugins directory
+ Must come after the view has connected to notify::plugin-list */
peas_engine_rescan_plugins (pm->priv->engine);
- /* populate the treeview */
+ pm->priv->view = peas_ui_plugin_manager_view_new (pm->priv->engine);
+ gtk_container_add (GTK_CONTAINER (pm->priv->sw), pm->priv->view);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->view));
+
g_signal_connect_after (pm->priv->engine,
"load-plugin",
- G_CALLBACK (plugin_toggled_cb), pm);
+ G_CALLBACK (plugin_loaded_toggled_cb),
+ pm);
g_signal_connect_after (pm->priv->engine,
"unload-plugin",
- G_CALLBACK (plugin_toggled_cb), pm);
+ G_CALLBACK (plugin_loaded_toggled_cb),
+ pm);
+ g_signal_connect (selection,
+ "changed",
+ G_CALLBACK (selection_changed_cb),
+ pm);
+ g_signal_connect (pm->priv->view,
+ "cursor-changed",
+ G_CALLBACK (cursor_changed_cb),
+ pm);
+ g_signal_connect (pm->priv->view,
+ "populate-popup",
+ G_CALLBACK (populate_popup_cb),
+ pm);
+
+ /* Update the button sensitivity */
+ selection_changed_cb (selection, pm);
+
+ if (G_OBJECT_CLASS (peas_ui_plugin_manager_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (peas_ui_plugin_manager_parent_class)->constructed (object);
+}
- if (peas_engine_get_plugin_list (pm->priv->engine) != NULL)
- {
- plugin_manager_populate_lists (pm);
- }
- else
+static void
+peas_ui_plugin_manager_dispose (GObject *object)
+{
+ PeasUIPluginManager *pm = PEAS_UI_PLUGIN_MANAGER (object);
+
+ if (pm->priv->engine != NULL)
{
- gtk_widget_set_sensitive (pm->priv->about_button, FALSE);
- gtk_widget_set_sensitive (pm->priv->configure_button, FALSE);
+ g_signal_handlers_disconnect_by_func (pm->priv->engine,
+ plugin_loaded_toggled_cb,
+ pm);
+
+ g_object_unref (pm->priv->engine);
+ pm->priv->engine = NULL;
}
+
+ G_OBJECT_CLASS (peas_ui_plugin_manager_parent_class)->dispose (object);
}
static void
-peas_ui_plugin_manager_finalize (GObject *object)
+peas_ui_plugin_manager_class_init (PeasUIPluginManagerClass *klass)
{
- PeasUIPluginManager *pm = PEAS_UI_PLUGIN_MANAGER (object);
-
- g_signal_handlers_disconnect_by_func (pm->priv->engine,
- plugin_toggled_cb, pm);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
- if (pm->priv->popup_menu)
- gtk_widget_destroy (pm->priv->popup_menu);
+ object_class->set_property = peas_ui_plugin_manager_set_property;
+ object_class->get_property = peas_ui_plugin_manager_get_property;
+ object_class->constructed = peas_ui_plugin_manager_constructed;
+ object_class->dispose = peas_ui_plugin_manager_dispose;
- g_object_unref (pm->priv->engine);
+ /**
+ * PeasUIPLuginManager:engine:
+ *
+ * The #PeasEngine this manager is attached to.
+ */
+ g_object_class_install_property (object_class,
+ PROP_ENGINE,
+ g_param_spec_object ("engine",
+ "engine",
+ "The PeasEngine this manager is attached to",
+ PEAS_TYPE_ENGINE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
- G_OBJECT_CLASS (peas_ui_plugin_manager_parent_class)->finalize (object);
+ g_type_class_add_private (object_class, sizeof (PeasUIPluginManagerPrivate));
}
/**
* peas_ui_plugin_manager_new:
- * @engine: a #PeasEngine.
+ * @engine: A #PeasEngine.
*
* Creates a new plugin manager for the given #PeasEngine.
*
@@ -984,3 +463,19 @@ peas_ui_plugin_manager_new (PeasEngine *engine)
"engine", engine,
NULL));
}
+
+/**
+ * peas_ui_plugin_manager_get_view:
+ * @pm: A @PeasUIPluginManager.
+ *
+ * Returns the #PeasUIPluginManagerView of @pm.
+ *
+ * Returns: the view of @pm.
+ */
+GtkWidget *
+peas_ui_plugin_manager_get_view (PeasUIPluginManager *pm)
+{
+ g_return_val_if_fail (PEAS_UI_IS_PLUGIN_MANAGER (pm), NULL);
+
+ return pm->priv->view;
+}
diff --git a/libpeasui/peas-ui-plugin-manager.h b/libpeasui/peas-ui-plugin-manager.h
index 91e41c9..280a3e2 100644
--- a/libpeasui/peas-ui-plugin-manager.h
+++ b/libpeasui/peas-ui-plugin-manager.h
@@ -54,8 +54,10 @@ struct _PeasUIPluginManagerClass
GtkVBoxClass parent_class;
};
-GType peas_ui_plugin_manager_get_type (void) G_GNUC_CONST;
-GtkWidget *peas_ui_plugin_manager_new (PeasEngine *engine);
+GType peas_ui_plugin_manager_get_type (void) G_GNUC_CONST;
+GtkWidget *peas_ui_plugin_manager_new (PeasEngine *engine);
+
+GtkWidget *peas_ui_plugin_manager_get_view (PeasUIPluginManager *pm);
G_END_DECLS
diff --git a/libpeasui/peas-ui.h b/libpeasui/peas-ui.h
index 9192a9d..f2e7c6e 100644
--- a/libpeasui/peas-ui.h
+++ b/libpeasui/peas-ui.h
@@ -23,5 +23,6 @@
#include "peas-ui-configurable.h"
#include "peas-ui-plugin-info.h"
#include "peas-ui-plugin-manager.h"
+#include "peas-ui-plugin-manager-view.h"
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]