[evolution-data-server] Bug 332497 - Add Edit -> Available Categories
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug 332497 - Add Edit -> Available Categories
- Date: Thu, 5 May 2011 14:28:44 +0000 (UTC)
commit 11044cd0ebb4fff492a207750050111d895d3bce
Author: Dan Vrátil <dvratil redhat com>
Date: Thu May 5 10:01:43 2011 -0400
Bug 332497 - Add Edit -> Available Categories
Split ECategoriesDialog into smaller widgets:
ECategoriesEditor
ECategoriesSelector
ECategoryEditor
.../libedataserverui/libedataserverui-docs.sgml | 3 +
.../libedataserverui/libedataserverui-sections.txt | 66 ++
.../libedataserverui/libedataserverui.types | 6 +
.../libedataserverui/tmpl/e-categories-editor.sgml | 87 ++
.../tmpl/e-categories-selector.sgml | 114 +++
.../libedataserverui/tmpl/e-category-editor.sgml | 58 ++
libedataserverui/Makefile.am | 6 +
libedataserverui/e-categories-dialog.c | 823 +-------------------
libedataserverui/e-categories-editor.c | 427 ++++++++++
libedataserverui/e-categories-editor.h | 76 ++
libedataserverui/e-categories-selector.c | 570 ++++++++++++++
libedataserverui/e-categories-selector.h | 85 ++
libedataserverui/e-category-editor.c | 348 +++++++++
libedataserverui/e-category-editor.h | 69 ++
libedataserverui/e-data-server-ui-marshal.list | 1 +
15 files changed, 1953 insertions(+), 786 deletions(-)
---
diff --git a/docs/reference/libedataserverui/libedataserverui-docs.sgml b/docs/reference/libedataserverui/libedataserverui-docs.sgml
index 130697f..3242839 100644
--- a/docs/reference/libedataserverui/libedataserverui-docs.sgml
+++ b/docs/reference/libedataserverui/libedataserverui-docs.sgml
@@ -12,6 +12,9 @@
<title>Evolution-Data-Server Manual: Graphical Utilities (libedataserverui)</title>
<xi:include href="xml/e-book-auth-util.xml"/>
<xi:include href="xml/e-categories-dialog.xml"/>
+ <xi:include href="xml/e-categories-editor.xml"/>
+ <xi:include href="xml/e-categories-selector.xml"/>
+ <xi:include href="xml/e-category-editor.xml"/>
<xi:include href="xml/e-category-completion.xml"/>
<xi:include href="xml/e-cell-renderer-color.xml"/>
<xi:include href="xml/e-contact-store.xml"/>
diff --git a/docs/reference/libedataserverui/libedataserverui-sections.txt b/docs/reference/libedataserverui/libedataserverui-sections.txt
index 6165102..e703f1c 100644
--- a/docs/reference/libedataserverui/libedataserverui-sections.txt
+++ b/docs/reference/libedataserverui/libedataserverui-sections.txt
@@ -26,6 +26,52 @@ e_categories_dialog_get_type
</SECTION>
<SECTION>
+<FILE>e-categories-editor</FILE>
+<TITLE>ECategoriesEditor</TITLE>
+ECategoriesEditor
+e_categories_editor_new
+e_categories_editor_get_categories
+e_categories_editor_set_categories
+e_categories_editor_get_entry_visible
+e_categories_editor_set_entry_visible
+<SUBSECTION Standard>
+E_CATEGORIES_EDITOR
+E_IS_CATEGORIES_EDITOR
+E_TYPE_CATEGORIES_EDITOR
+E_CATEGORIES_EDITOR_CLASS
+E_IS_CATEGORIES_EDITOR_CLASS
+E_CATEGORIES_EDITOR_GET_CLASS
+ECategoriesEditorClass
+<SUBSECTION Private>
+ECategoriesEditorPrivate
+e_categories_editor_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-categories-selector</FILE>
+<TITLE>ECategoriesSelector</TITLE>
+ECategoriesSelector
+e_categories_selector_new
+e_categories_selector_get_checked
+e_categories_selector_set_checked
+e_categories_selector_get_items_checkable
+e_categories_selector_set_items_checkable
+e_categories_selector_delete_selection
+e_categories_selector_get_selected
+<SUBSECTION Standard>
+E_CATEGORIES_SELECTOR
+E_IS_CATEGORIES_SELECTOR
+E_TYPE_CATEGORIES_SELECTOR
+E_CATEGORIES_SELECTOR_CLASS
+E_IS_CATEGORIES_SELECTOR_CLASS
+E_CATEGORIES_SELECTOR_GET_CLASS
+ECategoriesSelectorClass
+<SUBSECTION Private>
+ECategoriesSelectorPrivate
+e_categories_selector_get_type
+</SECTION>
+
+<SECTION>
<FILE>e-category-completion</FILE>
<TITLE>ECategoryCompletion</TITLE>
ECategoryCompletion
@@ -44,6 +90,26 @@ e_category_completion_get_type
</SECTION>
<SECTION>
+<FILE>e-category-editor</FILE>
+<TITLE>ECategoryEditor</TITLE>
+ECategoryEditor
+e_category_editor_new
+e_category_editor_create_category
+e_category_editor_edit_category
+<SUBSECTION Standard>
+E_CATEGORY_EDITOR
+E_IS_CATEGORY_EDITOR
+E_TYPE_CATEGORY_EDITOR
+E_CATEGORY_EDITOR_CLASS
+E_IS_CATEGORY_EDITOR_CLASS
+E_CATEGORY_EDITOR_GET_CLASS
+ECategoryEditorClass
+<SUBSECTION Private>
+ECategoryEditorPrivate
+e_category_editor_get_type
+</SECTION>
+
+<SECTION>
<FILE>e-cell-renderer-color</FILE>
<TITLE>ECellRendererColor</TITLE>
ECellRendererColor
diff --git a/docs/reference/libedataserverui/libedataserverui.types b/docs/reference/libedataserverui/libedataserverui.types
index 04eae99..0041710 100644
--- a/docs/reference/libedataserverui/libedataserverui.types
+++ b/docs/reference/libedataserverui/libedataserverui.types
@@ -1,4 +1,7 @@
#include <libedataserverui/e-categories-dialog.h>
+#include <libedataserverui/e-categories-editor.h>
+#include <libedataserverui/e-categories-selector.h>
+#include <libedataserverui/e-category-editor.h>
#include <libedataserverui/e-contact-store.h>
#include <libedataserverui/e-destination-store.h>
#include <libedataserverui/e-name-selector.h>
@@ -12,6 +15,9 @@
#include <libedataserverui/e-tree-model-generator.h>
e_categories_dialog_get_type
+e_categories_editor_get_type
+e_categories_selector_get_type
+e_category_editor_get_type
e_contact_store_get_type
e_destination_store_get_type
e_name_selector_get_type
diff --git a/docs/reference/libedataserverui/tmpl/e-categories-editor.sgml b/docs/reference/libedataserverui/tmpl/e-categories-editor.sgml
new file mode 100644
index 0000000..1671364
--- /dev/null
+++ b/docs/reference/libedataserverui/tmpl/e-categories-editor.sgml
@@ -0,0 +1,87 @@
+<!-- ##### SECTION Title ##### -->
+ECategoriesEditor
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ECategoriesEditor ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SIGNAL ECategoriesEditor::entry-changed ##### -->
+<para>
+
+</para>
+
+ ecategorieseditor: the object which received the signal.
+
+<!-- ##### ARG ECategoriesEditor:entry-visible ##### -->
+<para>
+
+</para>
+
+<!-- ##### FUNCTION e_categories_editor_new ##### -->
+<para>
+
+</para>
+
+ void:
+ Returns:
+
+
+<!-- ##### FUNCTION e_categories_editor_get_categories ##### -->
+<para>
+
+</para>
+
+ editor:
+ Returns:
+
+
+<!-- ##### FUNCTION e_categories_editor_set_categories ##### -->
+<para>
+
+</para>
+
+ editor:
+ categories:
+
+
+<!-- ##### FUNCTION e_categories_editor_get_entry_visible ##### -->
+<para>
+
+</para>
+
+ editor:
+ Returns:
+
+
+<!-- ##### FUNCTION e_categories_editor_set_entry_visible ##### -->
+<para>
+
+</para>
+
+ editor:
+ entry_visible:
+
+
diff --git a/docs/reference/libedataserverui/tmpl/e-categories-selector.sgml b/docs/reference/libedataserverui/tmpl/e-categories-selector.sgml
new file mode 100644
index 0000000..f0c1dc2
--- /dev/null
+++ b/docs/reference/libedataserverui/tmpl/e-categories-selector.sgml
@@ -0,0 +1,114 @@
+<!-- ##### SECTION Title ##### -->
+ECategoriesSelector
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ECategoriesSelector ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SIGNAL ECategoriesSelector::category-checked ##### -->
+<para>
+
+</para>
+
+ ecategoriesselector: the object which received the signal.
+ arg1:
+ arg2:
+
+<!-- ##### SIGNAL ECategoriesSelector::selection-changed ##### -->
+<para>
+
+</para>
+
+ ecategoriesselector: the object which received the signal.
+ arg1:
+
+<!-- ##### ARG ECategoriesSelector:items-checkable ##### -->
+<para>
+
+</para>
+
+<!-- ##### FUNCTION e_categories_selector_new ##### -->
+<para>
+
+</para>
+
+ void:
+ Returns:
+
+
+<!-- ##### FUNCTION e_categories_selector_get_checked ##### -->
+<para>
+
+</para>
+
+ selector:
+ Returns:
+
+
+<!-- ##### FUNCTION e_categories_selector_set_checked ##### -->
+<para>
+
+</para>
+
+ selector:
+ categories:
+
+
+<!-- ##### FUNCTION e_categories_selector_get_items_checkable ##### -->
+<para>
+
+</para>
+
+ selector:
+ Returns:
+
+
+<!-- ##### FUNCTION e_categories_selector_set_items_checkable ##### -->
+<para>
+
+</para>
+
+ selectr:
+ checkable:
+
+
+<!-- ##### FUNCTION e_categories_selector_delete_selection ##### -->
+<para>
+
+</para>
+
+ selector:
+
+
+<!-- ##### FUNCTION e_categories_selector_get_selected ##### -->
+<para>
+
+</para>
+
+ selector:
+ Returns:
+
+
diff --git a/docs/reference/libedataserverui/tmpl/e-category-editor.sgml b/docs/reference/libedataserverui/tmpl/e-category-editor.sgml
new file mode 100644
index 0000000..8ef7cf3
--- /dev/null
+++ b/docs/reference/libedataserverui/tmpl/e-category-editor.sgml
@@ -0,0 +1,58 @@
+<!-- ##### SECTION Title ##### -->
+ECategoryEditor
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ECategoryEditor ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION e_category_editor_new ##### -->
+<para>
+
+</para>
+
+ void:
+ Returns:
+
+
+<!-- ##### FUNCTION e_category_editor_create_category ##### -->
+<para>
+
+</para>
+
+ editor:
+ Returns:
+
+
+<!-- ##### FUNCTION e_category_editor_edit_category ##### -->
+<para>
+
+</para>
+
+ editor:
+ category:
+ Returns:
+
+
diff --git a/libedataserverui/Makefile.am b/libedataserverui/Makefile.am
index e20028d..af00b8a 100644
--- a/libedataserverui/Makefile.am
+++ b/libedataserverui/Makefile.am
@@ -17,7 +17,10 @@ lib_LTLIBRARIES = libedataserverui-3.0.la
libedataserveruiinclude_HEADERS = \
e-categories-dialog.h \
+ e-categories-editor.h \
+ e-categories-selector.h \
e-category-completion.h \
+ e-category-editor.h \
e-destination-store.h \
e-book-auth-util.h \
e-contact-store.h \
@@ -44,7 +47,10 @@ endif
libedataserverui_3_0_la_SOURCES = \
$(MARSHAL_GENERATED) \
e-categories-dialog.c \
+ e-categories-editor.c \
+ e-categories-selector.c \
e-category-completion.c \
+ e-category-editor.c \
e-destination-store.c \
e-book-auth-util.c \
e-contact-store.c \
diff --git a/libedataserverui/e-categories-dialog.c b/libedataserverui/e-categories-dialog.c
index 6e3b360..0be5698 100644
--- a/libedataserverui/e-categories-dialog.c
+++ b/libedataserverui/e-categories-dialog.c
@@ -28,756 +28,63 @@
#include "libedataserver/e-categories.h"
#include "libedataserver/libedataserver-private.h"
#include "e-categories-dialog.h"
+#include "e-categories-editor.h"
+#include "e-categories-selector.h"
#include "e-category-completion.h"
+#include "e-category-editor.h"
G_DEFINE_TYPE (ECategoriesDialog, e_categories_dialog, GTK_TYPE_DIALOG)
struct _ECategoriesDialogPrivate {
- GtkWidget *categories_entry;
- GtkWidget *categories_list;
- GtkWidget *new_button;
- GtkWidget *edit_button;
- GtkWidget *delete_button;
-
- GHashTable *selected_categories;
-
- guint ignore_category_changes : 1;
-};
-
-enum {
- COLUMN_ACTIVE,
- COLUMN_ICON,
- COLUMN_CATEGORY,
- N_COLUMNS
+ GtkWidget *categories_editor;
};
-static gpointer parent_class;
-
-/* Category properties dialog */
-
-typedef struct {
- ECategoriesDialog *parent;
- GtkWidget *the_dialog;
- GtkWidget *category_name;
- GtkWidget *category_icon;
-} CategoryPropertiesDialog;
-
-static void
-update_preview (GtkFileChooser *chooser, gpointer user_data)
-{
- GtkImage *image;
- gchar *filename;
-
- g_return_if_fail (chooser != NULL);
-
- image = GTK_IMAGE (gtk_file_chooser_get_preview_widget (chooser));
- g_return_if_fail (image != NULL);
-
- filename = gtk_file_chooser_get_preview_filename (chooser);
-
- gtk_image_set_from_file (image, filename);
- gtk_file_chooser_set_preview_widget_active (chooser, filename != NULL);
-
- g_free (filename);
-}
-
-static void
-file_chooser_response (GtkDialog *dialog, gint response_id, GtkFileChooser *button)
-{
- g_return_if_fail (button != NULL);
-
- if (response_id == GTK_RESPONSE_NO) {
- gtk_file_chooser_unselect_all (button);
- }
-}
-
-static void
-category_name_changed_cb (GtkEntry *category_name_entry, CategoryPropertiesDialog *prop_dialog)
-{
- gchar *name;
-
- g_return_if_fail (prop_dialog != NULL);
- g_return_if_fail (prop_dialog->the_dialog != NULL);
- g_return_if_fail (category_name_entry != NULL);
-
- name = g_strdup (gtk_entry_get_text (category_name_entry));
- if (name)
- name = g_strstrip (name);
-
- gtk_dialog_set_response_sensitive (GTK_DIALOG (prop_dialog->the_dialog), GTK_RESPONSE_OK, name && *name);
-
- g_free (name);
-}
-
-static CategoryPropertiesDialog *
-create_properties_dialog (ECategoriesDialog *parent)
-{
- CategoryPropertiesDialog *prop_dialog;
- GtkWidget *properties_dialog;
- GtkWidget *dialog_content;
- GtkWidget *dialog_action_area;
- GtkWidget *table_category_properties;
- GtkWidget *label4;
- GtkWidget *label6;
- GtkWidget *category_name;
- GtkWidget *cancelbutton1;
- GtkWidget *okbutton1;
-
- properties_dialog = gtk_dialog_new ();
- gtk_window_set_title (GTK_WINDOW (properties_dialog), _("Category Properties"));
- gtk_window_set_type_hint (GTK_WINDOW (properties_dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
-
- dialog_content = gtk_dialog_get_content_area (GTK_DIALOG (properties_dialog));
-
- table_category_properties = gtk_table_new (3, 2, FALSE);
- gtk_box_pack_start (GTK_BOX (dialog_content), table_category_properties, TRUE, TRUE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (table_category_properties), 12);
- gtk_table_set_row_spacings (GTK_TABLE (table_category_properties), 6);
- gtk_table_set_col_spacings (GTK_TABLE (table_category_properties), 6);
-
- label4 = gtk_label_new_with_mnemonic (_("Category _Name"));
- gtk_table_attach (GTK_TABLE (table_category_properties), label4, 0, 1, 0, 1,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
- gtk_misc_set_alignment (GTK_MISC (label4), 0, 0.5);
-
- label6 = gtk_label_new_with_mnemonic (_("Category _Icon"));
- gtk_table_attach (GTK_TABLE (table_category_properties), label6, 0, 1, 2, 3,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
- gtk_misc_set_alignment (GTK_MISC (label6), 0, 0.5);
-
- category_name = gtk_entry_new ();
- gtk_table_attach (GTK_TABLE (table_category_properties), category_name, 1, 2, 0, 1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- dialog_action_area = gtk_dialog_get_action_area (GTK_DIALOG (properties_dialog));
- gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area), GTK_BUTTONBOX_END);
-
- cancelbutton1 = gtk_button_new_from_stock ("gtk-cancel");
- gtk_dialog_add_action_widget (GTK_DIALOG (properties_dialog), cancelbutton1, GTK_RESPONSE_CANCEL);
- gtk_widget_set_can_default (cancelbutton1, TRUE);
-
- okbutton1 = gtk_button_new_from_stock ("gtk-ok");
- gtk_dialog_add_action_widget (GTK_DIALOG (properties_dialog), okbutton1, GTK_RESPONSE_OK);
- gtk_widget_set_can_default (okbutton1, TRUE);
-
- gtk_label_set_mnemonic_widget (GTK_LABEL (label4), category_name);
-
- gtk_widget_show_all (dialog_content);
-
- prop_dialog = g_new0 (CategoryPropertiesDialog, 1);
- prop_dialog->parent = parent;
-
- prop_dialog->the_dialog = properties_dialog;
- gtk_window_set_transient_for (GTK_WINDOW (prop_dialog->the_dialog), GTK_WINDOW (parent));
-
- prop_dialog->category_name = category_name;
- g_signal_connect (prop_dialog->category_name, "changed", G_CALLBACK (category_name_changed_cb), prop_dialog);
- category_name_changed_cb (GTK_ENTRY (prop_dialog->category_name), prop_dialog);
-
- if (table_category_properties) {
- GtkFileChooser *chooser;
- GtkWidget *dialog, *button;
- GtkWidget *image = gtk_image_new ();
-
- dialog = gtk_file_chooser_dialog_new ( _("Category Icon"),
- NULL,
- GTK_FILE_CHOOSER_ACTION_OPEN,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- NULL);
-
- button = gtk_button_new_with_mnemonic (_("_No Image"));
- gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_BUTTON));
- gtk_widget_show (button);
- gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_NO);
- gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT);
- button = NULL;
-
- chooser = GTK_FILE_CHOOSER (gtk_file_chooser_button_new_with_dialog (dialog));
-
- gtk_file_chooser_set_local_only (chooser, TRUE);
-
- g_signal_connect (dialog, "response", (GCallback) file_chooser_response, chooser);
-
- prop_dialog->category_icon = GTK_WIDGET (chooser);
- gtk_widget_show (prop_dialog->category_icon);
- gtk_table_attach (GTK_TABLE (table_category_properties), prop_dialog->category_icon, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
-
- gtk_widget_show (image);
-
- gtk_file_chooser_set_preview_widget (chooser, image);
- gtk_file_chooser_set_preview_widget_active (chooser, TRUE);
-
- g_signal_connect (G_OBJECT (chooser), "update-preview", (GCallback) update_preview, NULL);
- }
-
- return prop_dialog;
-}
-
static void
-free_properties_dialog (CategoryPropertiesDialog *prop_dialog)
+entry_changed_cb (GtkEntry *entry,
+ ECategoriesDialog *dialog)
{
- if (prop_dialog->the_dialog) {
- gtk_widget_destroy (prop_dialog->the_dialog);
- prop_dialog->the_dialog = NULL;
- }
-
- g_free (prop_dialog);
-}
-
-static void
-categories_dialog_build_model (ECategoriesDialog *dialog)
-{
- GtkTreeView *tree_view;
- GtkListStore *store;
- GList *list, *iter;
-
- store = gtk_list_store_new (
- N_COLUMNS, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_STRING);
-
- gtk_tree_sortable_set_sort_column_id (
- GTK_TREE_SORTABLE (store),
- COLUMN_CATEGORY, GTK_SORT_ASCENDING);
-
- list = e_categories_get_list ();
- for (iter = list; iter != NULL; iter = iter->next) {
- const gchar *category_name = iter->data;
- const gchar *filename;
- GdkPixbuf *pixbuf = NULL;
- GtkTreeIter iter;
- gboolean active;
-
- /* Only add user-visible categories. */
- if (!e_categories_is_searchable (category_name))
- continue;
-
- active = (g_hash_table_lookup (
- dialog->priv->selected_categories,
- category_name) != NULL);
-
- filename = e_categories_get_icon_file_for (category_name);
- if (filename != NULL)
- pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
-
- gtk_list_store_append (store, &iter);
-
- gtk_list_store_set (
- store, &iter,
- COLUMN_ACTIVE, active,
- COLUMN_ICON, pixbuf,
- COLUMN_CATEGORY, category_name,
- -1);
-
- if (pixbuf != NULL)
- g_object_unref (pixbuf);
- }
-
- tree_view = GTK_TREE_VIEW (dialog->priv->categories_list);
- gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (store));
-
- /* This has to be reset everytime we install a new model. */
- gtk_tree_view_set_search_column (tree_view, COLUMN_CATEGORY);
-
- g_list_free (list);
- g_object_unref (store);
-}
-
-static void
-categories_dialog_listener_cb (gpointer useless_pointer,
- ECategoriesDialog *dialog)
-{
- /* Don't rebuild the model if we're in
- * the middle of changing it ourselves. */
- if (dialog->priv->ignore_category_changes)
- return;
-
- categories_dialog_build_model (dialog);
-}
-
-static void
-add_comma_sep_categories (gpointer key, gpointer value, gpointer user_data)
-{
- GString **str = user_data;
-
- if (strlen ((*str)->str) > 0)
- *str = g_string_append (*str, ",");
-
- *str = g_string_append (*str, (const gchar *) key);
-}
-
-static void
-category_toggled_cb (GtkCellRenderer *renderer, const gchar *path, gpointer user_data)
-{
- ECategoriesDialogPrivate *priv;
- GtkTreeIter iter;
- GtkTreeModel *model;
- ECategoriesDialog *dialog = user_data;
-
- priv = dialog->priv;
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->categories_list));
-
- if (gtk_tree_model_get_iter_from_string (model, &iter, path)) {
- gboolean place_bool;
- gchar *place_string;
- GString *str;
-
- gtk_tree_model_get (model, &iter,
- COLUMN_ACTIVE, &place_bool,
- COLUMN_CATEGORY, &place_string,
- -1);
- if (place_bool) {
- g_hash_table_remove (priv->selected_categories, place_string);
- gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_ACTIVE, FALSE, -1);
- } else {
- g_hash_table_insert (priv->selected_categories, g_strdup (place_string), g_strdup (place_string));
- gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_ACTIVE, TRUE, -1);
- }
-
- str = g_string_new ("");
- g_hash_table_foreach (priv->selected_categories, (GHFunc) add_comma_sep_categories, &str);
- gtk_entry_set_text (GTK_ENTRY (priv->categories_entry), str->str);
-
- /* free memory */
- g_string_free (str, TRUE);
- g_free (place_string);
-
- gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
- }
-}
-
-static void
-entry_changed_cb (GtkEditable *editable, gpointer user_data)
-{
- ECategoriesDialog *dialog = user_data;
-
- gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
-}
-
-static gchar *
-check_category_name (const gchar *name)
-{
- GString *str = NULL;
- gchar *p = (gchar *) name;
-
- str = g_string_new ("");
- while (*p) {
- switch (*p) {
- case ',' :
- break;
- default :
- str = g_string_append_c (str, *p);
- }
- p++;
- }
-
- p = g_strstrip (g_string_free (str, FALSE));
-
- return p;
-}
-
-static void
-new_button_clicked_cb (GtkButton *button, gpointer user_data)
-{
- ECategoriesDialog *dialog;
- CategoryPropertiesDialog *prop_dialog;
-
- dialog = user_data;
-
- prop_dialog = create_properties_dialog (dialog);
- if (!prop_dialog)
- return;
-
- do {
- if (gtk_dialog_run (GTK_DIALOG (prop_dialog->the_dialog)) == GTK_RESPONSE_OK) {
- const gchar *category_name;
- gchar *correct_category_name;
-
- category_name = gtk_entry_get_text (GTK_ENTRY (prop_dialog->category_name));
- correct_category_name = check_category_name (category_name);
-
- if (e_categories_exist (correct_category_name)) {
- GtkWidget *error_dialog;
-
- error_dialog = gtk_message_dialog_new (
- GTK_WINDOW (prop_dialog->the_dialog),
- 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
- _("There is already a category '%s' in the configuration. Please use another name"),
- category_name);
-
- gtk_dialog_run (GTK_DIALOG (error_dialog));
- gtk_widget_destroy (error_dialog);
- g_free (correct_category_name);
- } else {
- gchar *category_icon;
-
- category_icon = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (prop_dialog->category_icon));
-
- e_categories_add (correct_category_name, NULL, category_icon, TRUE);
-
- g_free (category_icon);
- g_free (correct_category_name);
-
- break;
- }
- } else
- break;
- } while (TRUE);
-
- free_properties_dialog (prop_dialog);
-}
-
-static void
-edit_button_clicked_cb (GtkButton *button, gpointer user_data)
-{
- ECategoriesDialog *dialog;
- CategoryPropertiesDialog *prop_dialog;
- GtkTreeSelection *selection;
- GtkTreeIter iter;
- GtkTreeModel *model;
- GtkTreeView *tree_view;
- GList *selected;
- gchar *category_name;
- const gchar *icon_file;
-
- dialog = user_data;
-
- tree_view = GTK_TREE_VIEW (dialog->priv->categories_list);
- selection = gtk_tree_view_get_selection (tree_view);
- selected = gtk_tree_selection_get_selected_rows (selection, &model);
- g_return_if_fail (g_list_length (selected) == 1);
-
- /* load the properties dialog */
- prop_dialog = create_properties_dialog (dialog);
- if (!prop_dialog)
- return;
-
- gtk_tree_model_get_iter (model, &iter, selected->data);
- gtk_tree_model_get (model, &iter, COLUMN_CATEGORY, &category_name, -1);
- gtk_entry_set_text (GTK_ENTRY (prop_dialog->category_name), category_name);
- gtk_widget_set_sensitive (prop_dialog->category_name, FALSE);
-
- icon_file = e_categories_get_icon_file_for (category_name);
- if (icon_file)
- gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (prop_dialog->category_icon), icon_file);
-
- if (gtk_dialog_run (GTK_DIALOG (prop_dialog->the_dialog)) == GTK_RESPONSE_OK) {
- gchar *category_icon;
-
- category_icon = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (prop_dialog->category_icon));
-
- e_categories_set_icon_file_for (category_name, category_icon);
-
- if (category_icon) {
- GdkPixbuf *icon = NULL;
-
- icon = gdk_pixbuf_new_from_file (category_icon, NULL);
- if (icon) {
- gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_ICON, icon, -1);
- g_object_unref (icon);
- }
-
- g_free (category_icon);
- } else {
- gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_ICON, NULL, -1);
- }
-
- gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
- }
-
- g_free (category_name);
- free_properties_dialog (prop_dialog);
-
- g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
- g_list_free (selected);
-}
-
-static void
-categories_dialog_delete_cb (ECategoriesDialog *dialog)
-{
- GtkTreeSelection *selection;
- GtkTreeView *tree_view;
- GtkTreeModel *model;
- GList *selected, *item;
-
- tree_view = GTK_TREE_VIEW (dialog->priv->categories_list);
- selection = gtk_tree_view_get_selection (tree_view);
- selected = gtk_tree_selection_get_selected_rows (selection, &model);
-
- /* Remove categories in reverse order to avoid invalidating
- * tree paths as we iterate over the list. Note, the list is
- * probably already sorted but we sort again just to be safe. */
- selected = g_list_reverse (g_list_sort (
- selected, (GCompareFunc) gtk_tree_path_compare));
-
- /* Prevent the model from being rebuilt every time we
- * remove a category, since we're already modifying it. */
- dialog->priv->ignore_category_changes = TRUE;
-
- for (item = selected; item != NULL; item = item->next) {
- GtkTreePath *path = item->data;
- GtkTreeIter iter;
- gchar *category;
- gint column_id;
-
- column_id = COLUMN_CATEGORY;
- gtk_tree_model_get_iter (model, &iter, path);
- gtk_tree_model_get (model, &iter, column_id, &category, -1);
- gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
- e_categories_remove (category);
- g_free (category);
- }
-
- dialog->priv->ignore_category_changes = FALSE;
-
- /* If we only removed one category, try to select another. */
- if (g_list_length (selected) == 1) {
- GtkTreePath *path = selected->data;
-
- gtk_tree_selection_select_path (selection, path);
- if (!gtk_tree_selection_path_is_selected (selection, path))
- if (gtk_tree_path_prev (path))
- gtk_tree_selection_select_path (selection, path);
- }
-
- g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
- g_list_free (selected);
-}
-
-static void
-categories_dialog_selection_changed_cb (ECategoriesDialog *dialog,
- GtkTreeSelection *selection)
-{
- GtkWidget *widget;
- gint n_rows;
-
- n_rows = gtk_tree_selection_count_selected_rows (selection);
-
- widget = dialog->priv->edit_button;
- gtk_widget_set_sensitive (widget, n_rows == 1);
-
- widget = dialog->priv->delete_button;
- gtk_widget_set_sensitive (widget, n_rows >= 1);
-}
-
-static gboolean
-categories_dialog_key_press_event (ECategoriesDialog *dialog,
- GdkEventKey *event)
-{
- GtkButton *button;
-
- button = GTK_BUTTON (dialog->priv->delete_button);
-
- if (event->keyval == GDK_KEY_Delete) {
- gtk_button_clicked (button);
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-categories_dialog_dispose (GObject *object)
-{
- ECategoriesDialogPrivate *priv;
-
- priv = E_CATEGORIES_DIALOG (object)->priv;
-
- g_hash_table_remove_all (priv->selected_categories);
-
- /* Chain up to parent's dispose() method. */
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-categories_dialog_finalize (GObject *object)
-{
- ECategoriesDialogPrivate *priv;
-
- priv = E_CATEGORIES_DIALOG (object)->priv;
-
- e_categories_unregister_change_listener (
- G_CALLBACK (categories_dialog_listener_cb), object);
-
- g_hash_table_destroy (priv->selected_categories);
-
- /* Chain up to parent's finalize() method. */
- G_OBJECT_CLASS (parent_class)->finalize (object);
+ gtk_dialog_set_response_sensitive (
+ GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
}
static void
e_categories_dialog_class_init (ECategoriesDialogClass *class)
{
- GObjectClass *object_class;
-
- parent_class = g_type_class_peek_parent (class);
g_type_class_add_private (class, sizeof (ECategoriesDialogPrivate));
-
- object_class = G_OBJECT_CLASS (class);
- object_class->dispose = categories_dialog_dispose;
- object_class->finalize = categories_dialog_finalize;
}
static void
e_categories_dialog_init (ECategoriesDialog *dialog)
{
- GtkCellRenderer *renderer;
- GtkEntryCompletion *completion;
- GtkTreeViewColumn *column;
- GtkTreeSelection *selection;
- GtkTreeView *tree_view;
GtkWidget *dialog_content;
- GtkWidget *table_categories;
- GtkWidget *entry_categories;
- GtkWidget *label_header;
- GtkWidget *label2;
- GtkWidget *scrolledwindow1;
- GtkWidget *categories_list;
- GtkWidget *hbuttonbox1;
- GtkWidget *button_new;
- GtkWidget *button_edit;
- GtkWidget *alignment1;
- GtkWidget *hbox1;
- GtkWidget *image1;
- GtkWidget *label3;
- GtkWidget *button_delete;
-
- gtk_window_set_default_size (GTK_WINDOW (dialog), -1, 400);
-
- dialog_content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
-
- table_categories = gtk_table_new (5, 1, FALSE);
- gtk_box_pack_start (GTK_BOX (dialog_content), table_categories, TRUE, TRUE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (table_categories), 12);
- gtk_table_set_row_spacings (GTK_TABLE (table_categories), 6);
- gtk_table_set_col_spacings (GTK_TABLE (table_categories), 6);
-
- entry_categories = gtk_entry_new ();
- gtk_table_attach (GTK_TABLE (table_categories), entry_categories, 0, 1, 1, 2,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- label_header = gtk_label_new_with_mnemonic (_("Currently _used categories:"));
- gtk_table_attach (GTK_TABLE (table_categories), label_header, 0, 1, 0, 1,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
- gtk_label_set_justify (GTK_LABEL (label_header), GTK_JUSTIFY_CENTER);
- gtk_misc_set_alignment (GTK_MISC (label_header), 0, 0.5);
-
- label2 = gtk_label_new_with_mnemonic (_("_Available Categories:"));
- gtk_table_attach (GTK_TABLE (table_categories), label2, 0, 1, 2, 3,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
- gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_CENTER);
- gtk_misc_set_alignment (GTK_MISC (label2), 0, 0.5);
-
- scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
- gtk_table_attach (GTK_TABLE (table_categories), scrolledwindow1, 0, 1, 3, 4,
- (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL),
- (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL), 0, 0);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_SHADOW_IN);
-
- categories_list = gtk_tree_view_new ();
- gtk_container_add (GTK_CONTAINER (scrolledwindow1), categories_list);
- gtk_widget_set_size_request (categories_list, -1, 350);
- gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (categories_list), FALSE);
- gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (categories_list), TRUE);
-
- hbuttonbox1 = gtk_hbutton_box_new ();
- gtk_table_attach (GTK_TABLE (table_categories), hbuttonbox1, 0, 1, 4, 5,
- (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL),
- (GtkAttachOptions) (GTK_SHRINK), 0, 0);
- gtk_box_set_spacing (GTK_BOX (hbuttonbox1), 6);
-
- button_new = gtk_button_new_from_stock ("gtk-new");
- gtk_container_add (GTK_CONTAINER (hbuttonbox1), button_new);
- gtk_widget_set_can_default (button_new, TRUE);
-
- button_edit = gtk_button_new ();
- gtk_container_add (GTK_CONTAINER (hbuttonbox1), button_edit);
- gtk_widget_set_can_default (button_edit, TRUE);
-
- alignment1 = gtk_alignment_new (0.5, 0.5, 0, 0);
- gtk_container_add (GTK_CONTAINER (button_edit), alignment1);
-
- hbox1 = gtk_hbox_new (FALSE, 2);
- gtk_container_add (GTK_CONTAINER (alignment1), hbox1);
-
- image1 = gtk_image_new_from_stock ("gtk-properties", GTK_ICON_SIZE_BUTTON);
- gtk_box_pack_start (GTK_BOX (hbox1), image1, FALSE, FALSE, 0);
-
- label3 = gtk_label_new_with_mnemonic (_("_Edit"));
- gtk_box_pack_start (GTK_BOX (hbox1), label3, FALSE, FALSE, 0);
-
- button_delete = gtk_button_new_from_stock ("gtk-delete");
- gtk_container_add (GTK_CONTAINER (hbuttonbox1), button_delete);
- gtk_widget_set_can_default (button_delete, TRUE);
-
- gtk_label_set_mnemonic_widget (GTK_LABEL (label_header), entry_categories);
- gtk_label_set_mnemonic_widget (GTK_LABEL (label2), categories_list);
+ GtkWidget *categories_editor;
dialog->priv = G_TYPE_INSTANCE_GET_PRIVATE (
dialog, E_TYPE_CATEGORIES_DIALOG, ECategoriesDialogPrivate);
- dialog->priv->selected_categories = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-
- dialog->priv->categories_entry = entry_categories;
- dialog->priv->categories_list = categories_list;
-
- tree_view = GTK_TREE_VIEW (dialog->priv->categories_list);
- selection = gtk_tree_view_get_selection (tree_view);
- gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
-
- g_signal_connect_swapped (
- selection, "changed",
- G_CALLBACK (categories_dialog_selection_changed_cb), dialog);
- g_signal_connect_swapped (
- dialog->priv->categories_list, "key-press-event",
- G_CALLBACK (categories_dialog_key_press_event), dialog);
+ categories_editor = e_categories_editor_new ();
+ dialog->priv->categories_editor = categories_editor;
- completion = e_category_completion_new ();
- gtk_entry_set_completion (GTK_ENTRY (dialog->priv->categories_entry), completion);
- g_object_unref (completion);
-
- dialog->priv->new_button = button_new;
- g_signal_connect (G_OBJECT (dialog->priv->new_button), "clicked", G_CALLBACK (new_button_clicked_cb), dialog);
- dialog->priv->edit_button = button_edit;
- g_signal_connect (G_OBJECT (dialog->priv->edit_button), "clicked", G_CALLBACK (edit_button_clicked_cb), dialog);
- dialog->priv->delete_button = button_delete;
- g_signal_connect_swapped (
- G_OBJECT (dialog->priv->delete_button), "clicked",
- G_CALLBACK (categories_dialog_delete_cb), dialog);
-
- gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+ dialog_content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
+ gtk_box_pack_start (
+ GTK_BOX (dialog_content), categories_editor, TRUE, TRUE, 0);
+ gtk_box_set_spacing (GTK_BOX (dialog_content), 12);
+
+ g_signal_connect (
+ categories_editor, "entry-changed",
+ G_CALLBACK (entry_changed_cb), dialog);
+
+ gtk_dialog_add_buttons (
+ GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
- gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
+ gtk_dialog_set_response_sensitive (
+ GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
gtk_window_set_title (GTK_WINDOW (dialog), _("Categories"));
- gtk_widget_show_all (dialog_content);
-
- renderer = gtk_cell_renderer_toggle_new ();
- g_signal_connect (G_OBJECT (renderer), "toggled", G_CALLBACK (category_toggled_cb), dialog);
- column = gtk_tree_view_column_new_with_attributes ("?", renderer,
- "active", COLUMN_ACTIVE, NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->categories_list), column);
-
- renderer = gtk_cell_renderer_pixbuf_new ();
- column = gtk_tree_view_column_new_with_attributes (_("Icon"), renderer,
- "pixbuf", COLUMN_ICON, NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->categories_list), column);
-
- renderer = gtk_cell_renderer_text_new ();
- column = gtk_tree_view_column_new_with_attributes (_("Category"), renderer,
- "text", COLUMN_CATEGORY, NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->categories_list), column);
-
- categories_dialog_build_model (dialog);
-
- e_categories_register_change_listener (
- G_CALLBACK (categories_dialog_listener_cb), dialog);
+ gtk_widget_show_all (categories_editor);
}
/**
@@ -794,13 +101,11 @@ e_categories_dialog_new (const gchar *categories)
{
ECategoriesDialog *dialog;
- dialog = E_CATEGORIES_DIALOG (g_object_new (E_TYPE_CATEGORIES_DIALOG, NULL));
+ dialog = g_object_new (E_TYPE_CATEGORIES_DIALOG, NULL);
+
if (categories)
e_categories_dialog_set_categories (dialog, categories);
- g_signal_connect (G_OBJECT (dialog->priv->categories_entry), "changed",
- G_CALLBACK (entry_changed_cb), dialog);
-
return GTK_WIDGET (dialog);
}
@@ -816,30 +121,14 @@ e_categories_dialog_new (const gchar *categories)
const gchar *
e_categories_dialog_get_categories (ECategoriesDialog *dialog)
{
- GtkEntry *entry;
- const gchar *text;
+ const gchar *categories;
g_return_val_if_fail (E_IS_CATEGORIES_DIALOG (dialog), NULL);
- entry = GTK_ENTRY (dialog->priv->categories_entry);
+ categories = e_categories_editor_get_categories (
+ E_CATEGORIES_EDITOR (dialog->priv->categories_editor));
- text = gtk_entry_get_text (entry);
- if (text) {
- gint len = strlen (text), old_len = len;
-
- while (len > 0 && (text[len -1] == ' ' || text[len - 1] == ','))
- len--;
-
- if (old_len != len) {
- gchar *tmp = g_strndup (text, len);
-
- gtk_entry_set_text (entry, tmp);
-
- g_free (tmp);
- }
- }
-
- return gtk_entry_get_text (entry);
+ return categories;
}
/**
@@ -853,47 +142,9 @@ void
e_categories_dialog_set_categories (ECategoriesDialog *dialog,
const gchar *categories)
{
- ECategoriesDialogPrivate *priv;
- gchar **arr;
- GtkTreeIter iter;
- GtkTreeModel *model;
-
g_return_if_fail (E_IS_CATEGORIES_DIALOG (dialog));
- priv = dialog->priv;
-
- /* clean up the table of selected categories */
- g_hash_table_foreach_remove (priv->selected_categories, (GHRFunc) gtk_true, NULL);
-
- arr = g_strsplit (categories, ",", 0);
- if (arr) {
- gint i = 0;
- while (arr[i] != NULL) {
- arr[i] = g_strstrip (arr[i]);
-
- if (arr[i][0])
- g_hash_table_insert (priv->selected_categories, g_strdup (arr[i]), g_strdup (arr[i]));
- i++;
- }
-
- g_strfreev (arr);
- }
-
- /* set the widgets */
- gtk_entry_set_text (GTK_ENTRY (priv->categories_entry), categories);
-
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->categories_list));
- if (gtk_tree_model_get_iter_first (model, &iter)) {
- do {
- gchar *place_string;
-
- gtk_tree_model_get (model, &iter, COLUMN_CATEGORY, &place_string, -1);
- if (g_hash_table_lookup (priv->selected_categories, place_string))
- gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_ACTIVE, TRUE, -1);
- else
- gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_ACTIVE, FALSE, -1);
-
- g_free (place_string);
- } while (gtk_tree_model_iter_next (model, &iter));
- }
+ e_categories_editor_set_categories (
+ E_CATEGORIES_EDITOR (dialog->priv->categories_editor),
+ categories);
}
diff --git a/libedataserverui/e-categories-editor.c b/libedataserverui/e-categories-editor.c
new file mode 100644
index 0000000..7a4e208
--- /dev/null
+++ b/libedataserverui/e-categories-editor.c
@@ -0,0 +1,427 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <glib/gi18n-lib.h>
+#include "libedataserver/e-categories.h"
+#include "libedataserver/libedataserver-private.h"
+#include "e-categories-editor.h"
+#include "e-categories-selector.h"
+#include "e-category-completion.h"
+#include "e-category-editor.h"
+
+G_DEFINE_TYPE (ECategoriesEditor, e_categories_editor, GTK_TYPE_TABLE)
+
+struct _ECategoriesEditorPrivate {
+ ECategoriesSelector *categories_list;
+ GtkWidget *categories_entry;
+ GtkWidget *categories_entry_label;
+ GtkWidget *new_button;
+ GtkWidget *edit_button;
+ GtkWidget *delete_button;
+
+ guint ignore_category_changes : 1;
+};
+
+enum {
+ COLUMN_ACTIVE,
+ COLUMN_ICON,
+ COLUMN_CATEGORY,
+ N_COLUMNS
+};
+
+enum {
+ PROP_0,
+ PROP_ENTRY_VISIBLE
+};
+
+enum {
+ ENTRY_CHANGED,
+ LAST_SIGNAL
+};
+
+static gint signals[LAST_SIGNAL] = {0};
+
+static void
+entry_changed_cb (GtkEntry *entry,
+ ECategoriesEditor *editor)
+{
+ g_signal_emit (editor, signals[ENTRY_CHANGED], 0);
+}
+
+
+static void
+categories_editor_selection_changed_cb (ECategoriesEditor *editor,
+ GtkTreeSelection *selection)
+{
+ GtkWidget *widget;
+ gint n_rows;
+
+ n_rows = gtk_tree_selection_count_selected_rows (selection);
+
+ widget = editor->priv->edit_button;
+ gtk_widget_set_sensitive (widget, n_rows == 1);
+
+ widget = editor->priv->delete_button;
+ gtk_widget_set_sensitive (widget, n_rows >= 1);
+}
+
+static void
+category_checked_cb (ECategoriesSelector *selector,
+ const gchar *category,
+ const gboolean checked,
+ ECategoriesEditor *editor)
+{
+ GtkEntry *entry;
+ const gchar *categories;
+
+ entry = GTK_ENTRY (editor->priv->categories_entry);
+ categories = e_categories_selector_get_checked (selector);
+
+ gtk_entry_set_text (entry, categories);
+}
+
+static void
+new_button_clicked_cb (GtkButton *button,
+ ECategoriesEditor *editor)
+{
+ ECategoryEditor *cat_editor = e_category_editor_new();
+
+ e_category_editor_create_category (cat_editor);
+
+ gtk_widget_destroy (GTK_WIDGET (cat_editor));
+}
+
+static void
+edit_button_clicked_cb (GtkButton *button,
+ ECategoriesEditor *editor)
+{
+ ECategoryEditor *cat_editor = e_category_editor_new();
+ const gchar *category;
+
+ category = e_categories_selector_get_selected (
+ editor->priv->categories_list);
+
+ e_category_editor_edit_category (cat_editor, category);
+
+ gtk_widget_destroy (GTK_WIDGET (cat_editor));
+}
+
+static void
+categories_editor_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ENTRY_VISIBLE:
+ e_categories_editor_set_entry_visible (
+ E_CATEGORIES_EDITOR (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+categories_editor_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ENTRY_VISIBLE:
+ g_value_set_boolean (
+ value, e_categories_editor_get_entry_visible (
+ E_CATEGORIES_EDITOR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_categories_editor_class_init (ECategoriesEditorClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (ECategoriesEditorPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = categories_editor_set_property;
+ object_class->get_property = categories_editor_get_property;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ENTRY_VISIBLE,
+ g_param_spec_boolean (
+ "entry-visible",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ signals[ENTRY_CHANGED] = g_signal_new (
+ "entry-changed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (ECategoriesEditorClass, entry_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+e_categories_editor_init (ECategoriesEditor *editor)
+{
+ GtkEntryCompletion *completion;
+ GtkWidget *entry_categories;
+ GtkWidget *label_header;
+ GtkWidget *label2;
+ GtkWidget *scrolledwindow1;
+ GtkWidget *categories_list;
+ GtkWidget *hbuttonbox1;
+ GtkWidget *button_new;
+ GtkWidget *button_edit;
+ GtkWidget *button_delete;
+
+ gtk_widget_set_size_request (GTK_WIDGET (editor), -1, 400);
+
+ gtk_table_resize (GTK_TABLE (editor), 3, 2);
+ gtk_table_set_row_spacings (GTK_TABLE (editor), 6);
+ gtk_table_set_col_spacings (GTK_TABLE (editor), 6);
+
+ entry_categories = gtk_entry_new ();
+ gtk_table_attach (
+ GTK_TABLE (editor),
+ entry_categories, 0, 1, 1, 2,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ label_header = gtk_label_new_with_mnemonic (
+ _("Currently _used categories:"));
+ gtk_table_attach (
+ GTK_TABLE (editor),
+ label_header, 0, 1, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_label_set_justify (GTK_LABEL (label_header), GTK_JUSTIFY_CENTER);
+ gtk_misc_set_alignment (GTK_MISC (label_header), 0, 0.5);
+
+ label2 = gtk_label_new_with_mnemonic (_("_Available Categories:"));
+ gtk_table_attach (
+ GTK_TABLE (editor),
+ label2, 0, 1, 2, 3,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_CENTER);
+ gtk_misc_set_alignment (GTK_MISC (label2), 0, 0.5);
+
+ scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_table_attach (
+ GTK_TABLE (editor),
+ scrolledwindow1, 0, 1, 3, 4,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL),
+ (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL), 0, 0);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (scrolledwindow1),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_SHADOW_IN);
+
+ categories_list = GTK_WIDGET (e_categories_selector_new ());
+ gtk_container_add (GTK_CONTAINER (scrolledwindow1), categories_list);
+ gtk_widget_set_size_request (categories_list, -1, 350);
+ gtk_tree_view_set_headers_visible (
+ GTK_TREE_VIEW (categories_list), FALSE);
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (categories_list), TRUE);
+ g_signal_connect (G_OBJECT (categories_list), "category-checked",
+ G_CALLBACK (category_checked_cb), editor);
+
+ hbuttonbox1 = gtk_hbutton_box_new ();
+ gtk_table_attach (
+ GTK_TABLE (editor),
+ hbuttonbox1, 0, 1, 4, 5,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL),
+ (GtkAttachOptions) (GTK_SHRINK), 0, 0);
+ gtk_box_set_spacing (GTK_BOX (hbuttonbox1), 6);
+
+ button_new = gtk_button_new_from_stock (GTK_STOCK_NEW);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox1), button_new);
+ gtk_widget_set_can_default (button_new, TRUE);
+
+ button_edit = gtk_button_new_from_stock (GTK_STOCK_EDIT);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox1), button_edit);
+ gtk_widget_set_can_default (button_edit, TRUE);
+
+ button_delete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox1), button_delete);
+ gtk_widget_set_can_default (button_delete, TRUE);
+
+ gtk_label_set_mnemonic_widget (
+ GTK_LABEL (label_header), entry_categories);
+ gtk_label_set_mnemonic_widget (
+ GTK_LABEL (label2), categories_list);
+
+ editor->priv = G_TYPE_INSTANCE_GET_PRIVATE (
+ editor, E_TYPE_CATEGORIES_EDITOR, ECategoriesEditorPrivate);
+
+ editor->priv->categories_list = E_CATEGORIES_SELECTOR (categories_list);
+ editor->priv->categories_entry = entry_categories;
+ editor->priv->categories_entry_label = label_header;
+
+ g_signal_connect_swapped (
+ editor->priv->categories_list, "selection-changed",
+ G_CALLBACK (categories_editor_selection_changed_cb), editor);
+
+ completion = e_category_completion_new ();
+ gtk_entry_set_completion (
+ GTK_ENTRY (editor->priv->categories_entry), completion);
+ g_object_unref (completion);
+
+ editor->priv->new_button = button_new;
+ g_signal_connect (
+ editor->priv->new_button, "clicked",
+ G_CALLBACK (new_button_clicked_cb), editor);
+
+ editor->priv->edit_button = button_edit;
+ g_signal_connect (
+ editor->priv->edit_button, "clicked",
+ G_CALLBACK (edit_button_clicked_cb), editor);
+
+ editor->priv->delete_button = button_delete;
+ g_signal_connect_swapped (
+ editor->priv->delete_button, "clicked",
+ G_CALLBACK (e_categories_selector_delete_selection),
+ editor->priv->categories_list);
+
+ g_signal_connect (
+ editor->priv->categories_entry, "changed",
+ G_CALLBACK (entry_changed_cb), editor);
+
+ gtk_widget_show_all (GTK_WIDGET (editor));
+}
+
+/**
+ * e_categories_editor_new:
+ *
+ * Creates a new #ECategoriesEditor widget.
+ *
+ * Returns: a new #ECategoriesEditor
+ *
+ * Since: 3.2
+ **/
+GtkWidget *
+e_categories_editor_new (void)
+{
+ return g_object_new (E_TYPE_CATEGORIES_EDITOR, NULL);
+}
+
+/**
+ * e_categories_editor_get_categories:
+ * @editor: an #ECategoriesEditor
+ *
+ * Gets a comma-separated list of the categories currently selected
+ * in the editor.
+ *
+ * Returns: a comma-separated list of categories
+ *
+ * Since: 3.2
+ **/
+const gchar *
+e_categories_editor_get_categories (ECategoriesEditor *editor)
+{
+ ECategoriesSelector *categories_list;
+
+ g_return_val_if_fail (E_IS_CATEGORIES_EDITOR (editor), NULL);
+
+ categories_list = editor->priv->categories_list;
+
+ return e_categories_selector_get_checked (categories_list);
+}
+
+/**
+ * e_categories_editor_set_categories:
+ * @dialog: an #ECategoriesEditor
+ * @categories: comma-separated list of categories
+ *
+ * Sets the list of categories selected on the editor.
+ *
+ * Since: 3.2
+ **/
+void
+e_categories_editor_set_categories (ECategoriesEditor *editor,
+ const gchar *categories)
+{
+ ECategoriesSelector *categories_list;
+
+ g_return_if_fail (E_IS_CATEGORIES_EDITOR (editor));
+
+ categories_list = editor->priv->categories_list;
+
+ e_categories_selector_set_checked (categories_list, categories);
+ category_checked_cb (categories_list, NULL, FALSE, editor);
+}
+
+/**
+ * e_categories_editor_get_entry_visible:
+ * @editor: an #ECategoriesEditor
+ *
+ * Return the visibility of the category input entry.
+ *
+ * Returns: whether the entry is visible
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_categories_editor_get_entry_visible (ECategoriesEditor *editor)
+{
+ g_return_val_if_fail (E_IS_CATEGORIES_EDITOR (editor), TRUE);
+
+ return gtk_widget_get_visible (editor->priv->categories_entry);
+}
+
+/**
+ * e_categories_editor_set_entry_visible:
+ * @editor: an #ECategoriesEditor
+ * @entry_visible: whether to make the entry visible
+ *
+ * Sets the visibility of the category input entry.
+ *
+ * Since: 3.2
+ **/
+void
+e_categories_editor_set_entry_visible (ECategoriesEditor *editor,
+ gboolean entry_visible)
+{
+ g_return_if_fail (E_IS_CATEGORIES_EDITOR (editor));
+
+ gtk_widget_set_visible (
+ editor->priv->categories_entry, entry_visible);
+ gtk_widget_set_visible (
+ editor->priv->categories_entry_label, entry_visible);
+ e_categories_selector_set_items_checkable (
+ editor->priv->categories_list, entry_visible);
+
+ g_object_notify (G_OBJECT (editor), "entry-visible");
+}
diff --git a/libedataserverui/e-categories-editor.h b/libedataserverui/e-categories-editor.h
new file mode 100644
index 0000000..2789c0d
--- /dev/null
+++ b/libedataserverui/e-categories-editor.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef E_CATEGORIES_EDITOR_H
+#define E_CATEGORIES_EDITOR_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CATEGORIES_EDITOR \
+ (e_categories_editor_get_type ())
+#define E_CATEGORIES_EDITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CATEGORIES_EDITOR, ECategoriesEditor))
+#define E_CATEGORIES_EDITOR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CATEGORIES_EDITOR, ECategoriesEditorClass))
+#define E_IS_CATEGORIES_EDITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CATEGORIES_EDITOR))
+#define E_IS_CATEGORIES_EDITOR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CATEGORIES_EDITOR))
+#define E_CATEGORIES_EDITOR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CATEGORIES_EDITOR, ECategoriesEditorClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECategoriesEditor ECategoriesEditor;
+typedef struct _ECategoriesEditorClass ECategoriesEditorClass;
+typedef struct _ECategoriesEditorPrivate ECategoriesEditorPrivate;
+
+struct _ECategoriesEditor {
+ GtkTable parent;
+ ECategoriesEditorPrivate *priv;
+};
+
+struct _ECategoriesEditorClass {
+ GtkTableClass parent_class;
+
+ void (*entry_changed) (GtkEntry *entry);
+};
+
+GType e_categories_editor_get_type (void);
+GtkWidget * e_categories_editor_new (void);
+const gchar * e_categories_editor_get_categories
+ (ECategoriesEditor *editor);
+void e_categories_editor_set_categories
+ (ECategoriesEditor *editor,
+ const gchar *categories);
+gboolean e_categories_editor_get_entry_visible
+ (ECategoriesEditor *editor);
+void e_categories_editor_set_entry_visible
+ (ECategoriesEditor *editor,
+ gboolean entry_visible);
+
+G_END_DECLS
+
+#endif /* E_CATEGORIES_EDITOR_H */
diff --git a/libedataserverui/e-categories-selector.c b/libedataserverui/e-categories-selector.c
new file mode 100644
index 0000000..addd266
--- /dev/null
+++ b/libedataserverui/e-categories-selector.c
@@ -0,0 +1,570 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this library; 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-lib.h>
+#include "libedataserver/e-categories.h"
+#include "e-categories-selector.h"
+#include "e-data-server-ui-marshal.h"
+
+G_DEFINE_TYPE (
+ ECategoriesSelector,
+ e_categories_selector,
+ GTK_TYPE_TREE_VIEW)
+
+struct _ECategoriesSelectorPrivate {
+ gboolean checkable;
+ GHashTable *selected_categories;
+
+ gboolean ignore_category_changes;
+};
+
+enum {
+ PROP_0,
+ PROP_ITEMS_CHECKABLE
+};
+
+enum {
+ CATEGORY_CHECKED,
+ SELECTION_CHANGED,
+ LAST_SIGNAL
+};
+
+enum {
+ COLUMN_ACTIVE,
+ COLUMN_ICON,
+ COLUMN_CATEGORY,
+ N_COLUMNS
+};
+
+static gint signals[LAST_SIGNAL] = {0};
+
+static void
+categories_selector_build_model (ECategoriesSelector *selector)
+{
+ GtkListStore *store;
+ GList *list, *iter;
+
+ store = gtk_list_store_new (
+ N_COLUMNS, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_STRING);
+
+ gtk_tree_sortable_set_sort_column_id (
+ GTK_TREE_SORTABLE (store),
+ COLUMN_CATEGORY, GTK_SORT_ASCENDING);
+
+ list = e_categories_get_list ();
+ for (iter = list; iter != NULL; iter = iter->next) {
+ const gchar *category_name = iter->data;
+ const gchar *filename;
+ GdkPixbuf *pixbuf = NULL;
+ GtkTreeIter iter;
+ gboolean active;
+
+ /* Only add user-visible categories. */
+ if (!e_categories_is_searchable (category_name))
+ continue;
+
+ active = (g_hash_table_lookup (
+ selector->priv->selected_categories,
+ category_name) != NULL);
+
+ filename = e_categories_get_icon_file_for (category_name);
+ if (filename != NULL)
+ pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+
+ gtk_list_store_append (store, &iter);
+
+ gtk_list_store_set (
+ store, &iter,
+ COLUMN_ACTIVE, active,
+ COLUMN_ICON, pixbuf,
+ COLUMN_CATEGORY, category_name,
+ -1);
+
+ if (pixbuf != NULL)
+ g_object_unref (pixbuf);
+ }
+
+ gtk_tree_view_set_model (
+ GTK_TREE_VIEW (selector), GTK_TREE_MODEL (store));
+
+ /* This has to be reset everytime we install a new model */
+ gtk_tree_view_set_search_column (
+ GTK_TREE_VIEW (selector), COLUMN_CATEGORY);
+
+ g_list_free (list);
+ g_object_unref (store);
+}
+
+static void
+category_toggled_cb (GtkCellRenderer *renderer,
+ const gchar *path,
+ ECategoriesSelector *selector)
+{
+ GtkTreeModel *model;
+ GtkTreePath *tree_path;
+ GtkTreeIter iter;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
+ g_return_if_fail (model);
+
+ tree_path = gtk_tree_path_new_from_string (path);
+ g_return_if_fail (tree_path);
+
+ if (gtk_tree_model_get_iter (model, &iter, tree_path)) {
+ gchar *category;
+ gboolean active;
+
+ gtk_tree_model_get (model, &iter,
+ COLUMN_ACTIVE, &active,
+ COLUMN_CATEGORY, &category, -1);
+
+ gtk_list_store_set (
+ GTK_LIST_STORE (model), &iter,
+ COLUMN_ACTIVE, !active, -1);
+
+ if (active)
+ g_hash_table_remove (
+ selector->priv->selected_categories, category);
+ else
+ g_hash_table_insert (
+ selector->priv->selected_categories,
+ g_strdup (category), g_strdup (category));
+
+ g_signal_emit (
+ selector, signals[CATEGORY_CHECKED], 0,
+ category, !active);
+
+ g_free (category);
+ }
+
+ gtk_tree_path_free (tree_path);
+}
+
+static void
+categories_selector_listener_cb (gpointer useless_pointer,
+ ECategoriesSelector *selector)
+{
+ if (!selector->priv->ignore_category_changes)
+ categories_selector_build_model (selector);
+}
+
+static gboolean
+categories_selector_key_press_event (ECategoriesSelector *selector,
+ GdkEventKey *event)
+{
+ if (event->keyval == GDK_KEY_Delete) {
+ e_categories_selector_delete_selection (selector);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+categories_selector_selection_changed (GtkTreeSelection *selection,
+ ECategoriesSelector *selector)
+{
+ g_signal_emit (selector, signals[SELECTION_CHANGED], 0, selection);
+}
+
+static void
+categories_selector_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ITEMS_CHECKABLE:
+ g_value_set_boolean (
+ value,
+ e_categories_selector_get_items_checkable (
+ E_CATEGORIES_SELECTOR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+categories_selector_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ITEMS_CHECKABLE:
+ e_categories_selector_set_items_checkable (
+ E_CATEGORIES_SELECTOR (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+categories_selector_dispose (GObject *object)
+{
+ ECategoriesSelectorPrivate *priv;
+
+ priv = E_CATEGORIES_SELECTOR (object)->priv;
+
+ if (priv->selected_categories != NULL) {
+ g_hash_table_destroy (priv->selected_categories);
+ priv->selected_categories = NULL;
+ }
+
+ /* Chain up to parent's dispose() method.*/
+ G_OBJECT_CLASS (e_categories_selector_parent_class)->dispose (object);
+}
+
+static void
+categories_selector_finalize (GObject *object)
+{
+ e_categories_unregister_change_listener (
+ G_CALLBACK (categories_selector_listener_cb), object);
+}
+
+static void
+e_categories_selector_class_init (ECategoriesSelectorClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (ECategoriesSelectorPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = categories_selector_set_property;
+ object_class->get_property = categories_selector_get_property;
+ object_class->dispose = categories_selector_dispose;
+ object_class->finalize = categories_selector_finalize;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ITEMS_CHECKABLE,
+ g_param_spec_boolean (
+ "items-checkable",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ signals[CATEGORY_CHECKED] = g_signal_new (
+ "category-checked",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (ECategoriesSelectorClass, category_checked),
+ NULL, NULL,
+ e_data_server_ui_marshal_VOID__STRING_BOOLEAN,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN);
+
+ signals[SELECTION_CHANGED] = g_signal_new (
+ "selection-changed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (ECategoriesSelectorClass, selection_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ GTK_TYPE_TREE_SELECTION);
+}
+
+static void
+e_categories_selector_init (ECategoriesSelector *selector)
+{
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ GtkTreeSelection *selection;
+
+ selector->priv = G_TYPE_INSTANCE_GET_PRIVATE (
+ selector, E_TYPE_CATEGORIES_SELECTOR,
+ ECategoriesSelectorPrivate);
+
+ selector->priv->checkable = TRUE;
+ selector->priv->selected_categories = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+ selector->priv->ignore_category_changes = FALSE;
+
+ renderer = gtk_cell_renderer_toggle_new ();
+ column = gtk_tree_view_column_new_with_attributes (
+ "?", renderer, "active", COLUMN_ACTIVE, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (selector), column);
+
+ g_signal_connect (
+ renderer, "toggled",
+ G_CALLBACK (category_toggled_cb), selector);
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ column = gtk_tree_view_column_new_with_attributes (
+ _("Icon"), renderer, "pixbuf", COLUMN_ICON, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (selector), column);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (
+ _("Category"), renderer, "text", COLUMN_CATEGORY, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (selector), column);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selector));
+ g_signal_connect (
+ selection, "changed",
+ G_CALLBACK (categories_selector_selection_changed), selector);
+
+ g_signal_connect (
+ selector, "key-press-event",
+ G_CALLBACK(categories_selector_key_press_event), NULL);
+
+ e_categories_register_change_listener (
+ G_CALLBACK (categories_selector_listener_cb), selector);
+
+ categories_selector_build_model (selector);
+}
+
+/**
+ * e_categories_selector_new:
+ *
+ * Since: 3.2
+ **/
+GtkWidget *
+e_categories_selector_new (void)
+{
+ return g_object_new (
+ E_TYPE_CATEGORIES_SELECTOR,
+ "items-checkable", TRUE, NULL);
+}
+
+/**
+ * e_categories_selector_get_items_checkable:
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_categories_selector_get_items_checkable (ECategoriesSelector *selector)
+{
+ g_return_val_if_fail (E_IS_CATEGORIES_SELECTOR (selector), TRUE);
+
+ return selector->priv->checkable;
+}
+
+/**
+ * e_categories_selector_set_items_checkable:
+ *
+ * Since: 3.2
+ **/
+void
+e_categories_selector_set_items_checkable (ECategoriesSelector *selector,
+ gboolean checkable)
+{
+ GtkTreeViewColumn *column;
+
+ g_return_if_fail (E_IS_CATEGORIES_SELECTOR (selector));
+
+ selector->priv->checkable = checkable;
+
+ column = gtk_tree_view_get_column (
+ GTK_TREE_VIEW (selector), COLUMN_ACTIVE);
+ gtk_tree_view_column_set_visible (column, checkable);
+
+ g_object_notify (G_OBJECT (selector), "items-checkable");
+}
+
+/**
+ * e_categories_selector_get_checked:
+ *
+ * Since: 3.2
+ **/
+const gchar *
+e_categories_selector_get_checked (ECategoriesSelector *selector)
+{
+ GString *str = g_string_new ("");
+ GList *list, *category;
+
+ g_return_val_if_fail (E_IS_CATEGORIES_SELECTOR (selector), NULL);
+
+ list = g_hash_table_get_values (selector->priv->selected_categories);
+
+ for (category = list; category != NULL; category = category->next) {
+ if (str->len > 0)
+ g_string_append_printf (
+ str, ",%s", (gchar *) category->data);
+ else
+ g_string_append (str, (gchar *) category->data);
+ }
+
+ g_list_free (list);
+
+ return g_string_free (str, FALSE);
+}
+
+/**
+ * e_categories_selector_set_checked:
+ *
+ * Since: 3.2
+ **/
+void
+e_categories_selector_set_checked (ECategoriesSelector *selector,
+ const gchar *categories)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gchar **arr;
+ gint i;
+
+ g_return_if_fail (E_IS_CATEGORIES_SELECTOR (selector));
+
+ /* Clean up table of selected categories. */
+ g_hash_table_remove_all (selector->priv->selected_categories);
+
+ arr = g_strsplit (categories, ",", 0);
+ if (arr) {
+ for (i = 0; arr[i] != NULL; i++) {
+ g_strstrip (arr[i]);
+ g_hash_table_insert (
+ selector->priv->selected_categories,
+ g_strdup (arr[i]), g_strdup (arr[i]));
+ }
+ g_strfreev (arr);
+ }
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
+ if (gtk_tree_model_get_iter_first (model, &iter)) {
+ do {
+ gchar *category_name;
+ gboolean found;
+
+ gtk_tree_model_get (model, &iter,
+ COLUMN_CATEGORY, &category_name,
+ -1);
+ found = (g_hash_table_lookup (
+ selector->priv->selected_categories,
+ category_name) != NULL);
+ gtk_list_store_set (
+ GTK_LIST_STORE (model), &iter,
+ COLUMN_ACTIVE, found, -1);
+
+ g_free (category_name);
+ } while (gtk_tree_model_iter_next (model, &iter));
+ }
+}
+
+/**
+ * e_categories_selector_delete_selection:
+ *
+ * Since: 3.2
+ **/
+void
+e_categories_selector_delete_selection (ECategoriesSelector *selector)
+{
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GList *selected, *item;
+
+ g_return_if_fail (E_IS_CATEGORIES_SELECTOR (selector));
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
+ g_return_if_fail (model != NULL);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selector));
+ selected = gtk_tree_selection_get_selected_rows (selection, &model);
+
+ /* Remove categories in reverse order to avoid invalidating
+ * tree paths as we iterate over the list. Note, the list is
+ * probably already sorted but we sort again just to be safe. */
+ selected = g_list_reverse (g_list_sort (
+ selected, (GCompareFunc) gtk_tree_path_compare));
+
+ /* Prevent the model from being rebuilt every time we
+ remove a category, since we're already modifying it. */
+ selector->priv->ignore_category_changes = TRUE;
+
+ for (item = selected; item != NULL; item = item->next) {
+ GtkTreePath *path = item->data;
+ GtkTreeIter iter;
+ gchar *category;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ COLUMN_CATEGORY, &category, -1);
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+ e_categories_remove (category);
+ g_free (category);
+ }
+
+ selector->priv->ignore_category_changes = FALSE;
+
+ /* If we only remove one category, try to select another */
+ if (g_list_length (selected) == 1) {
+ GtkTreePath *path = selected->data;
+
+ gtk_tree_selection_select_path (selection, path);
+ if (!gtk_tree_selection_path_is_selected (selection, path))
+ if (gtk_tree_path_prev (path))
+ gtk_tree_selection_select_path (selection, path);
+ }
+
+ g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (selected);
+}
+
+/**
+ * e_categories_selector_get_selected:
+ *
+ * Since: 3.2
+ **/
+const gchar *
+e_categories_selector_get_selected (ECategoriesSelector *selector)
+{
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GList *selected, *item;
+ GString *str = g_string_new ("");
+
+ g_return_val_if_fail (E_IS_CATEGORIES_SELECTOR (selector), NULL);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
+ g_return_val_if_fail (model != NULL, NULL);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selector));
+ selected = gtk_tree_selection_get_selected_rows (selection, &model);
+
+ for (item = selected; item != NULL; item = item->next) {
+ GtkTreePath *path = item->data;
+ GtkTreeIter iter;
+ gchar *category;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ COLUMN_CATEGORY, &category, -1);
+ if (str->len == 0)
+ g_string_assign (str, category);
+ else
+ g_string_append_printf (str, ",%s", category);
+
+ g_free (category);
+ }
+
+ g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (selected);
+
+ return g_string_free (str, FALSE);
+}
diff --git a/libedataserverui/e-categories-selector.h b/libedataserverui/e-categories-selector.h
new file mode 100644
index 0000000..75dbfa5
--- /dev/null
+++ b/libedataserverui/e-categories-selector.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef E_CATEGORIES_SELECTOR_H
+#define E_CATEGORIES_SELECTOR_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CATEGORIES_SELECTOR \
+ (e_categories_selector_get_type ())
+#define E_CATEGORIES_SELECTOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CATEGORIES_SELECTOR, ECategoriesSelector))
+#define E_CATEGORIES_SELECTOR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CATEGORIES_SELECTOR, ECategoriesSelectorClass))
+#define E_IS_CATEGORIES_SELECTOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CATEGORIES_SELECTOR))
+#define E_IS_CATEGORIES_SELECTOR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CATEGORIES_SELECTOR))
+#define E_CATEGORIES_SELECTOR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CATEGORIES_SELECTOR, ECategoriesSelectorClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECategoriesSelector ECategoriesSelector;
+typedef struct _ECategoriesSelectorClass ECategoriesSelectorClass;
+typedef struct _ECategoriesSelectorPrivate ECategoriesSelectorPrivate;
+
+struct _ECategoriesSelector {
+ GtkTreeView parent;
+ ECategoriesSelectorPrivate *priv;
+};
+
+struct _ECategoriesSelectorClass {
+ GtkTreeViewClass parent_class;
+
+ void (*category_checked) (ECategoriesSelector *selector,
+ const gchar *category,
+ gboolean checked);
+
+ void (*selection_changed) (ECategoriesSelector *selector,
+ GtkTreeSelection *selection);
+};
+
+GType e_categories_selector_get_type (void);
+GtkWidget * e_categories_selector_new (void);
+const gchar * e_categories_selector_get_checked
+ (ECategoriesSelector *selector);
+void e_categories_selector_set_checked
+ (ECategoriesSelector *selector,
+ const gchar *categories);
+gboolean e_categories_selector_get_items_checkable
+ (ECategoriesSelector *selector);
+void e_categories_selector_set_items_checkable
+ (ECategoriesSelector *selectr,
+ gboolean checkable);
+void e_categories_selector_delete_selection
+ (ECategoriesSelector *selector);
+const gchar * e_categories_selector_get_selected
+ (ECategoriesSelector *selector);
+
+G_END_DECLS
+
+#endif /* E_CATEGORIES_SELECTOR_H */
diff --git a/libedataserverui/e-category-editor.c b/libedataserverui/e-category-editor.c
new file mode 100644
index 0000000..958a578
--- /dev/null
+++ b/libedataserverui/e-category-editor.c
@@ -0,0 +1,348 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n-lib.h>
+#include "libedataserver/e-categories.h"
+#include "e-category-editor.h"
+
+G_DEFINE_TYPE (ECategoryEditor, e_category_editor, GTK_TYPE_DIALOG)
+
+struct _ECategoryEditorPrivate {
+ GtkWidget *category_name;
+ GtkWidget *category_icon;
+};
+
+static void
+update_preview (GtkFileChooser *chooser,
+ gpointer user_data)
+{
+ GtkImage *image;
+ gchar *filename;
+
+ g_return_if_fail (chooser != NULL);
+
+ image = GTK_IMAGE (gtk_file_chooser_get_preview_widget (chooser));
+ g_return_if_fail (image != NULL);
+
+ filename = gtk_file_chooser_get_preview_filename (chooser);
+
+ gtk_image_set_from_file (image, filename);
+ gtk_file_chooser_set_preview_widget_active (chooser, filename != NULL);
+
+ g_free (filename);
+}
+
+static void
+file_chooser_response (GtkDialog *dialog,
+ gint response_id,
+ GtkFileChooser *button)
+{
+ g_return_if_fail (button != NULL);
+
+ if (response_id == GTK_RESPONSE_NO)
+ gtk_file_chooser_unselect_all (button);
+}
+
+static void
+category_editor_category_name_changed (GtkEntry *category_name_entry,
+ ECategoryEditor *editor)
+{
+ gchar *name;
+
+ g_return_if_fail (editor != NULL);
+ g_return_if_fail (category_name_entry != NULL);
+
+ name = g_strdup (gtk_entry_get_text (category_name_entry));
+ if (name != NULL)
+ name = g_strstrip (name);
+
+ gtk_dialog_set_response_sensitive (
+ GTK_DIALOG (editor), GTK_RESPONSE_OK, name && *name);
+
+ g_free (name);
+}
+
+static gchar *
+check_category_name (const gchar *name)
+{
+ GString *str = NULL;
+ gchar *p = (gchar *) name;
+
+ str = g_string_new ("");
+ while (*p) {
+ switch (*p) {
+ case ',':
+ break;
+ default:
+ str = g_string_append_c (str, *p);
+ }
+ p++;
+ }
+
+ p = g_strstrip (g_string_free (str, FALSE));
+
+ return p;
+}
+
+static void
+e_category_editor_class_init (ECategoryEditorClass *class)
+{
+ g_type_class_add_private (class, sizeof (ECategoryEditorPrivate));
+}
+
+static void
+e_category_editor_init (ECategoryEditor *editor)
+{
+ GtkWidget *dialog_content;
+ GtkWidget *dialog_action_area;
+ GtkWidget *table_category_properties;
+ GtkWidget *label_name;
+ GtkWidget *label_icon;
+ GtkWidget *category_name;
+ GtkWidget *chooser_button;
+ GtkWidget *no_image_button;
+ GtkWidget *chooser_dialog;
+ GtkWidget *preview;
+
+ editor->priv = G_TYPE_INSTANCE_GET_PRIVATE (
+ editor, E_TYPE_CATEGORY_EDITOR, ECategoryEditorPrivate);
+
+ chooser_dialog = gtk_file_chooser_dialog_new (
+ _("Category Icon"),
+ NULL, GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
+
+ no_image_button = gtk_button_new_with_mnemonic (_("_No Image"));
+ gtk_button_set_image (
+ GTK_BUTTON (no_image_button),
+ gtk_image_new_from_stock (
+ GTK_STOCK_CLOSE, GTK_ICON_SIZE_BUTTON));
+ gtk_dialog_add_action_widget (
+ GTK_DIALOG (chooser_dialog),
+ no_image_button, GTK_RESPONSE_NO);
+ gtk_dialog_add_button (
+ GTK_DIALOG (chooser_dialog),
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT);
+ gtk_file_chooser_set_local_only (
+ GTK_FILE_CHOOSER (chooser_dialog), TRUE);
+ gtk_widget_show (no_image_button);
+
+ g_signal_connect (
+ chooser_dialog, "update-preview",
+ G_CALLBACK (update_preview), NULL);
+
+ preview = gtk_image_new();
+ gtk_file_chooser_set_preview_widget (
+ GTK_FILE_CHOOSER (chooser_dialog), preview);
+ gtk_file_chooser_set_preview_widget_active (
+ GTK_FILE_CHOOSER (chooser_dialog), TRUE);
+ gtk_widget_show_all (preview);
+
+ dialog_content = gtk_dialog_get_content_area (GTK_DIALOG (editor));
+
+ table_category_properties = gtk_table_new (3, 2, FALSE);
+ gtk_box_pack_start (
+ GTK_BOX (dialog_content),
+ table_category_properties, TRUE, TRUE, 0);
+ gtk_container_set_border_width (
+ GTK_CONTAINER (table_category_properties), 12);
+ gtk_table_set_row_spacings (GTK_TABLE (table_category_properties), 6);
+ gtk_table_set_col_spacings (GTK_TABLE (table_category_properties), 6);
+
+ label_name = gtk_label_new_with_mnemonic (_("Category _Name"));
+ gtk_misc_set_alignment (GTK_MISC (label_name), 0, 0.5);
+ gtk_table_attach (
+ GTK_TABLE (table_category_properties),
+ label_name, 0, 1, 0, 1,
+ (GtkAttachOptions) GTK_FILL,
+ (GtkAttachOptions) 0, 0, 0);
+
+ label_icon = gtk_label_new_with_mnemonic (_("Category _Icon"));
+ gtk_misc_set_alignment (GTK_MISC (label_icon), 0, 0.5);
+ gtk_table_attach (
+ GTK_TABLE (table_category_properties),
+ label_icon, 0, 1, 2, 3,
+ (GtkAttachOptions) GTK_FILL,
+ (GtkAttachOptions) 0, 0, 0);
+
+ category_name = gtk_entry_new ();
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label_name), category_name);
+ gtk_table_attach (
+ GTK_TABLE (table_category_properties),
+ category_name, 1, 2, 0, 1,
+ (GtkAttachOptions) GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ (GtkAttachOptions) 0, 0, 0);
+ editor->priv->category_name = category_name;
+
+ chooser_button = GTK_WIDGET (
+ gtk_file_chooser_button_new_with_dialog (chooser_dialog));
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label_icon), chooser_button);
+ gtk_table_attach (
+ GTK_TABLE (table_category_properties),
+ chooser_button, 1, 2, 2, 3,
+ (GtkAttachOptions) GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ (GtkAttachOptions) 0, 0, 0);
+ editor->priv->category_icon = chooser_button;
+
+ g_signal_connect (
+ chooser_dialog, "response",
+ G_CALLBACK (file_chooser_response), chooser_button);
+
+ dialog_action_area = gtk_dialog_get_action_area (GTK_DIALOG (editor));
+ gtk_button_box_set_layout (
+ GTK_BUTTON_BOX (dialog_action_area), GTK_BUTTONBOX_END);
+
+ gtk_dialog_add_buttons (
+ GTK_DIALOG (editor),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (editor), GTK_RESPONSE_OK);
+ gtk_window_set_title (GTK_WINDOW (editor), _("Category Properties"));
+ gtk_window_set_type_hint (
+ GTK_WINDOW (editor), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ gtk_widget_show_all (dialog_content);
+
+ g_signal_connect (
+ category_name, "changed",
+ G_CALLBACK (category_editor_category_name_changed), editor);
+
+ category_editor_category_name_changed (
+ GTK_ENTRY (category_name), editor);
+}
+
+/**
+ * e_categort_editor_new:
+ *
+ * Creates a new #ECategoryEditor widget.
+ *
+ * Returns: a new #ECategoryEditor
+ *
+ * Since: 3.2
+ **/
+ECategoryEditor *
+e_category_editor_new ()
+{
+ return g_object_new (E_TYPE_CATEGORY_EDITOR, NULL);
+}
+
+/**
+ * e_category_editor_create_category:
+ *
+ * Since: 3.2
+ **/
+const gchar *
+e_category_editor_create_category (ECategoryEditor *editor)
+{
+ GtkEntry *entry;
+ GtkFileChooser *file_chooser;
+
+ g_return_val_if_fail (E_IS_CATEGORY_EDITOR (editor), NULL);
+
+ entry = GTK_ENTRY (editor->priv->category_name);
+ file_chooser = GTK_FILE_CHOOSER (editor->priv->category_icon);
+
+ do {
+ const gchar *category_name;
+ const gchar *correct_category_name;
+
+ if (gtk_dialog_run (GTK_DIALOG (editor)) != GTK_RESPONSE_OK)
+ return NULL;
+
+ category_name = gtk_entry_get_text (entry);
+ correct_category_name = check_category_name (category_name);
+
+ if (e_categories_exist (correct_category_name)) {
+ GtkWidget *error_dialog;
+
+ error_dialog = gtk_message_dialog_new (
+ GTK_WINDOW (editor),
+ 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ _("There is already a category '%s' in the "
+ "configuration. Please use another name"),
+ category_name);
+
+ gtk_dialog_run (GTK_DIALOG (error_dialog));
+ gtk_widget_destroy (error_dialog);
+
+ /* Now we loop and run the dialog again. */
+
+ } else {
+ gchar *category_icon;
+
+ category_icon =
+ gtk_file_chooser_get_filename (file_chooser);
+ e_categories_add (
+ correct_category_name, NULL,
+ category_icon, TRUE);
+ g_free (category_icon);
+
+ return correct_category_name;
+ }
+
+ } while (TRUE);
+}
+
+/**
+ * e_category_editor_edit_category:
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_category_editor_edit_category (ECategoryEditor *editor,
+ const gchar *category)
+{
+ GtkFileChooser *file_chooser;
+ const gchar *icon_file;
+
+ g_return_val_if_fail (E_IS_CATEGORY_EDITOR (editor), FALSE);
+ g_return_val_if_fail (category != NULL, FALSE);
+
+ file_chooser = GTK_FILE_CHOOSER (editor->priv->category_icon);
+
+ gtk_entry_set_text (GTK_ENTRY (editor->priv->category_name), category);
+ gtk_widget_set_sensitive (editor->priv->category_name, FALSE);
+
+ icon_file = e_categories_get_icon_file_for (category);
+ if (icon_file) {
+ gtk_file_chooser_set_filename (file_chooser, icon_file);
+ update_preview (file_chooser, NULL);
+ }
+
+ if (gtk_dialog_run (GTK_DIALOG (editor)) == GTK_RESPONSE_OK) {
+ gchar *category_icon;
+
+ category_icon = gtk_file_chooser_get_filename (file_chooser);
+ e_categories_set_icon_file_for (category, category_icon);
+
+ gtk_dialog_set_response_sensitive (
+ GTK_DIALOG (editor), GTK_RESPONSE_OK, TRUE);
+
+ g_free (category_icon);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/libedataserverui/e-category-editor.h b/libedataserverui/e-category-editor.h
new file mode 100644
index 0000000..19c706b
--- /dev/null
+++ b/libedataserverui/e-category-editor.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef E_CATEGORY_EDITOR_H
+#define E_CATEGORY_EDITOR_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CATEGORY_EDITOR \
+ (e_category_editor_get_type ())
+#define E_CATEGORY_EDITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CATEGORY_EDITOR, ECategoryEditor))
+#define E_CATEGORY_EDITOR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CATEGORY_EDITOR, ECategoryEditorClass))
+#define E_IS_CATEGORY_EDITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CATEGORY_EDITOR))
+#define E_IS_CATEGORY_EDITOR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CATEGORY_EDITOR))
+#define E_CATEGORY_EDITOR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CATEGORY_EDITOR, ECategoryEditorClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECategoryEditor ECategoryEditor;
+typedef struct _ECategoryEditorClass ECategoryEditorClass;
+typedef struct _ECategoryEditorPrivate ECategoryEditorPrivate;
+
+struct _ECategoryEditor {
+ GtkDialog parent;
+ ECategoryEditorPrivate *priv;
+};
+
+struct _ECategoryEditorClass {
+ GtkDialogClass parent_class;
+};
+
+GType e_category_editor_get_type (void);
+ECategoryEditor *
+ e_category_editor_new (void);
+const gchar * e_category_editor_create_category
+ (ECategoryEditor *editor);
+gboolean e_category_editor_edit_category (ECategoryEditor *editor,
+ const gchar *category);
+
+G_END_DECLS
+
+#endif /* E_CATEGORY_EDITOR_H */
diff --git a/libedataserverui/e-data-server-ui-marshal.list b/libedataserverui/e-data-server-ui-marshal.list
index 333b042..5b7fbe9 100644
--- a/libedataserverui/e-data-server-ui-marshal.list
+++ b/libedataserverui/e-data-server-ui-marshal.list
@@ -1,2 +1,3 @@
BOOLEAN:OBJECT,BOXED
BOOLEAN:BOXED,OBJECT,FLAGS,UINT
+NONE:STRING,BOOLEAN
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]