Hi guys! Here goes a complete patch for the actual state of the Evolution Data Server Resource importer. In this new patch you can find: - Select/Unselect all import resources - Search capabilities - Sort by name and email Once I finish all the sorting stuff the next steps are: - Convert to asynchronous all the eds queries - Add undo support In other email I will send a screenshot of a query using LDAP againts Verising LDAP search for sun.com emails and sorted by the name. To test the plugin: - Apply the patch to CVS HEAD - Copy the planner-eds-plugin.c to "src" - Copy evolution-data-server.glade to "data/glade" - Copy eds-plugin.glade to "data/ui" Then: ./autogen.sh --enable-eds Cheers -- Alvaro
Index: configure.in =================================================================== RCS file: /cvs/gnome/planner/configure.in,v retrieving revision 1.41 diff -u -b -B -p -r1.41 configure.in --- configure.in 1 Aug 2004 11:21:26 -0000 1.41 +++ configure.in 7 Aug 2004 12:42:26 -0000 @@ -247,6 +247,28 @@ fi AM_CONDITIONAL(HAVE_DOTNET, test x$have_dotnet = xyes) +dnl ----------------------------- +dnl | Evolution Data Server check |---------------------------------------------- +dnl ----------------------------- +AC_ARG_ENABLE(eds, + AC_HELP_STRING ([--enable-eds], + [Enable evolution-data-server support [default=no]]) + , enable_eds="$enableval", enable_eds=no) + +if test "x$enable_eds" = "xyes" ; then + EDS_REQUIRED=0.0.95 + PKG_CHECK_MODULES(EDS, libecal-1.0 >= $EDS_REQUIRED) + PKG_CHECK_MODULES(EDS, libebook-1.0 >= $EDS_REQUIRED) + use_eds=yes +else + use_eds=no +fi + +AC_SUBST(EDS_LIBS) +AC_SUBST(EDS_CFLAGS) +AM_CONDITIONAL(HAVE_EDS_PLUGIN, test x$use_eds = xyes) +dnl ----------------------------------------------------------- + dnl This will cause the automake generated makefiles to pass the dnl correct flags to aclocal. ACLOCAL_AMFLAGS="\${ACLOCAL_FLAGS}" @@ -292,7 +314,8 @@ echo "Build API docs : $enable_gtk_ echo "Python bindings : $have_python" echo "Python plugin : $enable_python_plugin" echo "Dotnet bindings : $have_dotnet" -echo "Database/GDA support: $use_gda" +echo "Database/GDA support : $use_gda" +echo "Evolution Data Server support : $use_eds" echo Index: data/glade/Makefile.am =================================================================== RCS file: /cvs/gnome/planner/data/glade/Makefile.am,v retrieving revision 1.1.1.1 diff -u -b -B -p -r1.1.1.1 Makefile.am --- data/glade/Makefile.am 1 Dec 2003 17:36:55 -0000 1.1.1.1 +++ data/glade/Makefile.am 7 Aug 2004 12:42:26 -0000 @@ -12,7 +12,8 @@ glade_DATA = \ resource-input-dialog.glade \ sql.glade \ task-dialog.glade \ - task-input-dialog.glade + task-input-dialog.glade \ + evolution-data-server.glade EXTRA_DIST = $(glade_DATA) Index: data/ui/Makefile.am =================================================================== RCS file: /cvs/gnome/planner/data/ui/Makefile.am,v retrieving revision 1.8 diff -u -b -B -p -r1.8 Makefile.am --- data/ui/Makefile.am 30 Jul 2004 17:49:17 -0000 1.8 +++ data/ui/Makefile.am 7 Aug 2004 12:42:27 -0000 @@ -10,7 +10,8 @@ ui_DATA = \ sql-plugin.ui \ task-view.ui \ xml-planner-plugin.ui \ - time-table-view.ui + time-table-view.ui \ + eds-plugin.ui EXTRA_DIST = $(ui_DATA) Index: libplanner/mrp-project.c =================================================================== RCS file: /cvs/gnome/planner/libplanner/mrp-project.c,v retrieving revision 1.11 diff -u -b -B -p -r1.11 mrp-project.c Index: libplanner/mrp-storage-sql.c =================================================================== RCS file: /cvs/gnome/planner/libplanner/mrp-storage-sql.c,v retrieving revision 1.2 diff -u -b -B -p -r1.2 mrp-storage-sql.c Index: src/Makefile.am =================================================================== RCS file: /cvs/gnome/planner/src/Makefile.am,v retrieving revision 1.22 diff -u -b -B -p -r1.22 Makefile.am --- src/Makefile.am 6 Aug 2004 09:58:08 -0000 1.22 +++ src/Makefile.am 7 Aug 2004 12:42:33 -0000 @@ -209,11 +209,20 @@ libpython_plugin_la_LIBADD = $(PYTHON_L libpython_plugin_la_CFLAGS = $(PYGTK_CFLAGS) endif +if HAVE_EDS_PLUGIN +eds_plugin = libeds-plugin.la +libeds_plugin_la_SOURCES = planner-eds-plugin.c +libeds_plugin_la_LDFLAGS = -avoid-version -module +libeds_plugin_la_LIBADD = $(EDS_LIBS) +libeds_plugin_la_CFLAGS = $(EDS_CFLAGS) +endif + plugin_LTLIBRARIES = \ libhtml-plugin.la \ libxmlplanner-plugin.la \ $(sql_plugin) \ - $(python_plugin) + $(python_plugin) \ + $(eds_plugin) libhtml_plugin_la_SOURCES = planner-html-plugin.c libhtml_plugin_la_LDFLAGS = -avoid-version -module
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2004 Alvaro del Castillo <acs barrapunto com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include <config.h> #include <glib.h> #include <string.h> #include <gdk/gdkevents.h> #include <gdk/gdkkeysyms.h> #include <glade/glade.h> #include <gtk/gtklist.h> #include <gtk/gtkcombobox.h> #include <gtk/gtkbutton.h> #include <gtk/gtkentry.h> #include <gtk/gtktreemodel.h> #include <gtk/gtkliststore.h> #include <gtk/gtkcellrenderertext.h> #include <gtk/gtkcellrenderertoggle.h> #include <gtk/gtkcellrendererpixbuf.h> #include <gtk/gtkcelllayout.h> #include <libgnome/gnome-i18n.h> #include <libgnomeui/gnome-file-entry.h> #include <gconf/gconf-client.h> #include "planner-window.h" #include "planner-plugin.h" /* Evolution Data Server sources */ #include <libedataserver/e-source-list.h> #include <libedataserver/e-source-group.h> /* Calendar */ #include <libecal/e-cal.h> /* Addressbook */ #include <libebook/e-book.h> struct _PlannerPluginPriv { PlannerWindow *main_window; MrpProject *project; /* Manage groups of source from e-d-s */ ESourceList *source_list; GtkComboBox *select_group; GSList *groups; GtkTreeModel *groups_model; /* Manage resource from a group */ GtkTreeView *resources_tree_view; GtkTreeModel *resources_model; /* Main widgets */ GladeXML *glade; GtkWidget *dialog_get_resources; }; enum { COL_RESOURCE_NAME, COL_RESOURCE_EMAIL, COL_RESOURCE_SELECTED, COL_RESOURCE_PHOTO, COL_RESOURCE_OBJECT, NUM_RESOURCE_COLS }; enum { COL_GROUP_NAME, COL_GROUP_OBJECT, NUM_GROUP_COLS }; static void eds_plugin_import (GtkAction *action, gpointer user_data, const gchar *cname); static void eds_create_groups_model (GSList *groups, PlannerPlugin *plugin); static void eds_ok_button_clicked (GtkButton *button, PlannerPlugin *plugin); static void eds_cancel_button_clicked (GtkButton *button, PlannerPlugin *plugin); static void eds_search_button_clicked (GtkButton *button, PlannerPlugin *plugin); static void eds_import_change_all (PlannerPlugin *plugin, gboolean state); static void eds_all_button_clicked (GtkButton *button, PlannerPlugin *plugin); static void eds_none_button_clicked (GtkButton *button, PlannerPlugin *plugin); static gboolean eds_search_key_pressed (GtkEntry *entry, GdkEventKey *event, PlannerPlugin *plugin); static void eds_column_clicked (GtkTreeViewColumn *treeviewcolumn, PlannerPlugin *plugin); static void eds_group_selected (GtkComboBox *select_group, PlannerPlugin *plugin); static void eds_resource_selected (GtkCellRendererToggle *toggle, const gchar *path_str, PlannerPlugin *plugin); static void eds_import_resource (gchar *name, gchar *email, PlannerPlugin *plugin); static void eds_load_resources (ESourceGroup *group, PlannerPlugin *plugin, const gchar *search); void plugin_init (PlannerPlugin *plugin, PlannerWindow *main_window); void plugin_exit (PlannerPlugin *plugin); static GtkActionEntry action_entries[] = { { "EDS Import", NULL, N_("EDS"), NULL, N_("Import resources from Evolution Data Server"), G_CALLBACK (eds_plugin_import) }, }; static guint n_action_entries = G_N_ELEMENTS (action_entries); static gint eds_compare_field (GtkTreeModel *model, GtkTreeIter *resource1, GtkTreeIter *resource2, gpointer user_data) { gchar *field1, *field2; gint res = 0; gtk_tree_model_get (model, resource1, GPOINTER_TO_INT (user_data), &field1, -1); gtk_tree_model_get (model, resource2, GPOINTER_TO_INT (user_data), &field2, -1); if (field1 && field2) { res = strcmp (field1, field2); } return res; } static void eds_plugin_import (GtkAction *action, gpointer user_data, const gchar *cname) { PlannerPlugin *plugin; PlannerPluginPriv *priv; GtkCellRenderer *renderer; GConfClient *gconf_client; ESourceList *source_list; GSList *groups; plugin = PLANNER_PLUGIN (user_data); priv = plugin->priv; priv->glade = glade_xml_new (GLADEDIR"/evolution-data-server.glade", NULL, NULL); priv->dialog_get_resources = glade_xml_get_widget (priv->glade, "resources_get"); gtk_window_set_transient_for (GTK_WINDOW (priv->dialog_get_resources), GTK_WINDOW (priv->main_window)); priv->select_group = (GtkComboBox *) glade_xml_get_widget (priv->glade, "select_group"); g_signal_connect (priv->select_group, "changed", G_CALLBACK (eds_group_selected), user_data); priv->resources_tree_view = (GtkTreeView *) glade_xml_get_widget (priv->glade, "resources"); g_signal_connect (glade_xml_get_widget (priv->glade, "ok_button"), "clicked", G_CALLBACK (eds_ok_button_clicked), plugin); g_signal_connect (glade_xml_get_widget (priv->glade, "cancel_button"), "clicked", G_CALLBACK (eds_cancel_button_clicked), plugin); g_signal_connect (glade_xml_get_widget (priv->glade, "search_button"), "clicked", G_CALLBACK (eds_search_button_clicked), plugin); g_signal_connect (glade_xml_get_widget (priv->glade, "all_button"), "clicked", G_CALLBACK (eds_all_button_clicked), plugin); g_signal_connect (glade_xml_get_widget (priv->glade, "none_button"), "clicked", G_CALLBACK (eds_none_button_clicked), plugin); g_signal_connect (glade_xml_get_widget (priv->glade, "search_entry"), "key-press-event", G_CALLBACK (eds_search_key_pressed), plugin); gtk_widget_show (priv->dialog_get_resources); gconf_client = gconf_client_get_default (); source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/addressbook/sources"); /* List with addressbook groups */ groups = e_source_list_peek_groups (source_list); eds_create_groups_model (groups, plugin); gtk_combo_box_set_model (priv->select_group, priv->groups_model); renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->select_group), renderer, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (priv->select_group), renderer, "text", 0, NULL); g_slist_free (groups); } static void eds_create_groups_model (GSList *groups, PlannerPlugin *plugin) { GtkListStore *model; GtkTreeIter iter; GSList *sl; const gchar *name; if (groups == NULL) { return; } model = gtk_list_store_new (NUM_GROUP_COLS, G_TYPE_STRING, G_TYPE_OBJECT); for (sl = groups; sl; sl = sl->next) { name = e_source_group_peek_name (sl->data); gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, COL_GROUP_NAME, name, COL_GROUP_OBJECT, sl->data, -1); } plugin->priv->groups_model = (GtkTreeModel *) model; } /* For now we show all the sources from a group in a List. Later we will us a Tree to show them usings groups. */ static void eds_load_resources (ESourceGroup *group, PlannerPlugin *plugin, const gchar *search) { GtkListStore *model; GtkTreeIter iter; GSList *sources, *sl; PlannerPluginPriv *priv; g_return_if_fail (E_IS_SOURCE_GROUP (group)); sources = e_source_group_peek_sources (group); if (sources == NULL) { return; } priv = plugin->priv; model = (GtkListStore *) priv->resources_model; if (model) { gtk_list_store_clear (model); } else { GtkCellRenderer *toggle; guint column_pos; GtkTreeViewColumn *column; model = gtk_list_store_new (NUM_RESOURCE_COLS, G_TYPE_STRING, /* name */ G_TYPE_STRING, /* email */ G_TYPE_BOOLEAN, /* import */ GDK_TYPE_PIXBUF, /* photo */ G_TYPE_OBJECT); /* full contact */ priv->resources_model = (GtkTreeModel *) model; gtk_tree_view_set_model (priv->resources_tree_view, priv->resources_model); /* Name Column with sorting features */ column_pos = gtk_tree_view_insert_column_with_attributes (priv->resources_tree_view, -1, _("Name"), gtk_cell_renderer_text_new (), "text", COL_RESOURCE_NAME, NULL); column = gtk_tree_view_get_column (priv->resources_tree_view, column_pos-1); gtk_tree_view_column_set_sort_indicator (column, TRUE); gtk_tree_sortable_set_sort_func ((GtkTreeSortable *) priv->resources_model, column_pos-1, eds_compare_field, GINT_TO_POINTER (column_pos-1), NULL); gtk_tree_view_column_set_sort_column_id (column, column_pos-1); g_signal_connect (gtk_tree_view_get_column (priv->resources_tree_view, column_pos-1), "clicked", G_CALLBACK (eds_column_clicked), plugin); /* Email column with sorting features */ column_pos = gtk_tree_view_insert_column_with_attributes (priv->resources_tree_view, -1, _("Email"), gtk_cell_renderer_text_new (), "text", COL_RESOURCE_EMAIL, NULL); column = gtk_tree_view_get_column (priv->resources_tree_view, column_pos-1); gtk_tree_view_column_set_sort_indicator (column, TRUE); gtk_tree_sortable_set_sort_func ((GtkTreeSortable *) priv->resources_model, column_pos-1, eds_compare_field, GINT_TO_POINTER (column_pos-1), NULL); gtk_tree_view_column_set_sort_column_id (column, column_pos-1); g_signal_connect (gtk_tree_view_get_column (priv->resources_tree_view, column_pos-1), "clicked", G_CALLBACK (eds_column_clicked), plugin); /* Import */ toggle = gtk_cell_renderer_toggle_new (); gtk_tree_view_insert_column_with_attributes (priv->resources_tree_view, -1, _("Import"), toggle, "active", COL_RESOURCE_SELECTED, NULL); g_signal_connect (toggle, "toggled", G_CALLBACK (eds_resource_selected), plugin); /* Photo */ gtk_tree_view_insert_column_with_attributes (priv->resources_tree_view, -1, _("Photo"), gtk_cell_renderer_pixbuf_new (), "pixbuf", COL_RESOURCE_PHOTO, NULL); gtk_tree_view_set_headers_clickable (priv->resources_tree_view, TRUE); } for (sl = sources; sl; sl = sl->next) { EBook *client; EBookQuery *query; GError *error = NULL; GList *l, *contacts; GdkPixbuf *pixbuf; pixbuf = gdk_pixbuf_new_from_file (IMAGEDIR"/resources.png", NULL); client = e_book_new (sl->data, NULL); if (!e_book_open (client, TRUE, NULL)) { continue; } /* query = e_book_query_field_exists (E_CONTACT_FULL_NAME); */ /* query = e_book_query_any_field_contains ("John"); */ /* query = e_book_query_from_string ("#t"); */ query = e_book_query_any_field_contains (search); e_book_get_contacts (client, query, &contacts, &error); e_book_query_unref (query); for (l = contacts; l; l = l->next) { gchar *name, *email; name = e_contact_get (l->data, E_CONTACT_GIVEN_NAME); email = e_contact_get (l->data, E_CONTACT_EMAIL_1); gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, COL_RESOURCE_NAME, name, COL_RESOURCE_EMAIL, email, COL_RESOURCE_SELECTED, FALSE, COL_RESOURCE_PHOTO, pixbuf, COL_RESOURCE_OBJECT, l->data, -1); } } } static void eds_all_button_clicked (GtkButton *button, PlannerPlugin *plugin) { eds_import_change_all (plugin, TRUE); } static void eds_none_button_clicked (GtkButton *button, PlannerPlugin *plugin) { eds_import_change_all (plugin, FALSE); } static void eds_import_change_all (PlannerPlugin *plugin, gboolean state) { GtkTreeIter iter; PlannerPluginPriv *priv = plugin->priv; gtk_tree_model_get_iter_first (priv->resources_model, &iter); do { gtk_list_store_set ((GtkListStore *) priv->resources_model, &iter, COL_RESOURCE_SELECTED, state, -1); } while (gtk_tree_model_iter_next (priv->resources_model, &iter)); } static void eds_import_resource (gchar *name, gchar *email, PlannerPlugin *plugin) { MrpResource *resource = mrp_resource_new (); mrp_project_add_resource (plugin->priv->project, resource); if (name) { mrp_object_set (resource, "name", name, NULL); } if (email) { mrp_object_set (resource, "email", email, NULL); } } static void eds_group_selected (GtkComboBox *select_group, PlannerPlugin *plugin) { GtkTreeIter iter; PlannerPluginPriv *priv = plugin->priv; ESourceGroup *group; gtk_widget_set_sensitive (glade_xml_get_widget (priv->glade, "search_box"), TRUE); if (gtk_combo_box_get_active_iter (select_group, &iter)) { gtk_tree_model_get (priv->groups_model, &iter, COL_GROUP_OBJECT, &group, -1); eds_load_resources (group, plugin, ""); } } static void eds_resource_selected (GtkCellRendererToggle *toggle, const gchar *path_str, PlannerPlugin *plugin) { GtkTreePath *path; GtkTreeModel *model; GtkTreeIter iter; gboolean selected; EContact *contact; path = gtk_tree_path_new_from_string (path_str); model = plugin->priv->resources_model; gtk_tree_model_get_iter (model, &iter, path); gtk_tree_model_get (model, &iter, COL_RESOURCE_SELECTED, &selected, COL_RESOURCE_OBJECT, &contact, -1); gtk_list_store_set ((GtkListStore *) model, &iter, COL_RESOURCE_SELECTED, !selected, -1); gtk_tree_path_free (path); } static void eds_ok_button_clicked (GtkButton *button, PlannerPlugin *plugin) { GtkTreeIter iter; PlannerPluginPriv *priv = plugin->priv; gtk_tree_model_get_iter_first (priv->resources_model, &iter); do { EContact *contact; gboolean selected; gtk_tree_model_get (priv->resources_model, &iter, COL_RESOURCE_SELECTED, &selected, COL_RESOURCE_OBJECT, &contact, -1); if (selected) { gchar *name = e_contact_get (contact, E_CONTACT_GIVEN_NAME); gchar *email = e_contact_get (contact, E_CONTACT_EMAIL_1); eds_import_resource (name, email, plugin); } } while (gtk_tree_model_iter_next (priv->resources_model, &iter)); /* FIXME: free memory */ gtk_widget_destroy (priv->dialog_get_resources); } static void eds_cancel_button_clicked (GtkButton *button, PlannerPlugin *plugin) { PlannerPluginPriv *priv = plugin->priv; /* FIXME: free memory */ gtk_widget_destroy (priv->dialog_get_resources); } static void eds_search_button_clicked (GtkButton *button, PlannerPlugin *plugin) { const gchar *search; PlannerPluginPriv *priv = plugin->priv; GtkTreeIter iter; ESourceGroup *group; search = gtk_entry_get_text ((GtkEntry *) glade_xml_get_widget (priv->glade,"search_entry")); if (gtk_combo_box_get_active_iter (priv->select_group, &iter)) { gtk_tree_model_get (priv->groups_model, &iter, COL_GROUP_OBJECT, &group, -1); eds_load_resources (group, plugin, search); } } static gboolean eds_search_key_pressed (GtkEntry *entry, GdkEventKey *event, PlannerPlugin *plugin) { PlannerPluginPriv *priv = plugin->priv; GtkTreeIter iter; ESourceGroup *group; if (event->keyval == GDK_Return) { if (gtk_combo_box_get_active_iter (priv->select_group, &iter)) { gtk_tree_model_get (priv->groups_model, &iter, COL_GROUP_OBJECT, &group, -1); eds_load_resources (group, plugin, gtk_entry_get_text (entry)); } } return FALSE; } static void eds_column_clicked (GtkTreeViewColumn *column, PlannerPlugin *plugin) { gtk_tree_sortable_set_sort_column_id ((GtkTreeSortable *) plugin->priv->resources_model, gtk_tree_view_column_get_sort_column_id (column), GTK_SORT_ASCENDING); } /* FIXME: Undo support */ G_MODULE_EXPORT void plugin_init (PlannerPlugin *plugin, PlannerWindow *main_window) { PlannerPluginPriv *priv; GtkUIManager *ui; GtkActionGroup *actions; GError *error = NULL; priv = g_new0 (PlannerPluginPriv, 1); plugin->priv = priv; priv->main_window = main_window; priv->project = planner_window_get_project (plugin->main_window); actions = gtk_action_group_new("HTML plugin actions"); gtk_action_group_set_translation_domain (actions, GETTEXT_PACKAGE); gtk_action_group_add_actions (actions, action_entries, n_action_entries, plugin); ui = planner_window_get_ui_manager (main_window); gtk_ui_manager_insert_action_group (ui, actions, 0); if (!gtk_ui_manager_add_ui_from_file(ui, DATADIR"/planner/ui/eds-plugin.ui", &error)) { g_message("Building menu failed: %s", error->message); g_message ("Couldn't load: %s",DATADIR"/planner/ui/eds-plugin.ui"); g_error_free(error); } gtk_ui_manager_ensure_update(ui); } G_MODULE_EXPORT void plugin_exit (PlannerPlugin *plugin) { /*g_message ("Test exit");*/ }
Attachment:
evolution-data-server.glade
Description: application/glade
<ui> <menubar name="MenuBar"> <menu action="File"> <menu action="Export"> <placeholder name="Export placeholder"> <menuitem action="EDS Import"/> </placeholder> </menu> </menu> </menubar> </ui>
Attachment:
signature.asc
Description: Esta parte del mensaje =?ISO-8859-1?Q?est=E1?= firmada digitalmente