[evolution-kolab] EPlugin: added dialog for sync conflict resolution



commit f87506d7ab04c1a5a245cfd477505616fdf20ce1
Author: Christian Hilberg <hilberg kernelconcepts de>
Date:   Tue Feb 21 15:17:02 2012 +0100

    EPlugin: added dialog for sync conflict resolution
    
    * replicates https://roundup.kolab.org/file1562/new-conflictdialog-7-en.png,
      minus the "Details..." buttons which we will leave out for the
      first shot
    * no functionality as yet, dialog will not be visible
      until the frontend<->backend extra communication
      has been implemented

 src/eplugin/Makefile.am                     |    2 +
 src/eplugin/e-kolab-backend-sync-conflict.c |  370 +++++++++++++++++++++++++++
 src/eplugin/e-kolab-backend-sync-conflict.h |   47 ++++
 src/eplugin/e-kolab-plugin.c                |   10 +
 4 files changed, 429 insertions(+), 0 deletions(-)
---
diff --git a/src/eplugin/Makefile.am b/src/eplugin/Makefile.am
index 8ae9677..45ea299 100644
--- a/src/eplugin/Makefile.am
+++ b/src/eplugin/Makefile.am
@@ -11,6 +11,7 @@ AM_CPPFLAGS =				\
 
 noinst_HEADERS =			\
 	e-kolab-account-setup.h		\
+	e-kolab-backend-sync-conflict.h	\
 	e-kolab-folder-metadata.h	\
 	e-kolab-folder-permissions.h	\
 	e-kolab-freebusy.h		\
@@ -26,6 +27,7 @@ plugin_LTLIBRARIES = liborg-gnome-kolab.la
 
 liborg_gnome_kolab_la_SOURCES =		\
 	e-kolab-account-setup.c		\
+	e-kolab-backend-sync-conflict.c	\
 	e-kolab-folder-metadata.c	\
 	e-kolab-folder-permissions.c	\
 	e-kolab-freebusy.c		\
diff --git a/src/eplugin/e-kolab-backend-sync-conflict.c b/src/eplugin/e-kolab-backend-sync-conflict.c
new file mode 100644
index 0000000..76dd2d4
--- /dev/null
+++ b/src/eplugin/e-kolab-backend-sync-conflict.c
@@ -0,0 +1,370 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/***************************************************************************
+ *            e-kolab-backend-sync-conflict.c
+ *
+ *  Fri Feb 20 22:54:05 2012
+ *  Copyright  2012  Christian Hilberg
+ *  <hilberg kernelconcepts de>
+ *
+ ****************************************************************************/
+
+/*
+ * 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.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
+ */
+/*----------------------------------------------------------------------------*/
+
+#include <config.h>
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <glib/gi18n-lib.h>
+
+#include "e-kolab-backend-sync-conflict.h"
+
+/*----------------------------------------------------------------------------*/
+
+typedef struct _KolabBackendSyncConflictUIWidgets KolabBackendSyncConflictUIWidgets;
+struct _KolabBackendSyncConflictUIWidgets {
+	GtkWidget *container;
+	/* sub-widgets of container */
+	GtkWidget *lbl_folder_name;
+	GtkWidget *lbl_local_subject;
+	GtkWidget *lbl_local_modtime;
+	GtkWidget *lbl_remote_subject;
+	GtkWidget *lbl_remote_modtime;
+	GSList *radio_group;
+	GtkWidget *radio_btn_this_sync;
+	GtkWidget *radio_btn_this_session;
+	GtkWidget *radio_btn_permanent;
+	GtkWidget *radio_btn_ask_again;
+	GtkWidget *btn_strategy_newer;
+	GtkWidget *btn_strategy_server;
+	GtkWidget *btn_strategy_client;
+	GtkWidget *btn_strategy_dupe;
+};
+
+typedef struct _KolabBackendSyncConflictUIData KolabBackendSyncConflictUIData;
+struct _KolabBackendSyncConflictUIData {
+	KolabBackendSyncConflictUIWidgets *widgets;
+	/* FIXME add payload "data" part here */
+};
+
+/* corresponds to sync strategy,
+ * maybe we can unify this
+ */
+enum {
+	KOLAB_SYNC_CONFLICT_RESPONSE_NEWER = 0,
+	KOLAB_SYNC_CONFLICT_RESPONSE_SERVER,
+	KOLAB_SYNC_CONFLICT_RESPONSE_CLIENT,
+	KOLAB_SYNC_CONFLICT_RESPONSE_DUPE,
+	KOLAB_SYNC_CONFLICT_LAST_RESPONSE,
+	KOLAB_SYNC_CONFLICT_RESPONSE_DEFAULT = KOLAB_SYNC_CONFLICT_RESPONSE_NEWER
+};
+
+#define KOLAB_SYNC_CONFLICT_WIDGET_BORDER_WIDTH 8
+
+/*----------------------------------------------------------------------------*/
+/* internal statics (non-UI) */
+
+
+/*----------------------------------------------------------------------------*/
+/* internal statics (UI) */
+
+
+/*----------------------------------------------------------------------------*/
+/* API functions (non-UI) */
+
+/*----------------------------------------------------------------------------*/
+/* API functions (UI) */
+
+static KolabBackendSyncConflictUIData*
+kolab_backend_sync_conflict_ui_new (void)
+{
+	KolabBackendSyncConflictUIData *uidata = g_new0 (KolabBackendSyncConflictUIData, 1);
+	GtkWidget *content = NULL;
+	GtkWidget *ev_box = NULL;
+	GtkWidget *frame_info = NULL;
+	GtkWidget *frame_take_dur = NULL;
+	GtkWidget *frame_take = NULL;
+	GtkGrid *grid = NULL;
+	GtkWidget *widget = NULL;
+	GtkWidget *label = NULL;
+	gchar *tmp_str = NULL;
+	const guint state_flags = GTK_STATE_FLAG_NORMAL;
+	const GdkRGBA color = { 0.933, 0.965, 1.0, 1.0 };
+	gint row = 0;
+
+	uidata->widgets = g_new0 (KolabBackendSyncConflictUIWidgets, 1);
+	uidata->widgets->container = gtk_dialog_new ();
+	gtk_window_set_modal (GTK_WINDOW (uidata->widgets->container), TRUE);
+	gtk_window_set_resizable (GTK_WINDOW (uidata->widgets->container), FALSE);
+	content = gtk_dialog_get_content_area (GTK_DIALOG (uidata->widgets->container));
+	gtk_container_set_border_width (GTK_CONTAINER (content), KOLAB_SYNC_CONFLICT_WIDGET_BORDER_WIDTH);
+
+	/* sync conflict information */
+	frame_info = gtk_frame_new (NULL);
+	gtk_container_set_border_width (GTK_CONTAINER (frame_info), KOLAB_SYNC_CONFLICT_WIDGET_BORDER_WIDTH);
+	gtk_container_add (GTK_CONTAINER (content), frame_info);
+	ev_box = gtk_event_box_new ();
+	gtk_container_set_border_width (GTK_CONTAINER (ev_box), 1);
+	gtk_widget_override_background_color (ev_box, state_flags, &color);
+	gtk_container_add (GTK_CONTAINER (frame_info), ev_box);
+	widget = gtk_label_new (NULL);
+	gtk_label_set_text (GTK_LABEL (widget),
+	                    _("A synchronization error occured: \nProbably someone modified an entry remotely (i.e. on the server), \nwhich you have also modified locally (i.e. on your client)."));
+	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_LEFT);
+	gtk_container_add (GTK_CONTAINER (ev_box), widget);
+
+	/* object detail */
+
+	grid = GTK_GRID (gtk_grid_new ());
+	gtk_grid_set_row_homogeneous (grid, TRUE);
+	gtk_grid_set_row_spacing (grid, 6);
+	gtk_grid_set_column_homogeneous (grid, FALSE);
+	gtk_grid_set_column_spacing (grid, 6);
+	gtk_container_set_border_width (GTK_CONTAINER (grid), KOLAB_SYNC_CONFLICT_WIDGET_BORDER_WIDTH);
+	/* gtk_container_set_resize_mode (GTK_CONTAINER (grid), GTK_RESIZE_QUEUE); */
+	gtk_container_add (GTK_CONTAINER (content), GTK_WIDGET (grid));
+
+	row = 0;
+
+	/* conflict folder name */
+	tmp_str = g_strconcat (_("Conflict in folder"), ":", NULL);
+	label = gtk_label_new (tmp_str);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+	g_free (tmp_str);
+	gtk_grid_attach (grid, label, 0, row, 1, 1);
+	label = gtk_label_new (NULL /* FIXME add folder path here */);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+	uidata->widgets->lbl_folder_name = label;
+	gtk_grid_attach (grid, label, 1, row, 1, 1);
+
+	row++;
+
+	/* local object - subject */
+	tmp_str = g_strconcat (_("Local entry"), ":", NULL);
+	label = gtk_label_new (tmp_str);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+	g_free (tmp_str);
+	gtk_grid_attach (grid, label, 0, row, 1, 1);
+	label = gtk_label_new (NULL /* FIXME add subject here */);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+	uidata->widgets->lbl_local_subject = label;
+	gtk_grid_attach (grid, label, 1, row, 1, 1);
+
+	row++;
+
+	/* local object - last modified */
+	tmp_str = g_strconcat (_("Last modified"), ":", NULL);
+	label = gtk_label_new (tmp_str);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+	g_free (tmp_str);
+	gtk_grid_attach (grid, label, 0, row, 1, 1);
+	label = gtk_label_new (NULL /* FIXME add modtime here */);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+	uidata->widgets->lbl_local_modtime = label;
+	gtk_grid_attach (grid, label, 1, row, 1, 1);
+
+	row++;
+
+	/* remote object - subject */
+	tmp_str = g_strconcat (_("Remote entry"), ":", NULL);
+	label = gtk_label_new (tmp_str);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+	g_free (tmp_str);
+	gtk_grid_attach (grid, label, 0, row, 1, 1);
+	label = gtk_label_new (NULL /* FIXME add subject here */);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+	uidata->widgets->lbl_remote_subject = label;
+	gtk_grid_attach (grid, label, 1, row, 1, 1);
+
+	row++;
+
+	/* remote object - last modified */
+	tmp_str = g_strconcat (_("Last modified"), ":", NULL);
+	label = gtk_label_new (tmp_str);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+	g_free (tmp_str);
+	gtk_grid_attach (grid, label, 0, row, 1, 1);
+	label = gtk_label_new (NULL /* FIXME add modtime here */);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+	uidata->widgets->lbl_remote_modtime = label;
+	gtk_grid_attach (grid, label, 1, row, 1, 1);
+
+	row++;
+
+	/* take option duration */
+
+	frame_take_dur = gtk_frame_new (_("Take option duration"));
+	gtk_container_set_border_width (GTK_CONTAINER (frame_take_dur), KOLAB_SYNC_CONFLICT_WIDGET_BORDER_WIDTH);
+	gtk_container_add (GTK_CONTAINER (content), frame_take_dur);
+
+	grid = GTK_GRID (gtk_grid_new ());
+	gtk_grid_set_row_homogeneous (grid, TRUE);
+	gtk_grid_set_row_spacing (grid, 0);
+	gtk_grid_set_column_homogeneous (grid, FALSE);
+	gtk_grid_set_column_spacing (grid, 6);
+	gtk_container_set_border_width (GTK_CONTAINER (grid), 6);
+	/* gtk_container_set_resize_mode (GTK_CONTAINER (grid), GTK_RESIZE_QUEUE); */
+	gtk_container_add (GTK_CONTAINER (frame_take_dur), GTK_WIDGET (grid));
+
+	row = 0;
+
+	tmp_str = g_strconcat (_("Please choose how long the \"Take option\" specified below \nshould remain in effect"), ":", NULL);
+	label = gtk_label_new (tmp_str);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+	g_free (tmp_str);
+	gtk_grid_attach (grid, label, 1, row, 1, 1);
+
+	row++;
+
+	widget = gtk_radio_button_new_with_label (NULL, _("Apply to all conflicts occuring during this synchronization"));
+	uidata->widgets->radio_btn_this_sync = widget;
+	uidata->widgets->radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
+	gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+	row++;
+
+	widget = gtk_radio_button_new_with_label (uidata->widgets->radio_group, _("Apply to all conflicts occuring during this Evolution session"));
+	uidata->widgets->radio_btn_this_session = widget;
+	gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+	row++;
+
+	widget = gtk_radio_button_new_with_label (uidata->widgets->radio_group, _("Apply always and permanently"));
+	uidata->widgets->radio_btn_permanent = widget;
+	gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+	row++;
+
+	widget = gtk_radio_button_new_with_label (uidata->widgets->radio_group, _("Apply only to this conflict (ask each time)"));
+	uidata->widgets->radio_btn_permanent = widget;
+	gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+	/* take options (actions!) */
+
+	frame_take = gtk_frame_new (_("Take options"));
+	gtk_container_set_border_width (GTK_CONTAINER (frame_take), KOLAB_SYNC_CONFLICT_WIDGET_BORDER_WIDTH);
+	gtk_container_add (GTK_CONTAINER (content), frame_take);
+
+	grid = GTK_GRID (gtk_grid_new ());
+	gtk_grid_set_row_homogeneous (grid, TRUE);
+	gtk_grid_set_row_spacing (grid, 2);
+	gtk_grid_set_column_homogeneous (grid, FALSE);
+	gtk_grid_set_column_spacing (grid, 6);
+	gtk_container_set_border_width (GTK_CONTAINER (grid), 6);
+	/* gtk_container_set_resize_mode (GTK_CONTAINER (grid), GTK_RESIZE_QUEUE); */
+	gtk_container_add (GTK_CONTAINER (frame_take), GTK_WIDGET (grid));
+
+	row = 0;
+
+	tmp_str = g_strconcat (_("Please choose which of the two entries should be retained"), ":", NULL);
+	label = gtk_label_new (tmp_str);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+	g_free (tmp_str);
+	gtk_grid_attach (grid, label, 1, row, 2, 1);
+
+	row++;
+
+	widget = gtk_button_new_with_label (_("Take Newer (last modified)"));
+	uidata->widgets->btn_strategy_newer = widget;
+	gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+	row++;
+
+	widget = gtk_button_new_with_label (_("Take Remote (server-side)"));
+	uidata->widgets->btn_strategy_server = widget;
+	gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+	row++;
+
+	widget = gtk_button_new_with_label (_("Take Local (client-side)"));
+	uidata->widgets->btn_strategy_client = widget;
+	gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+	row++;
+
+	widget = gtk_button_new_with_label (_("Take Both (resulting in two different, parallel entries)"));
+	uidata->widgets->btn_strategy_dupe = widget;
+	gtk_grid_attach (grid, widget, 1, row, 1, 1);
+
+	/* FIXME connect signals */
+	g_warning ("%s: FIXME connect signals", __func__);
+
+	gtk_widget_show_all (content);
+
+	return uidata;
+}
+
+static void
+kolab_backend_sync_conflict_ui_free (KolabBackendSyncConflictUIData *uidata)
+{
+	if (uidata == NULL)
+		return;
+
+	/* the actual widgets will have been deleted already,
+	 * so just deleting the struct shell here
+	 */
+	if (uidata->widgets != NULL)
+		g_free (uidata->widgets);
+
+	/* free payload data here */
+
+	g_free (uidata);
+}
+
+static void
+kolab_backend_sync_conflict_ui_destroy (gpointer ptr)
+{
+	KolabBackendSyncConflictUIData *uidata = ptr;
+	kolab_backend_sync_conflict_ui_free (uidata);
+}
+
+static void
+e_kolab_backend_sync_ui_conflict_response_cb (GObject *dialog,
+                                              gint response_id)
+{
+	g_return_if_fail (dialog != NULL);
+
+	if (response_id != GTK_RESPONSE_OK) {
+		gtk_widget_destroy (GTK_WIDGET (dialog));
+		return;
+	}
+
+	/* FIXME implement me */
+	g_warning ("%s: FIXME implement me", __func__);
+}
+
+void
+e_kolab_backend_sync_ui_conflict_cb (EShellView *shell_view)
+{
+	GObject *dialog = NULL;
+
+	KolabBackendSyncConflictUIData *uidata = NULL;
+
+	if (shell_view != NULL)
+		g_assert (E_IS_SHELL_VIEW (shell_view));
+
+	uidata = kolab_backend_sync_conflict_ui_new ();
+	dialog = G_OBJECT (uidata->widgets->container);
+	g_object_set_data_full (dialog, "e-kolab-backend-sync-prop", uidata, kolab_backend_sync_conflict_ui_destroy);
+
+	/* signals */
+
+	gtk_widget_show (GTK_WIDGET (dialog));
+}
+
+/*----------------------------------------------------------------------------*/
diff --git a/src/eplugin/e-kolab-backend-sync-conflict.h b/src/eplugin/e-kolab-backend-sync-conflict.h
new file mode 100644
index 0000000..993c924
--- /dev/null
+++ b/src/eplugin/e-kolab-backend-sync-conflict.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/***************************************************************************
+ *            e-kolab-backend-sync-conflict.h
+ *
+ *  Fri Feb 20 22:32:05 2012
+ *  Copyright  2012  Christian Hilberg
+ *  <hilberg kernelconcepts de>
+ *
+ ****************************************************************************/
+
+/*
+ * 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.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
+ */
+
+/*----------------------------------------------------------------------------*/
+
+#ifndef _E_KOLAB_BACKEND_SYNC_CONFLICT_H_
+#define _E_KOLAB_BACKEND_SYNC_CONFLICT_H_
+
+/*----------------------------------------------------------------------------*/
+
+#include <e-util/e-config.h>
+#include <e-util/e-plugin.h>
+#include <shell/e-shell-view.h>
+
+/*----------------------------------------------------------------------------*/
+
+void
+e_kolab_backend_sync_ui_conflict_cb (EShellView *shell_view);
+
+/*----------------------------------------------------------------------------*/
+
+#endif /* _E_KOLAB_BACKEND_SYNC_CONFLICT_H_ */
+
+/*----------------------------------------------------------------------------*/
diff --git a/src/eplugin/e-kolab-plugin.c b/src/eplugin/e-kolab-plugin.c
index a4b4a2d..d3ad1b4 100644
--- a/src/eplugin/e-kolab-plugin.c
+++ b/src/eplugin/e-kolab-plugin.c
@@ -26,6 +26,10 @@
 
 /*----------------------------------------------------------------------------*/
 
+#define d(x) x
+
+/*----------------------------------------------------------------------------*/
+
 #include <config.h>
 
 #include "e-kolab-account-setup.h"
@@ -33,6 +37,8 @@
 #include "e-kolab-plugin-ui.h"
 #include "e-kolab-plugin.h"
 
+#include "e-kolab-backend-sync-conflict.h"
+
 /*----------------------------------------------------------------------------*/
 /* plugin */
 
@@ -55,6 +61,10 @@ e_plugin_lib_enable (EPlugin *epl,
 	} else {
 		g_debug ("%s(): Kolab plugin disabled", __func__);
 	}
+
+	/* FIXME remove me! */
+	d (e_kolab_backend_sync_ui_conflict_cb (NULL);)
+
 	return 0;
 }
 



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