aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/gal-view-instance.c
diff options
context:
space:
mode:
Diffstat (limited to 'e-util/gal-view-instance.c')
-rw-r--r--e-util/gal-view-instance.c502
1 files changed, 502 insertions, 0 deletions
diff --git a/e-util/gal-view-instance.c b/e-util/gal-view-instance.c
new file mode 100644
index 0000000000..e0a107f146
--- /dev/null
+++ b/e-util/gal-view-instance.c
@@ -0,0 +1,502 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Lahey <clahey@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gal-view-instance.h"
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n.h>
+
+#include <libedataserver/libedataserver.h>
+
+#include "e-unicode.h"
+#include "e-xml-utils.h"
+#include "gal-define-views-dialog.h"
+#include "gal-view-instance-save-as-dialog.h"
+
+G_DEFINE_TYPE (GalViewInstance, gal_view_instance, G_TYPE_OBJECT)
+
+#define d(x)
+
+enum {
+ DISPLAY_VIEW,
+ CHANGED,
+ LOADED,
+ LAST_SIGNAL
+};
+
+static guint gal_view_instance_signals[LAST_SIGNAL] = { 0, };
+
+static void
+gal_view_instance_changed (GalViewInstance *instance)
+{
+ g_return_if_fail (instance != NULL);
+ g_return_if_fail (GAL_IS_VIEW_INSTANCE (instance));
+
+ g_signal_emit (
+ instance,
+ gal_view_instance_signals[CHANGED], 0);
+}
+
+static void
+gal_view_instance_display_view (GalViewInstance *instance,
+ GalView *view)
+{
+ g_return_if_fail (instance != NULL);
+ g_return_if_fail (GAL_IS_VIEW_INSTANCE (instance));
+
+ g_signal_emit (
+ instance,
+ gal_view_instance_signals[DISPLAY_VIEW], 0,
+ view);
+}
+
+static void
+save_current_view (GalViewInstance *instance)
+{
+ xmlDoc *doc;
+ xmlNode *root;
+
+ doc = xmlNewDoc ((const guchar *)"1.0");
+ root = xmlNewNode (NULL, (const guchar *)"GalViewCurrentView");
+ xmlDocSetRootElement (doc, root);
+
+ if (instance->current_id)
+ e_xml_set_string_prop_by_name (root, (const guchar *)"current_view", instance->current_id);
+ if (instance->current_type)
+ e_xml_set_string_prop_by_name (root, (const guchar *)"current_view_type", instance->current_type);
+
+ if (e_xml_save_file (instance->current_view_filename, doc) == -1)
+ g_warning ("Unable to save view to %s - %s", instance->current_view_filename, g_strerror (errno));
+ xmlFreeDoc (doc);
+}
+
+static void
+view_changed (GalView *view,
+ GalViewInstance *instance)
+{
+ if (instance->current_id != NULL) {
+ g_free (instance->current_id);
+ instance->current_id = NULL;
+ save_current_view (instance);
+ gal_view_instance_changed (instance);
+ }
+
+ gal_view_save (view, instance->custom_filename);
+}
+
+static void
+disconnect_view (GalViewInstance *instance)
+{
+ if (instance->current_view) {
+ if (instance->view_changed_id) {
+ g_signal_handler_disconnect (
+ instance->current_view,
+ instance->view_changed_id);
+ }
+
+ g_object_unref (instance->current_view);
+ }
+ g_free (instance->current_type);
+ g_free (instance->current_title);
+ instance->current_title = NULL;
+ instance->current_type = NULL;
+ instance->view_changed_id = 0;
+ instance->current_view = NULL;
+}
+
+static void
+connect_view (GalViewInstance *instance,
+ GalView *view)
+{
+ if (instance->current_view)
+ disconnect_view (instance);
+ instance->current_view = view;
+
+ instance->current_title = g_strdup (gal_view_get_title (view));
+ instance->current_type = g_strdup (gal_view_get_type_code (view));
+ instance->view_changed_id = g_signal_connect (
+ instance->current_view, "changed",
+ G_CALLBACK (view_changed), instance);
+
+ gal_view_instance_display_view (instance, instance->current_view);
+}
+
+static void
+gal_view_instance_dispose (GObject *object)
+{
+ GalViewInstance *instance = GAL_VIEW_INSTANCE (object);
+
+ if (instance->collection) {
+ if (instance->collection_changed_id) {
+ g_signal_handler_disconnect (
+ instance->collection,
+ instance->collection_changed_id);
+ }
+ g_object_unref (instance->collection);
+ }
+
+ g_free (instance->instance_id);
+ g_free (instance->custom_filename);
+ g_free (instance->current_view_filename);
+
+ g_free (instance->current_id);
+ disconnect_view (instance);
+
+ g_free (instance->default_view);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (gal_view_instance_parent_class)->dispose (object);
+}
+
+static void
+gal_view_instance_class_init (GalViewInstanceClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->dispose = gal_view_instance_dispose;
+
+ gal_view_instance_signals[DISPLAY_VIEW] = g_signal_new (
+ "display_view",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GalViewInstanceClass, display_view),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ GAL_TYPE_VIEW);
+
+ gal_view_instance_signals[CHANGED] = g_signal_new (
+ "changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GalViewInstanceClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ gal_view_instance_signals[LOADED] = g_signal_new (
+ "loaded",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GalViewInstanceClass, loaded),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ class->display_view = NULL;
+ class->changed = NULL;
+}
+
+static void
+gal_view_instance_init (GalViewInstance *instance)
+{
+ instance->collection = NULL;
+
+ instance->instance_id = NULL;
+ instance->custom_filename = NULL;
+ instance->current_view_filename = NULL;
+
+ instance->current_title = NULL;
+ instance->current_type = NULL;
+ instance->current_id = NULL;
+ instance->current_view = NULL;
+
+ instance->view_changed_id = 0;
+ instance->collection_changed_id = 0;
+
+ instance->loaded = FALSE;
+ instance->default_view = NULL;
+}
+
+static void
+collection_changed (GalView *view,
+ GalViewInstance *instance)
+{
+ if (instance->current_id) {
+ gchar *view_id = instance->current_id;
+ instance->current_id = NULL;
+ gal_view_instance_set_current_view_id (instance, view_id);
+ g_free (view_id);
+ }
+}
+
+static void
+load_current_view (GalViewInstance *instance)
+{
+ xmlDoc *doc = NULL;
+ xmlNode *root;
+ GalView *view = NULL;
+
+ if (g_file_test (instance->current_view_filename, G_FILE_TEST_IS_REGULAR)) {
+#ifdef G_OS_WIN32
+ gchar *locale_filename = g_win32_locale_filename_from_utf8 (instance->current_view_filename);
+ if (locale_filename != NULL)
+ doc = xmlParseFile (locale_filename);
+ g_free (locale_filename);
+#else
+ doc = xmlParseFile (instance->current_view_filename);
+#endif
+ }
+
+ if (doc == NULL) {
+ instance->current_id = g_strdup (gal_view_instance_get_default_view (instance));
+
+ if (instance->current_id) {
+ gint index = gal_view_collection_get_view_index_by_id (
+ instance->collection,
+ instance->current_id);
+
+ if (index != -1) {
+ view = gal_view_collection_get_view (
+ instance->collection, index);
+ view = gal_view_clone (view);
+ connect_view (instance, view);
+ }
+ }
+ return;
+ }
+
+ root = xmlDocGetRootElement (doc);
+ instance->current_id = e_xml_get_string_prop_by_name_with_default (root, (const guchar *)"current_view", NULL);
+
+ if (instance->current_id != NULL) {
+ gint index = gal_view_collection_get_view_index_by_id (
+ instance->collection,
+ instance->current_id);
+
+ if (index != -1) {
+ view = gal_view_collection_get_view (
+ instance->collection, index);
+ view = gal_view_clone (view);
+ }
+ }
+ if (view == NULL) {
+ gchar *type;
+ type = e_xml_get_string_prop_by_name_with_default (root, (const guchar *)"current_view_type", NULL);
+ view = gal_view_collection_load_view_from_file (
+ instance->collection, type,
+ instance->custom_filename);
+ g_free (type);
+ }
+
+ connect_view (instance, view);
+
+ xmlFreeDoc (doc);
+}
+
+/**
+ * gal_view_instance_new:
+ * @collection: This %GalViewCollection should be loaded before being passed to this function.
+ * @instance_id: Which instance of this type of object is this (for most of evo, this is the folder id.)
+ *
+ * Create a new %GalViewInstance.
+ *
+ * Return value: The new %GalViewInstance.
+ **/
+GalViewInstance *
+gal_view_instance_new (GalViewCollection *collection,
+ const gchar *instance_id)
+{
+ GalViewInstance *instance = g_object_new (GAL_VIEW_INSTANCE_TYPE, NULL);
+ if (gal_view_instance_construct (instance, collection, instance_id))
+ return instance;
+ else {
+ g_object_unref (instance);
+ return NULL;
+ }
+}
+
+GalViewInstance *
+gal_view_instance_construct (GalViewInstance *instance,
+ GalViewCollection *collection,
+ const gchar *instance_id)
+{
+ gchar *filename;
+ gchar *safe_id;
+
+ g_return_val_if_fail (gal_view_collection_loaded (collection), NULL);
+
+ instance->collection = collection;
+ if (collection)
+ g_object_ref (collection);
+ instance->collection_changed_id = g_signal_connect (
+ collection, "changed",
+ G_CALLBACK (collection_changed), instance);
+
+ if (instance_id)
+ instance->instance_id = g_strdup (instance_id);
+ else
+ instance->instance_id = g_strdup ("");
+
+ safe_id = g_strdup (instance->instance_id);
+ e_filename_make_safe (safe_id);
+
+ filename = g_strdup_printf ("custom_view-%s.xml", safe_id);
+ instance->custom_filename = g_build_filename (instance->collection->local_dir, filename, NULL);
+ g_free (filename);
+
+ filename = g_strdup_printf ("current_view-%s.xml", safe_id);
+ instance->current_view_filename = g_build_filename (instance->collection->local_dir, filename, NULL);
+ g_free (filename);
+
+ g_free (safe_id);
+
+ return instance;
+}
+
+/* Manipulate the current view. */
+gchar *
+gal_view_instance_get_current_view_id (GalViewInstance *instance)
+{
+ if (instance->current_id && gal_view_collection_get_view_index_by_id (instance->collection, instance->current_id) != -1)
+ return g_strdup (instance->current_id);
+ else
+ return NULL;
+}
+
+void
+gal_view_instance_set_current_view_id (GalViewInstance *instance,
+ const gchar *view_id)
+{
+ GalView *view;
+ gint index;
+
+ g_return_if_fail (instance != NULL);
+ g_return_if_fail (GAL_IS_VIEW_INSTANCE (instance));
+
+ d (g_print ("%s: view_id set to %s\n", G_STRFUNC, view_id));
+
+ if (instance->current_id && !strcmp (instance->current_id, view_id))
+ return;
+
+ g_free (instance->current_id);
+ instance->current_id = g_strdup (view_id);
+
+ index = gal_view_collection_get_view_index_by_id (instance->collection, view_id);
+ if (index != -1) {
+ view = gal_view_collection_get_view (instance->collection, index);
+ connect_view (instance, gal_view_clone (view));
+ }
+
+ if (instance->loaded)
+ save_current_view (instance);
+ gal_view_instance_changed (instance);
+}
+
+GalView *
+gal_view_instance_get_current_view (GalViewInstance *instance)
+{
+ return instance->current_view;
+}
+
+void
+gal_view_instance_set_custom_view (GalViewInstance *instance,
+ GalView *view)
+{
+ g_free (instance->current_id);
+ instance->current_id = NULL;
+
+ view = gal_view_clone (view);
+ connect_view (instance, view);
+ gal_view_save (view, instance->custom_filename);
+ save_current_view (instance);
+ gal_view_instance_changed (instance);
+}
+
+static void
+dialog_response (GtkWidget *dialog,
+ gint id,
+ GalViewInstance *instance)
+{
+ if (id == GTK_RESPONSE_OK) {
+ gal_view_instance_save_as_dialog_save (GAL_VIEW_INSTANCE_SAVE_AS_DIALOG (dialog));
+ }
+ gtk_widget_destroy (dialog);
+}
+
+void
+gal_view_instance_save_as (GalViewInstance *instance)
+{
+ GtkWidget *dialog;
+
+ g_return_if_fail (instance != NULL);
+
+ dialog = gal_view_instance_save_as_dialog_new (instance);
+ g_signal_connect (
+ dialog, "response",
+ G_CALLBACK (dialog_response), instance);
+ gtk_widget_show (dialog);
+}
+
+/* This is idempotent. Once it's been called once, the rest of the calls are ignored. */
+void
+gal_view_instance_load (GalViewInstance *instance)
+{
+ if (!instance->loaded) {
+ load_current_view (instance);
+ instance->loaded = TRUE;
+ g_signal_emit (instance, gal_view_instance_signals[LOADED], 0);
+ }
+}
+
+/* These only mean anything before gal_view_instance_load is called the first time. */
+const gchar *
+gal_view_instance_get_default_view (GalViewInstance *instance)
+{
+ if (instance->default_view)
+ return instance->default_view;
+ else
+ return gal_view_collection_get_default_view (instance->collection);
+}
+
+void
+gal_view_instance_set_default_view (GalViewInstance *instance,
+ const gchar *id)
+{
+ g_free (instance->default_view);
+ instance->default_view = g_strdup (id);
+}
+
+gboolean
+gal_view_instance_exists (GalViewInstance *instance)
+{
+ struct stat st;
+
+ if (instance->current_view_filename && g_stat (instance->current_view_filename, &st) == 0 && st.st_size > 0 && S_ISREG (st.st_mode))
+ return TRUE;
+ else
+ return FALSE;
+
+}