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