diff options
Diffstat (limited to 'addressbook/gui')
69 files changed, 7281 insertions, 8183 deletions
diff --git a/addressbook/gui/Makefile.am b/addressbook/gui/Makefile.am index 64bcd98356..73c12f9bf2 100644 --- a/addressbook/gui/Makefile.am +++ b/addressbook/gui/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = merging contact-editor contact-list-editor widgets component +SUBDIRS = merging widgets contact-editor contact-list-editor component -include $(top_srcdir)/git.mk diff --git a/addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in b/addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in deleted file mode 100644 index 823d5bd89f..0000000000 --- a/addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in +++ /dev/null @@ -1,136 +0,0 @@ -<oaf_info> - -<oaf_server iid="OAFIID:GNOME_Evolution_Addressbook_Factory:@VERSION@" - type="shlib" - location="@COMPONENTDIR_IN_SERVER_FILE@/libevolution-addressbook@SOEXT@"> - - <oaf_attribute name="repo_ids" type="stringv"> - <item value="IDL:GNOME/ObjectFactory:1.0"/> - </oaf_attribute> - - <oaf_attribute name="name" type="string" - _value="Evolution Address Book"/> - -</oaf_server> - -<oaf_server iid="OAFIID:GNOME_Evolution_Addressbook_VCard_Control:@VERSION@" - type="factory" - location="OAFIID:GNOME_Evolution_Addressbook_Factory:@VERSION@"> - - <oaf_attribute name="repo_ids" type="stringv"> - <item value="IDL:Bonobo/Control:1.0"/> - <item value="IDL:Bonobo/PersistStream:1.0"/> - </oaf_attribute> - - <oaf_attribute name="bonobo:supported_mime_types" type="stringv"> - <item value="text/vcard"/> - <item value="text/x-vcard"/> - </oaf_attribute> - - <oaf_attribute name="name" type="string" - _value="Evolution Address Book card viewer"/> - -</oaf_server> - -<oaf_server iid="OAFIID:GNOME_Evolution_Addressbook_Component:@VERSION@" - type="factory" - location="OAFIID:GNOME_Evolution_Addressbook_Factory:@VERSION@"> - - <oaf_attribute name="repo_ids" type="stringv"> - <item value="IDL:GNOME/Evolution/Component:@VERSION@"/> - </oaf_attribute> - - <oaf_attribute name="name" type="string" - _value="Evolution Address Book component"/> - - <oaf_attribute name="evolution:component_alias" type="string" value="contacts"/> - - <oaf_attribute name="evolution:menu_label" type="string" _value="C_ontacts"/> - <oaf_attribute name="evolution:menu_accelerator" type="string" value="*Control*2"/> - <oaf_attribute name="evolution:button_label" type="string" _value="Contacts"/> - <oaf_attribute name="evolution:button_tooltips" type="string" _value="Contacts"/> - <oaf_attribute name="evolution:button_sort_order" type="string" value="-9"/> - <oaf_attribute name="evolution:button_icon" type="string" value="x-office-address-book"/> - -</oaf_server> - -<oaf_server iid="OAFIID:GNOME_Evolution_Addressbook_AddressWidget:@VERSION@" - type="factory" - location="OAFIID:GNOME_Evolution_Addressbook_Factory:@VERSION@"> - - <oaf_attribute name="repo_ids" type="stringv"> - <item value="IDL:BonoboControl/address-widget:@VERSION@"/> - <item value="IDL:GNOME/Control:1.0"/> - </oaf_attribute> - - <oaf_attribute name="name" type="string" - _value="Evolution Address Book address viewer"/> - -</oaf_server> - -<oaf_server iid="OAFIID:GNOME_Evolution_Addressbook_AddressPopup:@VERSION@" - type="factory" - location="OAFIID:GNOME_Evolution_Addressbook_Factory:@VERSION@"> - - <oaf_attribute name="repo_ids" type="stringv"> - <item value="IDL:BonoboControl/address-widget:@VERSION@"/> - <item value="IDL:GNOME/Control:1.0"/> - </oaf_attribute> - - <oaf_attribute name="name" type="string" - _value="Evolution Address Book address popup"/> - -</oaf_server> - -<oaf_server iid="OAFIID:GNOME_Evolution_SMime_CertificateManager_ConfigControl:@VERSION@" - type="factory" - location="OAFIID:GNOME_Evolution_Addressbook_Factory:@VERSION@"> - - <oaf_attribute name="repo_ids" type="stringv"> - <item value="IDL:GNOME/Evolution/ConfigControl:@VERSION@"/> - </oaf_attribute> - - <oaf_attribute name="evolution2:config_item:title" type="string" - _value="Certificates"/> - - <oaf_attribute name="evolution2:config_item:description" type="string" - _value="Manage your S/MIME certificates here"/> - - <oaf_attribute name="evolution2:config_item:icon_name" type="string" - value="preferences-certificates"/> - - <oaf_attribute name="evolution2:config_item:priority" type="string" value="-6"/> - - <oaf_attribute name="name" type="string" - _value="Evolution S/MIME Certificate Management Control"/> - -</oaf_server> - -<oaf_server iid="OAFIID:GNOME_Evolution_Addressbook_Autocompletion_ConfigControl:@VERSION@" - type="factory" - location="OAFIID:GNOME_Evolution_Addressbook_Factory:@VERSION@"> - - <oaf_attribute name="repo_ids" type="stringv"> - <item value="IDL:GNOME/Evolution/ConfigControl:@VERSION@"/> - </oaf_attribute> - - <oaf_attribute name="evolution2:config_item:title" type="string" - _value="Autocompletion"/> - - <oaf_attribute name="evolution2:config_item:description" type="string" - _value="Configure autocomplete here"/> - - <oaf_attribute name="evolution2:config_item:icon_name" type="string" - value="preferences-autocompletion"/> - - <oaf_attribute name="evolution2:config_item:type" type="stringv"> - <item value="contacts"/> - </oaf_attribute> - - <oaf_attribute name="evolution2:config_item:priority" type="string" value="-9"/> - - <oaf_attribute name="name" type="string" - _value="Evolution folder settings configuration control"/> -</oaf_server> - -</oaf_info> diff --git a/addressbook/gui/component/Makefile.am b/addressbook/gui/component/Makefile.am index b7870eddc7..7aea84963b 100644 --- a/addressbook/gui/component/Makefile.am +++ b/addressbook/gui/component/Makefile.am @@ -1,19 +1,18 @@ -if OS_WIN32 -WIN32_BOOTSTRAP_LIBS = $(top_builddir)/win32/libevolution-mail.la -endif - INCLUDES = \ -DG_LOG_DOMAIN=\"evolution-addressbook\" \ -I$(top_srcdir) \ -I$(top_srcdir)/widgets \ -I$(top_srcdir)/shell \ -I$(top_builddir)/shell \ + -I$(top_srcdir)/widgets/menus \ -I$(top_srcdir)/widgets/misc \ -I$(top_srcdir)/addressbook/util \ -I$(top_srcdir)/addressbook/gui/contact-editor \ -I$(top_srcdir)/addressbook/gui/contact-list-editor \ -I$(top_srcdir)/addressbook/gui/widgets \ -I$(top_srcdir)/a11y/addressbook \ + -DEVOLUTION_ETSPECDIR=\""$(etspecdir)"\" \ + -DEVOLUTION_GALVIEWSDIR=\""$(viewsdir)"\" \ -DEVOLUTION_GLADEDIR=\""$(gladedir)"\" \ -DEVOLUTION_LOCALEDIR=\""$(localedir)"\" \ -DEVOLUTION_UIDIR=\""$(evolutionuidir)"\" \ @@ -21,32 +20,37 @@ INCLUDES = \ $(LDAP_CFLAGS) \ $(EVOLUTION_ADDRESSBOOK_CFLAGS) -component_LTLIBRARIES = libevolution-addressbook.la +module_LTLIBRARIES = libevolution-module-contacts.la -libevolution_addressbook_la_SOURCES = \ - addressbook-component.c \ - addressbook-component.h \ +libevolution_module_contacts_la_SOURCES = \ addressbook-config.c \ addressbook-config.h \ - addressbook-migrate.c \ - addressbook-migrate.h \ autocompletion-config.c \ autocompletion-config.h \ - addressbook.c \ - addressbook.h \ - addressbook-view.c \ - addressbook-view.h \ - component-factory.c - -# $(top_builddir)/addressbook/printing/libecontactprint.la + eab-composer-util.c \ + eab-composer-util.h \ + e-book-shell-content.c \ + e-book-shell-content.h \ + e-book-shell-module.c \ + e-book-shell-module-migrate.c \ + e-book-shell-module-migrate.h \ + e-book-shell-sidebar.c \ + e-book-shell-sidebar.h \ + e-book-shell-view.c \ + e-book-shell-view.h \ + e-book-shell-view-actions.c \ + e-book-shell-view-actions.h \ + e-book-shell-view-private.c \ + e-book-shell-view-private.h if ENABLE_SMIME SMIME_LIB=$(top_builddir)/smime/gui/libevolution-smime.la endif -libevolution_addressbook_la_LIBADD = \ +libevolution_module_contacts_la_LIBADD = \ $(SMIME_LIB) \ $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/composer/libcomposer.la \ $(top_builddir)/addressbook/printing/libecontactprint.la \ $(top_builddir)/shell/libeshell.la \ $(top_builddir)/addressbook/gui/merging/libeabbookmerging.la \ @@ -58,7 +62,6 @@ libevolution_addressbook_la_LIBADD = \ $(top_builddir)/widgets/table/libetable.la \ $(top_builddir)/widgets/text/libetext.la \ $(top_builddir)/widgets/misc/libemiscwidgets.la \ - $(top_builddir)/widgets/misc/libefilterbar.la \ $(top_builddir)/widgets/menus/libmenus.la \ $(top_builddir)/a11y/addressbook/libevolution-addressbook-a11y.la \ $(top_builddir)/addressbook/importers/libevolution-addressbook-importers.la \ @@ -66,7 +69,8 @@ libevolution_addressbook_la_LIBADD = \ $(EVOLUTION_ADDRESSBOOK_LIBS) $(LDAP_LIBS) -libevolution_addressbook_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED) +libevolution_module_contacts_la_LDFLAGS = \ + -module -avoid-version $(NO_UNDEFINED) # GConf schemas @@ -94,23 +98,14 @@ install-data-local: fi endif -server_in_files = GNOME_Evolution_Addressbook.server.in.in -server_DATA = $(server_in_files:.server.in.in=.server) -@EVO_SERVER_RULE@ -@INTLTOOL_SERVER_RULE@ - glade_DATA = \ ldap-config.glade -BUILT_SOURCES = $(server_DATA) -CLEANFILES = $(BUILT_SOURCES) - DISTCLEANFILES = $(schema_DATA) EXTRA_DIST = \ $(glade_DATA) \ $(schema_in_files) \ - $(server_in_files) \ openldap-extract.h dist-hook: diff --git a/addressbook/gui/component/addressbook-component.c b/addressbook/gui/component/addressbook-component.c deleted file mode 100644 index 3ec3f5ca08..0000000000 --- a/addressbook/gui/component/addressbook-component.c +++ /dev/null @@ -1,529 +0,0 @@ -/* - * 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: - * Ettore Perazzoli <ettore@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -/* EPFIXME: Add autocompletion setting. */ - -#include <config.h> - -#include "addressbook-component.h" -#include "addressbook-config.h" -#include "addressbook-migrate.h" -#include "addressbook-view.h" -#include "addressbook/gui/contact-editor/eab-editor.h" -#include "addressbook/gui/widgets/eab-gui-util.h" -#include "e-util/e-plugin.h" -#include "e-util/e-import.h" -#include "addressbook/gui/widgets/eab-popup.h" -#include "addressbook/gui/widgets/eab-menu.h" -#include "addressbook/gui/widgets/eab-config.h" -#include "addressbook/importers/evolution-addressbook-importers.h" - -#include "misc/e-task-bar.h" -#include "misc/e-info-label.h" - -#include "shell/e-component-view.h" - -#include <string.h> -#include <gtk/gtk.h> -#include <glib/gi18n-lib.h> -#include <gconf/gconf-client.h> -#include <e-util/e-util.h> -#include <libedataserver/e-url.h> - -#ifdef ENABLE_SMIME -#include "smime/gui/component.h" -#endif - -#define LDAP_BASE_URI "ldap://" -#define PERSONAL_RELATIVE_URI "system" - -#define PARENT_TYPE bonobo_object_get_type () -static BonoboObjectClass *parent_class = NULL; - -struct _AddressbookComponentPrivate { - GConfClient *gconf_client; - char *base_directory; - GList *views; -}; - -static void -ensure_sources (AddressbookComponent *component) -{ - ESourceList *source_list; - ESourceGroup *on_this_computer; - ESource *personal_source; - char *base_uri, *base_uri_proto, base_uri_proto_seventh; - const gchar *base_dir; - - personal_source = NULL; - - if (!e_book_get_addressbooks (&source_list, NULL)) { - g_warning ("Could not get addressbook source list from GConf!"); - return; - } - - base_dir = addressbook_component_peek_base_directory (component); - base_uri = g_build_filename (base_dir, "local", NULL); - - base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL); - if (strlen (base_uri_proto) >= 7) { - /* compare only file:// part. If user home dir name changes we do not want to create - one more group */ - base_uri_proto_seventh = base_uri_proto[7]; - base_uri_proto[7] = 0; - } else { - base_uri_proto_seventh = -1; - } - - on_this_computer = e_source_list_ensure_group (source_list, _("On This Computer"), base_uri_proto, TRUE); - e_source_list_ensure_group (source_list, _("On LDAP Servers"), LDAP_BASE_URI, FALSE); - - if (base_uri_proto_seventh != -1) { - base_uri_proto[7] = base_uri_proto_seventh; - } - - if (on_this_computer) { - /* make sure "Personal" shows up as a source under - this group */ - GSList *sources = e_source_group_peek_sources (on_this_computer); - GSList *s; - for (s = sources; s; s = s->next) { - ESource *source = E_SOURCE (s->data); - const gchar *relative_uri; - - relative_uri = e_source_peek_relative_uri (source); - if (relative_uri == NULL) - continue; - if (!strcmp (PERSONAL_RELATIVE_URI, relative_uri)) { - personal_source = source; - break; - } - } - /* Make sure we have the correct base uri. This can change when user's - homedir name changes */ - if (strcmp (base_uri_proto, e_source_group_peek_base_uri (on_this_computer))) { - e_source_group_set_base_uri (on_this_computer, base_uri_proto); - - /* *sigh* . We shouldn't need this sync call here as set_base_uri - call results in synching to gconf, but that happens in idle loop - and too late to prevent user seeing "Can not Open ... because of invalid uri" error.*/ - e_source_list_sync (source_list,NULL); - } - } - - if (personal_source) { - /* ensure the source name is in current locale, not read from configuration */ - e_source_set_name (personal_source, _("Personal")); - } else { - /* Create the default Person addressbook */ - ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI); - e_source_group_add_source (on_this_computer, source, -1); - g_object_unref (source); - - e_source_set_property (source, "completion", "true"); - - personal_source = source; - } - - g_object_unref (on_this_computer); - g_free (base_uri_proto); - g_free (base_uri); -} - -static void -view_destroyed_cb (gpointer data, GObject *where_the_object_was) -{ - AddressbookComponent *addressbook_component = data; - AddressbookComponentPrivate *priv; - GList *l; - - priv = addressbook_component->priv; - - for (l = priv->views; l; l = l->next) { - AddressbookView *view = l->data; - if (G_OBJECT (view) == where_the_object_was) { - priv->views = g_list_remove (priv->views, view); - break; - } - } -} - -/* Evolution::Component CORBA methods. */ - -static GNOME_Evolution_ComponentView -impl_createView (PortableServer_Servant servant, - GNOME_Evolution_ShellView parent, - CORBA_boolean select_item, - CORBA_Environment *ev) -{ - AddressbookComponent *addressbook_component = ADDRESSBOOK_COMPONENT (bonobo_object_from_servant (servant)); - AddressbookComponentPrivate *priv = addressbook_component->priv; - AddressbookView *view = addressbook_view_new (); - EComponentView *component_view; - - g_object_weak_ref (G_OBJECT (view), view_destroyed_cb, addressbook_component); - priv->views = g_list_append (priv->views, view); - - component_view = e_component_view_new_controls (parent, "contacts", - bonobo_control_new (addressbook_view_peek_sidebar (view)), - addressbook_view_peek_folder_view (view), - bonobo_control_new (addressbook_view_peek_statusbar (view))); - - return BONOBO_OBJREF(component_view); - -} - -static GNOME_Evolution_CreatableItemTypeList * -impl__get_userCreatableItems (PortableServer_Servant servant, - CORBA_Environment *ev) -{ - GNOME_Evolution_CreatableItemTypeList *list = GNOME_Evolution_CreatableItemTypeList__alloc (); - - list->_length = 3; - list->_maximum = list->_length; - list->_buffer = GNOME_Evolution_CreatableItemTypeList_allocbuf (list->_length); - - CORBA_sequence_set_release (list, FALSE); - - list->_buffer[0].id = "contact"; - list->_buffer[0].description = _("New Contact"); - list->_buffer[0].menuDescription = (char *) C_("New", "_Contact"); - list->_buffer[0].tooltip = _("Create a new contact"); - list->_buffer[0].menuShortcut = 'c'; - list->_buffer[0].iconName = "contact-new"; - list->_buffer[0].type = GNOME_Evolution_CREATABLE_OBJECT; - - list->_buffer[1].id = "contact_list"; - list->_buffer[1].description = _("New Contact List"); - list->_buffer[1].menuDescription = (char *) C_("New", "Contact _List"); - list->_buffer[1].tooltip = _("Create a new contact list"); - list->_buffer[1].menuShortcut = 'l'; - list->_buffer[1].iconName = "stock_contact-list"; - list->_buffer[1].type = GNOME_Evolution_CREATABLE_OBJECT; - - list->_buffer[2].id = "address_book"; - list->_buffer[2].description = _("New Address Book"); - list->_buffer[2].menuDescription = (char *) C_("New", "Address _Book"); - list->_buffer[2].tooltip = _("Create a new address book"); - list->_buffer[2].menuShortcut = '\0'; - list->_buffer[2].iconName = "address-book-new"; - list->_buffer[2].type = GNOME_Evolution_CREATABLE_FOLDER; - - return list; -} - -static void -book_loaded_cb (EBook *book, EBookStatus status, gpointer data) -{ - EContact *contact; - char *item_type_name = data; - - if (status != E_BOOK_ERROR_OK) { - /* XXX we really need a dialog here, but we don't have - access to the ESource so we can't use - eab_load_error_dialog. fun! */ - return; - } - - contact = e_contact_new (); - - if (!strcmp (item_type_name, "contact")) { - eab_show_contact_editor (book, contact, TRUE, TRUE); - } - else if (!strcmp (item_type_name, "contact_list")) { - eab_show_contact_list_editor (book, contact, TRUE, TRUE); - } - - g_object_unref (book); - g_object_unref (contact); - - g_free (item_type_name); -} - -static void -impl_requestCreateItem (PortableServer_Servant servant, - const CORBA_char *item_type_name, - CORBA_Environment *ev) -{ - EBook *book; - GConfClient *gconf_client; - ESourceList *source_list; - char *uid; - - if (!item_type_name || - (strcmp (item_type_name, "address_book") && - strcmp (item_type_name, "contact") && - strcmp (item_type_name, "contact_list"))) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, ex_GNOME_Evolution_Component_UnknownType, NULL); - return; - } - - if (!strcmp (item_type_name, "address_book")) { - addressbook_config_create_new_source (NULL); - return; - } - - gconf_client = gconf_client_get_default(); - uid = gconf_client_get_string (gconf_client, "/apps/evolution/addressbook/display/primary_addressbook", - NULL); - g_object_unref (gconf_client); - if (!e_book_get_addressbooks (&source_list, NULL)) { - g_warning ("Could not get addressbook source list from GConf!"); - g_free (uid); - return; - } - if (uid) { - ESource *source = e_source_list_peek_source_by_uid(source_list, uid); - if (source) { - book = e_book_new (source, NULL); - } - else { - book = e_book_new_default_addressbook (NULL); - } - g_free (uid); - } - else { - book = e_book_new_default_addressbook (NULL); - } - - e_book_async_open (book, FALSE, book_loaded_cb, g_strdup (item_type_name)); -} - -static void -impl_handleURI (PortableServer_Servant servant, - const char* uri, - CORBA_Environment *ev) -{ - AddressbookComponent *addressbook_component = ADDRESSBOOK_COMPONENT (bonobo_object_from_servant (servant)); - AddressbookComponentPrivate *priv; - AddressbookView *view = NULL; - - GList *l; - char *src_uid = NULL; - char *contact_uid = NULL; - - priv = addressbook_component->priv; - l = g_list_last (priv->views); - if (!l) - return; - - view = l->data; - - if (!strncmp (uri, "contacts:", 9)) { - EUri *euri = e_uri_new (uri); - const char *p; - char *header, *content; - size_t len, clen; - - p = euri->query; - if (p) { - while (*p) { - len = strcspn (p, "=&"); - - /* If it's malformed, give up. */ - if (p[len] != '=') - break; - - header = (char *) p; - header[len] = '\0'; - p += len + 1; - - clen = strcspn (p, "&"); - - content = g_strndup (p, clen); - - if (!g_ascii_strcasecmp (header, "source-uid")) { - src_uid = g_strdup (content); - } else if (!g_ascii_strcasecmp (header, "contact-uid")) { - contact_uid = g_strdup (content); - } - - g_free (content); - - p += clen; - if (*p == '&') { - p++; - if (!strcmp (p, "amp;")) - p += 4; - } - } - - addressbook_view_edit_contact (view, src_uid, contact_uid); - - g_free (src_uid); - g_free (contact_uid); - } - e_uri_free (euri); - } - -} - -static void -impl_upgradeFromVersion (PortableServer_Servant servant, short major, short minor, short revision, CORBA_Environment *ev) -{ - GError *err = NULL; - - if (!addressbook_migrate (addressbook_component_peek (), major, minor, revision, &err)) { - GNOME_Evolution_Component_UpgradeFailed *failedex; - - failedex = GNOME_Evolution_Component_UpgradeFailed__alloc(); - failedex->what = CORBA_string_dup(_("Failed upgrading Address Book settings or folders.")); - failedex->why = CORBA_string_dup(err->message); - CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ex_GNOME_Evolution_Component_UpgradeFailed, failedex); - } - - if (err) - g_error_free(err); -} - -static CORBA_boolean -impl_requestQuit (PortableServer_Servant servant, CORBA_Environment *ev) -{ - return eab_editor_request_close_all (); -} - -/* GObject methods. */ - -static void -impl_dispose (GObject *object) -{ - AddressbookComponentPrivate *priv = ADDRESSBOOK_COMPONENT (object)->priv; - GList *l; - - if (priv->gconf_client != NULL) { - g_object_unref (priv->gconf_client); - priv->gconf_client = NULL; - } - - for (l = priv->views; l; l = l->next) { - AddressbookView *view = l->data; - g_object_weak_unref (G_OBJECT (view), view_destroyed_cb, ADDRESSBOOK_COMPONENT (object)); - } - g_list_free (priv->views); - priv->views = NULL; - (* G_OBJECT_CLASS (parent_class)->dispose) (object); -} - -static void -impl_finalize (GObject *object) -{ - AddressbookComponentPrivate *priv = ADDRESSBOOK_COMPONENT (object)->priv; - - g_free (priv); - - (* G_OBJECT_CLASS (parent_class)->finalize) (object); -} - - -/* Initialization. */ - -static void -addressbook_component_class_init (AddressbookComponentClass *class) -{ - POA_GNOME_Evolution_Component__epv *epv = &class->epv; - GObjectClass *object_class = G_OBJECT_CLASS (class); - - bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - - epv->createView = impl_createView; - epv->_get_userCreatableItems = impl__get_userCreatableItems; - epv->requestCreateItem = impl_requestCreateItem; - epv->upgradeFromVersion = impl_upgradeFromVersion; - epv->requestQuit = impl_requestQuit; - epv->handleURI = impl_handleURI; - - object_class->dispose = impl_dispose; - object_class->finalize = impl_finalize; - - parent_class = g_type_class_peek_parent (class); -} - -static void -addressbook_component_init (AddressbookComponent *component) -{ - AddressbookComponentPrivate *priv; - static int first = TRUE; - - priv = g_new0 (AddressbookComponentPrivate, 1); - - /* EPFIXME: Should use a custom one instead? */ - priv->gconf_client = gconf_client_get_default (); - - priv->base_directory = g_build_filename (e_get_user_data_dir (), "addressbook", NULL); - - component->priv = priv; - - ensure_sources (component); - -#ifdef ENABLE_SMIME - smime_component_init (); -#endif - - if (first) { - EImportClass *klass; - - first = FALSE; - e_plugin_hook_register_type(eab_popup_hook_get_type()); - e_plugin_hook_register_type(eab_menu_hook_get_type()); - e_plugin_hook_register_type(eab_config_hook_get_type()); - - klass = g_type_class_ref(e_import_get_type()); - e_import_class_add_importer(klass, evolution_ldif_importer_peek(), NULL, NULL); - e_import_class_add_importer(klass, evolution_vcard_importer_peek(), NULL, NULL); - e_import_class_add_importer(klass, evolution_csv_outlook_importer_peek(), NULL, NULL); - e_import_class_add_importer(klass, evolution_csv_mozilla_importer_peek(), NULL, NULL); - e_import_class_add_importer(klass, evolution_csv_evolution_importer_peek(), NULL, NULL); - } -} - - -/* Public API. */ - -AddressbookComponent * -addressbook_component_peek (void) -{ - static AddressbookComponent *component = NULL; - - if (component == NULL) - component = g_object_new (addressbook_component_get_type (), NULL); - - return component; -} - -GConfClient* -addressbook_component_peek_gconf_client (AddressbookComponent *component) -{ - g_return_val_if_fail (ADDRESSBOOK_IS_COMPONENT (component), NULL); - - return component->priv->gconf_client; -} - -const char * -addressbook_component_peek_base_directory (AddressbookComponent *component) -{ - g_return_val_if_fail (ADDRESSBOOK_IS_COMPONENT (component), NULL); - - return component->priv->base_directory; -} - -BONOBO_TYPE_FUNC_FULL (AddressbookComponent, GNOME_Evolution_Component, PARENT_TYPE, addressbook_component) diff --git a/addressbook/gui/component/addressbook-component.h b/addressbook/gui/component/addressbook-component.h deleted file mode 100644 index 83fbdf87ee..0000000000 --- a/addressbook/gui/component/addressbook-component.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * 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: - * Ettore Perazzoli <ettore@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef _ADDRESSBOOK_COMPONENT_H_ -#define _ADDRESSBOOK_COMPONENT_H_ - -#include <bonobo/bonobo-object.h> - -#include "Evolution.h" -#include "e-activity-handler.h" -#include <libedataserver/e-source-list.h> - -#define ADDRESSBOOK_TYPE_COMPONENT (addressbook_component_get_type ()) -#define ADDRESSBOOK_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ADDRESSBOOK_TYPE_COMPONENT, AddressbookComponent)) -#define ADDRESSBOOK_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ADDRESSBOOK_TYPE_COMPONENT, AddressbookComponentClass)) -#define ADDRESSBOOK_IS_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ADDRESSBOOK_TYPE_COMPONENT)) -#define ADDRESSBOOK_IS_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), ADDRESSBOOK_TYPE_COMPONENT)) - - -typedef struct _AddressbookComponent AddressbookComponent; -typedef struct _AddressbookComponentPrivate AddressbookComponentPrivate; -typedef struct _AddressbookComponentClass AddressbookComponentClass; - -struct _AddressbookComponent { - BonoboObject parent; - - AddressbookComponentPrivate *priv; -}; - -struct _AddressbookComponentClass { - BonoboObjectClass parent_class; - - POA_GNOME_Evolution_Component__epv epv; -}; - - -GType addressbook_component_get_type (void); - -AddressbookComponent *addressbook_component_peek (void); - -GConfClient *addressbook_component_peek_gconf_client (AddressbookComponent *component); -const char *addressbook_component_peek_base_directory (AddressbookComponent *component); - -#endif /* _ADDRESSBOOK_COMPONENT_H_ */ diff --git a/addressbook/gui/component/addressbook-config.c b/addressbook/gui/component/addressbook-config.c index 1f0fa57847..07bc2f98d5 100644 --- a/addressbook/gui/component/addressbook-config.c +++ b/addressbook/gui/component/addressbook-config.c @@ -34,8 +34,6 @@ #include <gtk/gtk.h> #include <glib/gi18n.h> -#include <bonobo/bonobo-generic-factory.h> - #ifdef G_OS_WIN32 /* Include <windows.h> early and work around DATADIR lossage */ #define DATADIR crap_DATADIR @@ -46,7 +44,6 @@ #include <glade/glade.h> #include "addressbook.h" -#include "addressbook-component.h" #include "addressbook-config.h" #include "e-util/e-error.h" @@ -72,8 +69,6 @@ #define LDAPS_PORT_STRING "636" #define GLADE_FILE_NAME "ldap-config.glade" -#define CONFIG_CONTROL_FACTORY_ID "OAFIID:GNOME_Evolution_Addressbook_ConfigControlFactory:" BASE_VERSION -#define LDAP_CONFIG_CONTROL_ID "OAFIID:GNOME_Evolution_LDAPStorage_ConfigControl:" BASE_VERSION GtkWidget* supported_bases_create_table (char *name, char *string1, char *string2, int num1, int num2); diff --git a/addressbook/gui/component/addressbook-config.h b/addressbook/gui/component/addressbook-config.h index 04b44cd872..dc0452e6b1 100644 --- a/addressbook/gui/component/addressbook-config.h +++ b/addressbook/gui/component/addressbook-config.h @@ -24,7 +24,8 @@ #ifndef __ADDRESSBOOK_CONFIG_H__ #define __ADDRESSBOOK_CONFIG_H__ -#include "evolution-config-control.h" +#include <gtk/gtk.h> +#include <libedataserver/e-source.h> typedef enum { ADDRESSBOOK_LDAP_AUTH_NONE, diff --git a/addressbook/gui/component/addressbook-view.c b/addressbook/gui/component/addressbook-view.c deleted file mode 100644 index 53560e87d9..0000000000 --- a/addressbook/gui/component/addressbook-view.c +++ /dev/null @@ -1,1534 +0,0 @@ -/* - * 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 Toshok <toshok@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <gtk/gtk.h> -#include <glib/gi18n.h> -#include <gdk/gdkkeysyms.h> -#include <bonobo/bonobo-generic-factory.h> -#include <bonobo/bonobo-ui-util.h> -#include <bonobo/bonobo-exception.h> -#include <e-util/e-util.h> -#include <libedataserverui/e-source-selector.h> -#include <libedataserverui/e-passwords.h> - -#include "e-util/e-error.h" -#include "e-util/e-request.h" -#include "misc/e-task-bar.h" -#include "misc/e-info-label.h" - -#include "e-util/e-icon-factory.h" -#include "e-util/e-util-private.h" -#include "shell/e-user-creatable-items-handler.h" - -#include "evolution-shell-component-utils.h" -#include "e-activity-handler.h" -#include "e-contact-editor.h" -#include "addressbook-config.h" -#include "addressbook.h" -#include "addressbook-view.h" -#include "addressbook-component.h" -#include "addressbook/gui/widgets/e-addressbook-view.h" -#include "addressbook/gui/widgets/eab-gui-util.h" -#include "addressbook/gui/merging/eab-contact-merging.h" -#include "addressbook/printing/e-contact-print.h" -#include "addressbook/util/eab-book-util.h" -#include "addressbook/gui/widgets/eab-popup.h" -#include "addressbook/gui/widgets/eab-menu.h" - -#define PARENT_TYPE G_TYPE_OBJECT -static GObjectClass *parent_class = NULL; - -#define d(x) - -struct _AddressbookViewPrivate { - GtkWidget *notebook; - BonoboControl *folder_view_control; - - GtkWidget *statusbar_widget; - EActivityHandler *activity_handler; - - GtkWidget *info_widget; - GtkWidget *sidebar_widget; - GtkWidget *selector; - - GConfClient *gconf_client; - - GHashTable *uid_to_view; - GHashTable *uid_to_editor; - - EBook *book; - guint activity_id; - ESourceList *source_list; - char *passwd; - EUserCreatableItemsHandler *creatable_items_handler; - - EABMenu *menu; -}; - -enum DndTargetType { - DND_TARGET_TYPE_VCARD_LIST, - DND_TARGET_TYPE_SOURCE_VCARD_LIST -}; -#define VCARD_TYPE "text/x-vcard" -#define SOURCE_VCARD_TYPE "text/x-source-vcard" -static GtkTargetEntry drag_types[] = { - { SOURCE_VCARD_TYPE, 0, DND_TARGET_TYPE_SOURCE_VCARD_LIST }, - { VCARD_TYPE, 0, DND_TARGET_TYPE_VCARD_LIST } -}; -static gint num_drag_types = sizeof(drag_types) / sizeof(drag_types[0]); - -static void set_status_message (EABView *eav, const char *message, AddressbookView *view); -static void search_result (EABView *eav, EBookViewStatus status, AddressbookView *view); - -static void activate_source (AddressbookView *view, ESource *source); - -static void addressbook_view_init (AddressbookView *view); -static void addressbook_view_class_init (AddressbookViewClass *klass); -static void addressbook_view_dispose (GObject *object); - -static ESource *find_first_source (ESourceList *source_list); -static ESource *get_primary_source (AddressbookView *view); - -typedef struct { - GtkWidget *editor; - char *uid; - AddressbookView *view; -} EditorUidClosure; - -static void -editor_weak_notify (gpointer data, GObject *o) -{ - EditorUidClosure *closure = data; - AddressbookViewPrivate *priv = closure->view->priv; - - g_hash_table_remove (priv->uid_to_editor, - closure->uid); -} - -static EABView * -get_current_view (AddressbookView *view) -{ - AddressbookViewPrivate *priv = view->priv; - - return EAB_VIEW (gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), - gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)))); -} - -static void -save_all_contacts_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - - if (v) - eab_view_save_as (v, TRUE); -} - -static void -save_contact_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_save_as(v, FALSE); -} - -static void -view_contact_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_view(v); -} - -static void -delete_contact_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_delete_selection(v, TRUE); -} - -static void -print_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_print (v, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG); -} - -static void -print_preview_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_print (v, GTK_PRINT_OPERATION_ACTION_PREVIEW); -} - -static void -stop_loading_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_stop(v); -} - -static void -cut_contacts_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_cut(v); -} - -static void -copy_contacts_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_copy(v); -} - -static void -paste_contacts_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_paste(v); -} - -static void -select_all_contacts_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_select_all (v); -} - -static void -send_contact_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_send (v); -} - -static void -send_contact_to_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_send_to (v); -} - -static void -copy_all_contacts_to_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - - if (v) - eab_view_copy_to_folder (v, TRUE); -} - -static void -copy_contact_to_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_copy_to_folder (v, FALSE); -} - -static void -move_all_contacts_to_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_move_to_folder (v, TRUE); -} - -static void -move_contact_to_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - EABView *v = get_current_view (view); - if (v) - eab_view_move_to_folder (v, FALSE); -} - -static void -forget_passwords_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - e_passwords_forget_passwords(); -} - -static void -new_addressbook_folder (AddressbookView *view) -{ - AddressbookViewPrivate *priv = view->priv; - addressbook_config_create_new_source (gtk_widget_get_toplevel(priv->notebook)); -} - -static void -new_folder_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - new_addressbook_folder (view); -} - -static void -delete_addressbook_folder (AddressbookView *view) -{ - AddressbookViewPrivate *priv = view->priv; - ESource *selected_source; - EBook *book; - GError *error = NULL; - GtkWindow *toplevel; - - selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (priv->selector)); - if (!selected_source) - return; - toplevel = (GtkWindow *) gtk_widget_get_toplevel (priv->notebook); - - if (e_error_run (toplevel, "addressbook:ask-delete-addressbook", - e_source_peek_name(selected_source), NULL) != GTK_RESPONSE_YES) - return; - - /* Remove local data */ - book = e_book_new (selected_source, &error); - if (book) { - if (e_book_remove (book, NULL)) { - if (e_source_selector_source_is_selected (E_SOURCE_SELECTOR (priv->selector), - selected_source)) - e_source_selector_unselect_source (E_SOURCE_SELECTOR (priv->selector), - selected_source); - - e_source_group_remove_source (e_source_peek_group (selected_source), selected_source); - - e_source_list_sync (priv->source_list, NULL); - } - else { - e_error_run (toplevel, "addressbook:remove-addressbook", NULL); - } - g_object_unref (book); - } - else { - g_warning ("error removing addressbook : %s", error->message); - g_error_free (error); - } -} - -static void -delete_folder_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - if (view) - delete_addressbook_folder (view); - -} - -static void -edit_addressbook_folder (AddressbookView *view) -{ - AddressbookViewPrivate *priv = view->priv; - ESource *selected_source; - const char *uid; - EditorUidClosure *closure; - - selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (priv->selector)); - if (!selected_source) - return; - - uid = e_source_peek_uid (selected_source); - - closure = g_hash_table_lookup (priv->uid_to_editor, uid); - if (!closure) { - char *uid_copy = g_strdup (uid); - - closure = g_new (EditorUidClosure, 1); - closure->editor = addressbook_config_edit_source (gtk_widget_get_toplevel(priv->notebook), selected_source); - closure->uid = uid_copy; - closure->view = view; - - g_hash_table_insert (priv->uid_to_editor, - uid_copy, - closure); - - g_object_weak_ref (G_OBJECT (closure->editor), - editor_weak_notify, closure); - } - - gtk_window_present (GTK_WINDOW (closure->editor)); - -} - -static void -edit_folder_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - if (view) - edit_addressbook_folder (view); - -} - -static void -rename_addressbook_folder (AddressbookView *view) -{ - AddressbookViewPrivate *priv = view->priv; - ESource *source; - const char *old_name; - char *prompt, *new_name; - gboolean done = FALSE; - - source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (priv->selector)); - old_name = e_source_peek_name(source); - prompt = g_strdup_printf (_("Rename the \"%s\" folder to:"), old_name); - - while (!done) { - new_name = e_request_string (NULL, _("Rename Folder"), prompt, old_name); - if (new_name == NULL || !strcmp (old_name, new_name)) { - done = TRUE; - } else if (strchr(new_name, '/') != NULL) { - e_error_run (NULL, - "addressbook:no-rename-folder", old_name, new_name, _("Folder names cannot contain '/'"), NULL); - done = TRUE; - } else if (e_source_group_peek_source_by_name(e_source_peek_group(source), new_name)) { - e_error_run (NULL, "addressbook:no-rename-folder-exists", old_name, new_name, NULL); - } else { - e_source_set_name (source, new_name); - done = TRUE; - } - } - g_free (new_name); - -} - -static void -rename_folder_cb (BonoboUIComponent *uih, void *user_data, const char *path) -{ - AddressbookView *view = (AddressbookView *) user_data; - if (view) - rename_addressbook_folder (view); -} - -static gboolean -folder_can_delete (AddressbookView *view) -{ - AddressbookViewPrivate *priv = view->priv; - ESource *source ; - const char *source_uri; - - source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (priv->selector)); - if(source) { - source_uri = e_source_peek_relative_uri (source); - if (source_uri && !strcmp("system", source_uri)) - return 0; - else - return 1; - } - else - return 0; -} - -static void -set_status_message (EABView *eav, const char *message, AddressbookView *view) -{ - AddressbookViewPrivate *priv = view->priv; - EActivityHandler *activity_handler = priv->activity_handler; - - if (!message || !*message) { - if (priv->activity_id != 0) { - e_activity_handler_operation_finished (activity_handler, priv->activity_id); - priv->activity_id = 0; - } - } else if (priv->activity_id == 0) { - char *clientid = g_strdup_printf ("%p", view); - - priv->activity_id = e_activity_handler_operation_started ( - activity_handler, clientid, message, TRUE); - - g_free (clientid); - } else { - e_activity_handler_operation_progressing (activity_handler, priv->activity_id, message, -1.0); - } - -} - -static void -set_folder_bar_message (EABView *eav, const char *message, AddressbookView *view) -{ - AddressbookViewPrivate *priv = view->priv; - EABView *current_view = get_current_view (view); - - if (eav == current_view) { - ESource *source = eav->source; - - if (source) { - const char *name = e_source_peek_name (source); - - e_info_label_set_info((EInfoLabel*)priv->info_widget, name, message); - } - } -} - -static void -search_result (EABView *eav, EBookViewStatus status, AddressbookView *view) -{ - eab_search_result_dialog (NULL /* XXX */, status); -} - -static void -update_command_state (EABView *eav, AddressbookView *view) -{ - AddressbookViewPrivate *priv = view->priv; - BonoboUIComponent *uic; - EABMenuTargetSelect *target; - - if (eav != get_current_view (view)) - return; - - g_object_ref (view); - - target = eab_view_get_menu_target(eav, priv->menu); - e_menu_update_target((EMenu *)priv->menu, target); - - uic = bonobo_control_get_ui_component (priv->folder_view_control); - - /* TODO: this stuff can mostly be made to use the target bits instead */ - - if (bonobo_ui_component_get_container (uic) != CORBA_OBJECT_NIL) { -#define SET_SENSITIVE(verb,f) \ - bonobo_ui_component_set_prop (uic, (verb), "sensitive", (f)(eav) ? "1" : "0", NULL) - - SET_SENSITIVE ("/commands/ContactsSaveAsVCard", eab_view_can_save_as); - SET_SENSITIVE ("/commands/ContactsView", eab_view_can_view); - - /* Print Contact */ - SET_SENSITIVE ("/commands/ContactsPrint", eab_view_can_print); - SET_SENSITIVE ("/commands/ContactsPrintPreview", eab_view_can_print); - - /* Delete Contact */ - SET_SENSITIVE ("/commands/ContactDelete", eab_view_can_delete); - SET_SENSITIVE ("/commands/ContactsCut", eab_view_can_cut); - - SET_SENSITIVE ("/commands/ContactsCopy", eab_view_can_copy); - SET_SENSITIVE ("/commands/ContactsPaste", eab_view_can_paste); - SET_SENSITIVE ("/commands/ContactsSelectAll", eab_view_can_select_all); - SET_SENSITIVE ("/commands/ContactsSendContactToOther", eab_view_can_send); - SET_SENSITIVE ("/commands/ContactsSendMessageToContact", eab_view_can_send_to); - SET_SENSITIVE ("/commands/ContactsMoveToFolder", eab_view_can_move_to_folder); - SET_SENSITIVE ("/commands/ContactsCopyToFolder", eab_view_can_copy_to_folder); - - bonobo_ui_component_set_prop (uic, ("/commands/FolderDelete"), "sensitive", folder_can_delete(view) ? "1" : "0", NULL); - - /* Stop */ - SET_SENSITIVE ("/commands/ContactStop", eab_view_can_stop); -#undef SET_SENSITIVE - } - - g_object_unref (view); -} - -static BonoboUIVerb verbs [] = { - BONOBO_UI_UNSAFE_VERB ("ContactsPrint", print_cb), - BONOBO_UI_UNSAFE_VERB ("ContactsPrintPreview", print_preview_cb), - BONOBO_UI_UNSAFE_VERB ("ContactsSaveAsVCard", save_contact_cb), - BONOBO_UI_UNSAFE_VERB ("ContactsView", view_contact_cb), - - BONOBO_UI_UNSAFE_VERB ("ContactDelete", delete_contact_cb), - BONOBO_UI_UNSAFE_VERB ("ContactStop", stop_loading_cb), - - BONOBO_UI_UNSAFE_VERB ("ContactsCut", cut_contacts_cb), - BONOBO_UI_UNSAFE_VERB ("ContactsCopy", copy_contacts_cb), - BONOBO_UI_UNSAFE_VERB ("ContactsPaste", paste_contacts_cb), - BONOBO_UI_UNSAFE_VERB ("ContactsSelectAll", select_all_contacts_cb), - - BONOBO_UI_UNSAFE_VERB ("ContactsSendContactToOther", send_contact_cb), - BONOBO_UI_UNSAFE_VERB ("ContactsSendMessageToContact", send_contact_to_cb), - BONOBO_UI_UNSAFE_VERB ("ContactsMoveToFolder", move_contact_to_cb), - BONOBO_UI_UNSAFE_VERB ("ContactsCopyToFolder", copy_contact_to_cb), - BONOBO_UI_UNSAFE_VERB ("ContactsForgetPasswords", forget_passwords_cb), - /* ContactsViewPreview is a toggle */ - - BONOBO_UI_UNSAFE_VERB ("FolderCreate", new_folder_cb), - BONOBO_UI_UNSAFE_VERB ("FolderCopy", copy_all_contacts_to_cb), - BONOBO_UI_UNSAFE_VERB ("FolderMove", move_all_contacts_to_cb), - BONOBO_UI_UNSAFE_VERB ("FolderSave", save_all_contacts_cb), - BONOBO_UI_UNSAFE_VERB ("FolderDelete", delete_folder_cb), - BONOBO_UI_UNSAFE_VERB ("FolderRename", rename_folder_cb), - BONOBO_UI_UNSAFE_VERB ("ChangeFolderProperties", edit_folder_cb), - - BONOBO_UI_VERB_END -}; - -static EPixmap pixmaps [] = { - E_PIXMAP ("/commands/ChangeFolderProperties", "document-properties", E_ICON_SIZE_MENU), - E_PIXMAP ("/commands/ContactDelete", "edit-delete", E_ICON_SIZE_MENU), - E_PIXMAP ("/commands/ContactsCopy", "edit-copy", E_ICON_SIZE_MENU), - E_PIXMAP ("/commands/ContactsCut", "edit-cut", E_ICON_SIZE_MENU), - E_PIXMAP ("/commands/ContactsPaste", "edit-paste", E_ICON_SIZE_MENU), - E_PIXMAP ("/commands/ContactsPrint", "document-print", E_ICON_SIZE_MENU), - E_PIXMAP ("/commands/ContactsPrintPreview", "document-print-preview", E_ICON_SIZE_MENU), - E_PIXMAP ("/commands/ContactsSaveAsVCard", "document-save-as", E_ICON_SIZE_MENU), - E_PIXMAP ("/commands/ContactsSendContactToOther", "mail-forward", E_ICON_SIZE_MENU), - E_PIXMAP ("/commands/ContactsSendMessageToContact", "mail-message-new", E_ICON_SIZE_MENU), - E_PIXMAP ("/commands/FolderCopy", "edit-copy", E_ICON_SIZE_MENU), - E_PIXMAP ("/commands/FolderDelete", "edit-delete", E_ICON_SIZE_MENU), - E_PIXMAP ("/commands/FolderMove", "folder-move", E_ICON_SIZE_MENU), - E_PIXMAP ("/commands/FolderSave", "document-save-as", E_ICON_SIZE_MENU), - - E_PIXMAP ("/Toolbar/ContactsPrint", "document-print", E_ICON_SIZE_LARGE_TOOLBAR), - E_PIXMAP ("/Toolbar/ContactDelete", "edit-delete", E_ICON_SIZE_LARGE_TOOLBAR), - - E_PIXMAP_END -}; - -static void -control_activate (BonoboControl *control, - BonoboUIComponent *uic, - AddressbookView *view) -{ - AddressbookViewPrivate *priv = view->priv; - Bonobo_UIContainer remote_ui_container; - EABView *v = get_current_view (view); - char *xmlfile; - - remote_ui_container = bonobo_control_get_remote_ui_container (control, NULL); - bonobo_ui_component_set_container (uic, remote_ui_container, NULL); - bonobo_object_release_unref (remote_ui_container, NULL); - - bonobo_ui_component_add_verb_list_with_data ( - uic, verbs, view); - - bonobo_ui_component_freeze (uic, NULL); - - xmlfile = g_build_filename (EVOLUTION_UIDIR, - "evolution-addressbook.xml", - NULL); - bonobo_ui_util_set_ui (uic, PREFIX, - xmlfile, - "evolution-addressbook", NULL); - g_free (xmlfile); - - if (v) - eab_view_setup_menus (v, uic); - - e_pixmaps_update (uic, pixmaps); - - e_user_creatable_items_handler_activate (priv->creatable_items_handler, uic); - - bonobo_ui_component_thaw (uic, NULL); - - if (v) - update_command_state (v, view); -} - -static void -control_activate_cb (BonoboControl *control, - gboolean activate, - AddressbookView *view) -{ - BonoboUIComponent *uic; - EABView *v = get_current_view (view); - - uic = bonobo_control_get_ui_component (control); - g_return_if_fail (uic != NULL); - - if (activate) { - control_activate (control, uic, view); - e_menu_activate((EMenu *)view->priv->menu, uic, activate); - if (activate && v && v->model) - eab_model_force_folder_bar_message (v->model); - } else { - e_menu_activate((EMenu *)view->priv->menu, uic, activate); - bonobo_ui_component_unset_container (uic, NULL); - eab_view_discard_menus (v); - } -} - -static void -gather_uids_foreach (char *key, - gpointer value, - GList **list) -{ - (*list) = g_list_prepend (*list, key); -} - -static void -source_list_changed_cb (ESourceList *source_list, AddressbookView *view) -{ - AddressbookViewPrivate *priv = view->priv; - GList *uids, *l; - EABView *v; - - uids = NULL; - g_hash_table_foreach (priv->uid_to_view, (GHFunc)gather_uids_foreach, &uids); - for (l = uids; l; l = l->next) { - char *uid = l->data; - if (e_source_list_peek_source_by_uid (source_list, uid)) { - /* the source still exists, do nothing */ - } - else { - /* the source no longer exists, remove its - view remove it from our hash table. */ - v = g_hash_table_lookup (priv->uid_to_view, - uid); - gtk_notebook_remove_page (GTK_NOTEBOOK (priv->notebook), - gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), - GTK_WIDGET (v))); - g_hash_table_remove (priv->uid_to_view, uid); - } - } - g_list_free (uids); - - uids = NULL; - g_hash_table_foreach (priv->uid_to_editor, (GHFunc)gather_uids_foreach, &uids); - for (l = uids; l; l = l->next) { - char *uid = l->data; - if (e_source_list_peek_source_by_uid (source_list, uid)) { - /* the source still exists, do nothing */ - } - else { - /* the source no longer exists, remove its - editor remove it from our hash table. */ - EditorUidClosure *closure = g_hash_table_lookup (priv->uid_to_editor, - uid); - g_object_weak_unref (G_OBJECT (closure->editor), - editor_weak_notify, closure); - gtk_widget_destroy (closure->editor); - g_hash_table_remove (priv->uid_to_editor, uid); - } - } - g_list_free (uids); - - /* make sure we've got the current view selected and updated - properly */ - v = get_current_view (view); - if (v) { - eab_view_setup_menus (v, bonobo_control_get_ui_component (priv->folder_view_control)); - update_command_state (v, view); - } -} - -static void -load_uri_for_selection (ESourceSelector *selector, - AddressbookView *view, - gboolean force) -{ - ESource *selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (selector)); - ESource *primary = get_primary_source (view); - - if (selected_source != NULL && - ((primary && (!g_str_equal (e_source_peek_uid (primary),e_source_peek_uid (selected_source) )))||force)) - activate_source (view, selected_source); -} - -static ESource * -find_first_source (ESourceList *source_list) -{ - GSList *groups, *sources, *l, *m; - - groups = e_source_list_peek_groups (source_list); - for (l = groups; l; l = l->next) { - ESourceGroup *group = l->data; - - sources = e_source_group_peek_sources (group); - for (m = sources; m; m = m->next) { - ESource *source = m->data; - - return source; - } - } - - return NULL; -} - -static void -save_primary_selection (AddressbookView *view) -{ - AddressbookViewPrivate *priv = view->priv; - ESource *source; - - source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (priv->selector)); - if (!source) - return; - - /* Save the selection for next time we start up */ - gconf_client_set_string (priv->gconf_client, - "/apps/evolution/addressbook/display/primary_addressbook", - e_source_peek_uid (source), NULL); -} - -static ESource * -get_primary_source (AddressbookView *view) -{ - AddressbookViewPrivate *priv = view->priv; - ESource *source; - char *uid; - - uid = gconf_client_get_string (priv->gconf_client, - "/apps/evolution/addressbook/display/primary_addressbook", - NULL); - if (uid) { - source = e_source_list_peek_source_by_uid (priv->source_list, uid); - g_free (uid); - } else { - /* Try to create a default if there isn't one */ - source = find_first_source (priv->source_list); - } - - return source; -} - -static void -load_primary_selection (AddressbookView *view) -{ - AddressbookViewPrivate *priv = view->priv; - ESource *source; - - source = get_primary_source (view); - if (source) - e_source_selector_set_primary_selection (E_SOURCE_SELECTOR (priv->selector), source); -} - -/* Folder popup menu callbacks */ -typedef struct { - AddressbookView *view; - ESource *selected_source; - GtkWidget *toplevel; -} BookRemovedClosure; - -static void -book_removed (EBook *book, EBookStatus status, gpointer data) -{ - BookRemovedClosure *closure = data; - AddressbookView *view = closure->view; - AddressbookViewPrivate *priv = view->priv; - ESource *source = closure->selected_source; - GtkWidget *toplevel = closure->toplevel; - - g_free (closure); - - g_object_unref (book); - - if (E_BOOK_ERROR_OK == status) { - /* Remove source */ - if (e_source_selector_source_is_selected (E_SOURCE_SELECTOR (priv->selector), - source)) - e_source_selector_unselect_source (E_SOURCE_SELECTOR (priv->selector), - source); - - e_source_group_remove_source (e_source_peek_group (source), source); - - e_source_list_sync (priv->source_list, NULL); - } - else { - e_error_run (GTK_WINDOW (toplevel), - "addressbook:remove-addressbook", - NULL); - } -} - -static void -delete_addressbook_cb(EPopup *ep, EPopupItem *pitem, void *data) -{ - AddressbookView *view = data; - AddressbookViewPrivate *priv = view->priv; - ESource *selected_source; - EBook *book; - GError *error = NULL; - GtkWindow *toplevel; - - selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (priv->selector)); - if (!selected_source) - return; - - toplevel = (GtkWindow *)gtk_widget_get_toplevel(ep->target->widget); - - if (e_error_run (toplevel, "addressbook:ask-delete-addressbook", e_source_peek_name(selected_source), NULL) != GTK_RESPONSE_YES) - return; - - /* Remove local data */ - book = e_book_new (selected_source, &error); - if (book) { - BookRemovedClosure *closure = g_new (BookRemovedClosure, 1); - - closure->toplevel = (GtkWidget *)toplevel; - closure->view = view; - closure->selected_source = selected_source; - - if (e_book_async_remove (book, book_removed, closure)) { - e_error_run (toplevel, "addressbook:remove-addressbook", NULL); - g_free (closure); - g_object_unref (book); - } - } -} - -static void -new_addressbook_cb(EPopup *ep, EPopupItem *pitem, void *data) -{ - addressbook_config_create_new_source (gtk_widget_get_toplevel(ep->target->widget)); -} - -static void -rename_addressbook_cb (EPopup *ep, EPopupItem *pitem, void *data) -{ - AddressbookView *view = data; - ESourceSelector *selector; - - selector = E_SOURCE_SELECTOR (view->priv->selector); - e_source_selector_edit_primary_selection (selector); -} - -static void -save_addressbook_cb(EPopup *ep, EPopupItem *pitem, void *data) -{ - AddressbookView *view = data; - EABView *v = get_current_view (view); - if (v) - eab_view_save_as (v, TRUE); -} - -static void -edit_addressbook_cb(EPopup *ep, EPopupItem *pitem, void *data) -{ - AddressbookView *view = data; - if (view) - edit_addressbook_folder (view); -} - -/* Callbacks. */ - -static void -primary_source_selection_changed_callback (ESourceSelector *selector, - AddressbookView *view) -{ - load_uri_for_selection (selector, view, FALSE); - save_primary_selection (view); -} - -static EPopupItem abv_source_popups[] = { - { E_POPUP_ITEM, "10.new", N_("_New Address Book"), new_addressbook_cb, NULL, "address-book-new", 0, 0 }, - { E_POPUP_ITEM, "20.saveasvcard", N_("Save As vCard..."), save_addressbook_cb, NULL,"document-save-as", 0, EAB_POPUP_SOURCE_PRIMARY }, - { E_POPUP_ITEM, "25.rename", N_("_Rename..."), rename_addressbook_cb, NULL, NULL, 0, EAB_POPUP_SOURCE_PRIMARY }, - - { E_POPUP_BAR, "30.bar" }, - { E_POPUP_ITEM, "30.delete", N_("_Delete"), delete_addressbook_cb, NULL, "edit-delete", 0, EAB_POPUP_SOURCE_USER|EAB_POPUP_SOURCE_PRIMARY }, - - { E_POPUP_BAR, "99.bar" }, - { E_POPUP_ITEM, "99.properties", N_("_Properties"), edit_addressbook_cb, NULL,"document-properties", 0, EAB_POPUP_SOURCE_PRIMARY }, -}; - -static void -abv_source_popup_free(EPopup *ep, GSList *list, void *data) -{ - g_slist_free(list); -} - -static gboolean -popup_event_callback(ESourceSelector *selector, ESource *source, GdkEventButton *event, AddressbookView *view) -{ - EABPopup *ep; - EABPopupTargetSource *t; - GSList *menus = NULL; - int i; - GtkMenu *menu; - - /** @HookPoint-EABPopup:Addressbook Source Selector Context Menu - * @Id: org.gnome.evolution.addressbook.source.popup - * @Class: org.gnome.evolution.addresbook.popup:1.0 - * @Target: EABPopupTargetSource - * - * The context menu on the source selector in the contacts window. - */ - - ep = eab_popup_new("org.gnome.evolution.addressbook.source.popup"); - t = eab_popup_target_new_source(ep, selector); - t->target.widget = (GtkWidget *)view->priv->notebook; - - for (i=0;i<sizeof(abv_source_popups)/sizeof(abv_source_popups[0]);i++) - menus = g_slist_prepend(menus, &abv_source_popups[i]); - - e_popup_add_items((EPopup *)ep, menus, NULL, abv_source_popup_free, view); - - menu = e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0); - gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event?event->button:0, event?event->time:gtk_get_current_event_time()); - - return TRUE; -} - -typedef struct -{ - guint remove_from_source : 1; - guint copy_done : 1; - gint pending_removals; - - EContact *current_contact; - GList *remaining_contacts; - - EBook *source_book; - EBook *target_book; -} -MergeContext; - -static void -destroy_merge_context (MergeContext *merge_context) -{ - if (merge_context->source_book) - g_object_unref (merge_context->source_book); - if (merge_context->target_book) - g_object_unref (merge_context->target_book); - - g_free (merge_context); -} - -static void -removed_contact_cb (EBook *book, EBookStatus status, gpointer closure) -{ - MergeContext *merge_context = closure; - - merge_context->pending_removals--; - - if (merge_context->copy_done && merge_context->pending_removals == 0) { - /* Finished */ - - destroy_merge_context (merge_context); - } -} - -static void -merged_contact_cb (EBook *book, EBookStatus status, const char *id, gpointer closure) -{ - MergeContext *merge_context = closure; - - if (merge_context->remove_from_source && status == E_BOOK_ERROR_OK) { - /* Remove previous contact from source */ - - e_book_async_remove_contact (merge_context->source_book, merge_context->current_contact, - removed_contact_cb, merge_context); - merge_context->pending_removals++; - } - - g_object_unref (merge_context->current_contact); - - if (merge_context->remaining_contacts) { - /* Copy next contact */ - - merge_context->current_contact = merge_context->remaining_contacts->data; - merge_context->remaining_contacts = g_list_delete_link (merge_context->remaining_contacts, - merge_context->remaining_contacts); - eab_merging_book_add_contact (merge_context->target_book, merge_context->current_contact, - merged_contact_cb, merge_context); - } else if (merge_context->pending_removals == 0) { - /* Finished */ - - destroy_merge_context (merge_context); - } else { - /* Finished, but have pending removals */ - - merge_context->copy_done = TRUE; - } -} - -static gboolean -selector_tree_data_dropped (ESourceSelector *selector, - GtkSelectionData *data, - ESource *destination, - GdkDragAction action, - guint info, - AddressbookView *view) -{ - EBook *source_book, *target_book; - MergeContext *merge_context = NULL; - GList *contactlist; - EABView *v; - - target_book = e_book_new (destination, NULL); - if (!target_book) { - g_message (G_STRLOC ":Couldn't create EBook."); - return FALSE; - } - e_book_open (target_book, FALSE, NULL); - - eab_book_and_contact_list_from_string ((char *)data->data, &source_book, &contactlist); - - v = get_current_view (view); - g_object_get (v->model, "book",&source_book, NULL); - - /* Set up merge context */ - - merge_context = g_new0 (MergeContext, 1); - - merge_context->source_book = source_book; - merge_context->target_book = target_book; - - merge_context->current_contact = contactlist->data; - merge_context->remaining_contacts = g_list_delete_link (contactlist, contactlist); - - merge_context->remove_from_source = action == GDK_ACTION_MOVE ? TRUE : FALSE; - - /* Start merge */ - - eab_merging_book_add_contact (target_book, merge_context->current_contact, - merged_contact_cb, merge_context); - - return TRUE; -} - -static void -destroy_callback(gpointer data, GObject *where_object_was) -{ - AddressbookView *view = data; - g_object_unref (view); -} - -GType -addressbook_view_get_type (void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof (AddressbookViewClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) addressbook_view_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (EABView), - 0, /* n_preallocs */ - (GInstanceInitFunc) addressbook_view_init, - }; - - type = g_type_register_static (PARENT_TYPE, "AddressbookView", &info, 0); - } - - return type; -} - -static void -addressbook_view_class_init (AddressbookViewClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = addressbook_view_dispose; - - parent_class = g_type_class_peek_parent (klass); -} - -static gboolean -source_selector_key_press_event_callback (GtkWidget *widget, GdkEventKey *event, AddressbookView *view) -{ - if (event->keyval == GDK_Delete) { - delete_addressbook_folder (view); - return TRUE; - } - return FALSE; -} - -static void -addressbook_view_init (AddressbookView *view) -{ - AddressbookViewPrivate *priv; - GtkWidget *selector_scrolled_window; - AtkObject *a11y; - - view->priv = - priv = g_new0 (AddressbookViewPrivate, 1); - - priv->gconf_client = addressbook_component_peek_gconf_client (addressbook_component_peek ()); - - priv->uid_to_view = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, (GDestroyNotify)g_object_unref); - priv->uid_to_editor = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, (GDestroyNotify)g_free); - - priv->notebook = gtk_notebook_new (); - gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE); - gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->notebook), FALSE); - - g_object_weak_ref (G_OBJECT (priv->notebook), destroy_callback, view); - - /* Create the control. */ - priv->folder_view_control = bonobo_control_new (priv->notebook); - - gtk_widget_show (priv->notebook); - - e_book_get_addressbooks (&priv->source_list, NULL); - g_signal_connect (priv->source_list, - "changed", - G_CALLBACK (source_list_changed_cb), view); - - priv->creatable_items_handler = e_user_creatable_items_handler_new ("contacts", NULL, NULL); - priv->menu = eab_menu_new("org.gnome.evolution.addressbook.view"); - - g_signal_connect (priv->folder_view_control, "activate", - G_CALLBACK (control_activate_cb), view); - - priv->activity_handler = e_activity_handler_new (); - - priv->statusbar_widget = e_task_bar_new (); - gtk_widget_show (priv->statusbar_widget); - - e_activity_handler_attach_task_bar (priv->activity_handler, - E_TASK_BAR (priv->statusbar_widget)); - - priv->info_widget = e_info_label_new("x-office-address-book"); - e_info_label_set_info((EInfoLabel*)priv->info_widget, _("Contacts"), ""); - gtk_widget_show (priv->info_widget); - - priv->selector = e_source_selector_new (priv->source_list); - - g_signal_connect ( - priv->selector, "data-dropped", - G_CALLBACK (selector_tree_data_dropped), view); - gtk_drag_dest_set (priv->selector, GTK_DEST_DEFAULT_ALL, drag_types, num_drag_types, GDK_ACTION_COPY | GDK_ACTION_MOVE); - a11y = gtk_widget_get_accessible (GTK_WIDGET (priv->selector)); - atk_object_set_name (a11y, _("Contact Source Selector")); - - e_source_selector_show_selection (E_SOURCE_SELECTOR (priv->selector), FALSE); - gtk_widget_show (priv->selector); - - selector_scrolled_window = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (selector_scrolled_window), GTK_SHADOW_IN); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (selector_scrolled_window), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_container_add (GTK_CONTAINER (selector_scrolled_window), priv->selector); - gtk_widget_show (selector_scrolled_window); - - priv->sidebar_widget = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX (priv->sidebar_widget), priv->info_widget, FALSE, TRUE, 0); - gtk_box_pack_start(GTK_BOX (priv->sidebar_widget), selector_scrolled_window, TRUE, TRUE, 0); - gtk_widget_show (priv->sidebar_widget); - - g_signal_connect_object (priv->selector, "primary_selection_changed", - G_CALLBACK (primary_source_selection_changed_callback), - G_OBJECT (view), 0); - g_signal_connect_after (priv->selector, "key_press_event", - G_CALLBACK (source_selector_key_press_event_callback), - G_OBJECT (view)); - g_signal_connect_object (priv->selector, "popup_event", - G_CALLBACK (popup_event_callback), - G_OBJECT (view), 0); - - load_primary_selection (view); - load_uri_for_selection (E_SOURCE_SELECTOR (priv->selector), view, TRUE); -} - -static void -destroy_editor (char *key, - gpointer value, - gpointer nada) -{ - EditorUidClosure *closure = value; - - g_object_weak_unref (G_OBJECT (closure->editor), - editor_weak_notify, closure); - - gtk_widget_destroy (GTK_WIDGET (closure->editor)); -} - -static void -addressbook_view_dispose (GObject *object) -{ - AddressbookView *view = ADDRESSBOOK_VIEW (object); - AddressbookViewPrivate *priv = view->priv; - - if (view->priv) { - if (priv->book) - g_object_unref (priv->book); - - g_free(priv->passwd); - - if (priv->source_list) - g_object_unref (priv->source_list); - - if (priv->uid_to_view) - g_hash_table_destroy (priv->uid_to_view); - - if (priv->uid_to_editor) { - g_hash_table_foreach (priv->uid_to_editor, (GHFunc)destroy_editor, NULL); - g_hash_table_destroy (priv->uid_to_editor); - } - - if (priv->creatable_items_handler) - g_object_unref (priv->creatable_items_handler); - - if (priv->menu) - g_object_unref (priv->menu); - - g_free (view->priv); - view->priv = NULL; - } - - if (G_OBJECT_CLASS (parent_class)->dispose) - (* G_OBJECT_CLASS (parent_class)->dispose) (object); -} - -typedef struct { - EABView *view; - ESource *source; -} BookOpenData; - -static void -book_open_cb (EBook *book, EBookStatus status, gpointer closure) -{ - BookOpenData *data = closure; - EABView *view = data->view; - ESource *source = data->source; - - g_free (data); - - /* we always set the "source" property on the EABView, since - we use it to reload a previously failed book. */ - g_object_set(view, - "source", source, - NULL); - - if (status == E_BOOK_ERROR_OK) { - g_object_set(view, - "book", book, - NULL); - - if (view->model) - eab_model_force_folder_bar_message (view->model); - } - else if (status != E_BOOK_ERROR_CANCELLED) { - eab_load_error_dialog (NULL /* XXX */, source, status); - } - - - g_object_unref (source); -} - -static void -activate_source (AddressbookView *view, - ESource *source) -{ - AddressbookViewPrivate *priv = view->priv; - const char *uid; - GtkWidget *uid_view; - EBook *book; - BookOpenData *data; - - uid = e_source_peek_uid (source); - uid_view = g_hash_table_lookup (priv->uid_to_view, uid); - - if (uid_view) { - /* there is a view for this uid. make - sure that the view actually - contains an EBook (if it doesn't - contain an EBook a previous load - failed. try to load it again */ - g_object_get (uid_view, - "book", &book, - NULL); - - if (book) { - g_object_unref (book); - } - else { - g_object_get (uid_view, - "source", &source, - NULL); - - /* source can be NULL here, if - a previous load hasn't - actually made it to - book_open_cb yet. */ - if (source) { - book = e_book_new (source, NULL); - - if (!book) { - g_object_unref (source); - } - else { - data = g_new (BookOpenData, 1); - data->view = g_object_ref (uid_view); - data->source = source; /* transfer the ref we get back from g_object_get */ - - addressbook_load (book, book_open_cb, data); - } - } - } - } - else { - /* we don't have a view for this uid already - set up. */ - GtkWidget *label = gtk_label_new (uid); - GError *error = NULL; - - uid_view = eab_view_new (); - - gtk_widget_show (uid_view); - gtk_widget_show (label); - - g_object_set (uid_view, "type", EAB_VIEW_TABLE, NULL); - - gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), - uid_view, - label); - - g_hash_table_insert (priv->uid_to_view, g_strdup (uid), uid_view); - - g_signal_connect (uid_view, "status_message", - G_CALLBACK(set_status_message), view); - - g_signal_connect (uid_view, "search_result", - G_CALLBACK(search_result), view); - - g_signal_connect (uid_view, "folder_bar_message", - G_CALLBACK(set_folder_bar_message), view); - - g_signal_connect (uid_view, "command_state_change", - G_CALLBACK(update_command_state), view); - - book = e_book_new (source, &error); - - if (book) { - data = g_new (BookOpenData, 1); - data->view = g_object_ref (uid_view); - data->source = g_object_ref (source); - - addressbook_load (book, book_open_cb, data); - } - else { - g_warning ("error loading addressbook : %s", error->message); - g_error_free (error); - } - } - - gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), - gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), - uid_view)); - - if (EAB_VIEW (uid_view)->model) - eab_model_force_folder_bar_message (EAB_VIEW (uid_view)->model); - - /* change menus/toolbars to reflect the new view, assuming we are already displayed */ - if (bonobo_ui_component_get_container (bonobo_control_get_ui_component (priv->folder_view_control)) != CORBA_OBJECT_NIL) { - eab_view_setup_menus (EAB_VIEW (uid_view), bonobo_control_get_ui_component (priv->folder_view_control)); - update_command_state (EAB_VIEW (uid_view), view); - } -} - -AddressbookView * -addressbook_view_new (void) -{ - return g_object_new (ADDRESSBOOK_TYPE_VIEW, NULL); -} - -EActivityHandler* -addressbook_view_peek_activity_handler (AddressbookView *view) -{ - g_return_val_if_fail (ADDRESSBOOK_IS_VIEW (view), NULL); - - return view->priv->activity_handler; -} - -GtkWidget* -addressbook_view_peek_info_label (AddressbookView *view) -{ - g_return_val_if_fail (ADDRESSBOOK_IS_VIEW (view), NULL); - - return view->priv->info_widget; -} - -GtkWidget* -addressbook_view_peek_sidebar (AddressbookView *view) -{ - g_return_val_if_fail (ADDRESSBOOK_IS_VIEW (view), NULL); - - return view->priv->sidebar_widget; -} - -GtkWidget* -addressbook_view_peek_statusbar (AddressbookView *view) -{ - g_return_val_if_fail (ADDRESSBOOK_IS_VIEW (view), NULL); - - return view->priv->statusbar_widget; -} - -BonoboControl* -addressbook_view_peek_folder_view (AddressbookView *view) -{ - g_return_val_if_fail (ADDRESSBOOK_IS_VIEW (view), NULL); - - return view->priv->folder_view_control; -} - -void -addressbook_view_edit_contact (AddressbookView* view, - const char* source_uid, - const char* contact_uid) -{ - AddressbookViewPrivate *priv = view->priv; - - ESource* source = NULL; - EContact* contact = NULL; - EBook* book = NULL; - - if (!source_uid || !contact_uid) - return; - - source = e_source_list_peek_source_by_uid (priv->source_list, source_uid); - if (!source) - return; - - /* FIXME: Can I unref this book? */ - book = e_book_new (source, NULL); - if (!book) - return; - - if (!e_book_open (book, TRUE, NULL)) { - g_object_unref (book); - return; - } - - e_book_get_contact (book, contact_uid, &contact, NULL); - - if (!contact) { - g_object_unref (book); - return; - } - eab_show_contact_editor (book, contact, FALSE, FALSE); - g_object_unref (contact); - g_object_unref (book); -} diff --git a/addressbook/gui/component/addressbook-view.h b/addressbook/gui/component/addressbook-view.h deleted file mode 100644 index f86ce46005..0000000000 --- a/addressbook/gui/component/addressbook-view.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * 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 Toshok <toshok@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef _ADDRESSBOOK_VIEW_H_ -#define _ADDRESSBOOK_VIEW_H_ - -#include <bonobo/bonobo-control.h> - -#define ADDRESSBOOK_TYPE_VIEW (addressbook_view_get_type ()) -#define ADDRESSBOOK_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ADDRESSBOOK_TYPE_VIEW, AddressbookView)) -#define ADDRESSBOOK_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ADDRESSBOOK_TYPE_VIEW, AddressbookViewClass)) -#define ADDRESSBOOK_IS_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ADDRESSBOOK_TYPE_VIEW)) -#define ADDRESSBOOK_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), ADDRESSBOOK_TYPE_VIEW)) - - -typedef struct _AddressbookView AddressbookView; -typedef struct _AddressbookViewPrivate AddressbookViewPrivate; -typedef struct _AddressbookViewClass AddressbookViewClass; - -struct _AddressbookView { - GObject parent; - - AddressbookViewPrivate *priv; -}; - -struct _AddressbookViewClass { - GObjectClass parent_class; -}; - - -GType addressbook_view_get_type (void); - -AddressbookView *addressbook_view_new (void); - -EActivityHandler *addressbook_view_peek_activity_handler (AddressbookView *view); -GtkWidget *addressbook_view_peek_info_label (AddressbookView *view); -GtkWidget *addressbook_view_peek_sidebar (AddressbookView *view); -GtkWidget *addressbook_view_peek_statusbar (AddressbookView *view); -BonoboControl *addressbook_view_peek_folder_view (AddressbookView *view); - -void addressbook_view_edit_contact (AddressbookView* view, - const char* source_id, - const char* contact_id); - -#endif /* _ADDRESSBOOK_VIEW_H_ */ diff --git a/addressbook/gui/component/addressbook.c b/addressbook/gui/component/addressbook.c deleted file mode 100644 index c8285d8171..0000000000 --- a/addressbook/gui/component/addressbook.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * 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) - * - */ - -#include <config.h> - -#include <string.h> - -#include <gtk/gtk.h> -#include <glib/gi18n.h> -#include <libebook/e-book.h> -#include <libedataserver/e-url.h> -#include <libedataserverui/e-passwords.h> - -#include "e-util/e-error.h" -#include "addressbook.h" - -#define d(x) - -static void addressbook_authenticate (EBook *book, gboolean previous_failure, - ESource *source, EBookCallback cb, gpointer closure); -static void auth_required_cb (EBook *book, gpointer data); - -typedef struct { - EBookCallback cb; - ESource *source; - gpointer closure; - guint cancelled : 1; -} LoadSourceData; - -static void -free_load_source_data (LoadSourceData *data) -{ - if (data->source) - g_object_unref (data->source); - g_free (data); -} - -/*this function removes of anything present after semicolon -in uri*/ - -static gchar* -remove_parameters_from_uri (const gchar *uri) -{ - char *euri_str; - EUri *euri; - - euri = e_uri_new (uri); - euri_str = e_uri_to_string (euri, FALSE); - e_uri_free (euri); - return euri_str; -} - -static void -load_source_auth_cb (EBook *book, EBookStatus status, gpointer closure) -{ - LoadSourceData *data = closure; - gboolean was_in = g_object_get_data (G_OBJECT (book), "authenticated") != NULL; - - g_object_set_data (G_OBJECT (book), "authenticated", NULL); - - if (data->cancelled) { - free_load_source_data (data); - return; - } - - if (status != E_BOOK_ERROR_OK) { - - /* the user clicked cancel in the password dialog */ - if (status == E_BOOK_ERROR_CANCELLED) { - - if (e_book_check_static_capability (book, "anon-access")) { - - GtkWidget *dialog; - - /* XXX "LDAP" has to be removed from the folowing message - so that it wil valid for other servers which provide - anonymous access*/ - - dialog = gtk_message_dialog_new (NULL, - 0, - GTK_MESSAGE_WARNING, - GTK_BUTTONS_OK, - "%s", _("Accessing LDAP Server anonymously")); - g_signal_connect (dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL); - gtk_widget_show (dialog); - status = E_BOOK_ERROR_OK; - - goto done; - } - } else if (status == E_BOOK_ERROR_INVALID_SERVER_VERSION) { - e_error_run (NULL, "addressbook:server-version", NULL); - status = E_BOOK_ERROR_OK; - goto done; - } else if (status == E_BOOK_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD) { - goto done; - } else { - if (status == E_BOOK_ERROR_AUTHENTICATION_FAILED) { - const gchar *uri = e_book_get_uri (book); - gchar *stripped_uri = remove_parameters_from_uri (uri); - const gchar *auth_domain = e_source_get_property (data->source, "auth-domain"); - const gchar *component_name; - - component_name = auth_domain ? auth_domain : "Addressbook"; - - e_passwords_forget_password (component_name, stripped_uri); - - g_free (stripped_uri); - } else if (was_in) { - /* We already tried to authenticate to the server, and it failed with - other reason than with E_BOOK_ERROR_AUTHENTICATION_FAILED, thus stop - poking with the server and report error to the user. */ - goto done; - } - - g_object_set_data (G_OBJECT (book), "authenticated", GINT_TO_POINTER (1)); - addressbook_authenticate (book, TRUE, data->source, load_source_auth_cb, closure); - return; - } - } - -done: - if (data->cb) - data->cb (book, status, data->closure); - - free_load_source_data (data); -} - -static gboolean -get_remember_password (ESource *source) -{ - const gchar *value; - - value = e_source_get_property (source, "remember_password"); - if (value && !g_ascii_strcasecmp (value, "true")) - return TRUE; - - return FALSE; -} - -static void -set_remember_password (ESource *source, gboolean value) -{ - e_source_set_property (source, "remember_password", - value ? "true" : "false"); -} - -static void -addressbook_authenticate (EBook *book, gboolean previous_failure, ESource *source, - EBookCallback cb, gpointer closure) -{ - const char *password = NULL; - char *pass_dup = NULL; - const gchar *auth; - const gchar *user; - gchar *uri = remove_parameters_from_uri(e_book_get_uri (book)); - const gchar *auth_domain = e_source_get_property (source, "auth-domain"); - const gchar *component_name; - - component_name = auth_domain ? auth_domain : "Addressbook"; - - password = e_passwords_get_password (component_name, uri); - - auth = e_source_get_property (source, "auth"); - - if (auth && !strcmp ("ldap/simple-binddn", auth)) { - user = e_source_get_property (source, "binddn"); - } - else if (auth && !strcmp ("plain/password", auth)) { - user = e_source_get_property (source, "user"); - if (!user) { - user = e_source_get_property (source, "username"); - } - } - else { - user = e_source_get_property (source, "email_addr"); - } - if (!user) - user = ""; - - if (!password) { - char *prompt; - char *password_prompt; - gboolean remember; - char *failed_auth; - guint32 flags = E_PASSWORDS_REMEMBER_FOREVER|E_PASSWORDS_SECRET|E_PASSWORDS_ONLINE; - - if (previous_failure) { - failed_auth = _("Failed to authenticate.\n"); - flags |= E_PASSWORDS_REPROMPT; - } - else { - failed_auth = ""; - } - - password_prompt = g_strdup_printf (_("Enter password for %s (user %s)"), - e_source_peek_name (source), user); - - prompt = g_strconcat (failed_auth, password_prompt, NULL); - g_free (password_prompt); - - remember = get_remember_password (source); - pass_dup = e_passwords_ask_password ( - _("Enter password"), component_name, - uri, prompt, flags, &remember, NULL); - if (remember != get_remember_password (source)) - set_remember_password (source, remember); - - g_free (prompt); - } - - if (password || pass_dup) { - e_book_async_authenticate_user (book, user, password ? password : pass_dup, - e_source_get_property (source, "auth"), - cb, closure); - g_free (pass_dup); - } - else { - /* they hit cancel */ - cb (book, E_BOOK_ERROR_CANCELLED, closure); - } - - g_free (uri); -} - - - -static void -auth_required_cb (EBook *book, gpointer data) -{ - LoadSourceData *load_source_data = g_new0(LoadSourceData, 1); - - load_source_data->source = g_object_ref (g_object_ref (e_book_get_source (book))); - load_source_data->cancelled = FALSE; - addressbook_authenticate (book, FALSE, load_source_data->source, - load_source_auth_cb, load_source_data); - - - -} -static void -load_source_cb (EBook *book, EBookStatus status, gpointer closure) -{ - LoadSourceData *load_source_data = closure; - - if (load_source_data->cancelled) { - free_load_source_data (load_source_data); - return; - } - - if (status == E_BOOK_ERROR_OK && book != NULL) { - const gchar *auth; - - auth = e_source_get_property (load_source_data->source, "auth"); - if (auth && strcmp (auth, "none")) { - g_signal_connect (book, "auth_required", G_CALLBACK(auth_required_cb), NULL); - - if (e_book_is_online (book)) { - addressbook_authenticate (book, FALSE, load_source_data->source, - load_source_auth_cb, closure); - return; - } - } - } - load_source_data->cb (book, status, load_source_data->closure); - free_load_source_data (load_source_data); -} - -guint -addressbook_load (EBook *book, - EBookCallback cb, gpointer closure) -{ - LoadSourceData *load_source_data = g_new0 (LoadSourceData, 1); - - load_source_data->cb = cb; - load_source_data->closure = closure; - load_source_data->source = g_object_ref (g_object_ref (e_book_get_source (book))); - load_source_data->cancelled = FALSE; - - e_book_async_open (book, FALSE, load_source_cb, load_source_data); - - return GPOINTER_TO_UINT (load_source_data); -} - -void -addressbook_load_cancel (guint id) -{ - LoadSourceData *load_source_data = GUINT_TO_POINTER (id); - - load_source_data->cancelled = TRUE; -} - -static void -default_book_cb (EBook *book, EBookStatus status, gpointer closure) -{ - LoadSourceData *load_source_data = closure; - - if (status == E_BOOK_ERROR_OK) - load_source_data->source = g_object_ref (e_book_get_source (book)); - - load_source_cb (book, status, closure); -} - -void -addressbook_load_default_book (EBookCallback cb, gpointer closure) -{ - LoadSourceData *load_source_data = g_new (LoadSourceData, 1); - EBook *book; - - load_source_data->cb = cb; - load_source_data->source = NULL; - load_source_data->closure = closure; - load_source_data->cancelled = FALSE; - - book = e_book_new_default_addressbook (NULL); - if (!book) - load_source_cb (NULL, E_BOOK_ERROR_OTHER_ERROR, load_source_data); /* XXX we should just use a GError and it's error code here */ - else - e_book_async_open (book, FALSE, default_book_cb, load_source_data); -} diff --git a/addressbook/gui/component/addressbook.h b/addressbook/gui/component/addressbook.h deleted file mode 100644 index a56f088f7d..0000000000 --- a/addressbook/gui/component/addressbook.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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: - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef __ADDRESSBOOK_H__ -#define __ADDRESSBOOK_H__ - -#include <bonobo/bonobo-control.h> -#include <e-util/e-config-listener.h> -#include <bonobo/bonobo-object.h> -#include <bonobo/bonobo-moniker-util.h> -#include <libebook/e-book.h> - -guint addressbook_load (EBook *book, EBookCallback cb, gpointer closure); -void addressbook_load_cancel (guint id); -void addressbook_load_default_book (EBookCallback open_response, gpointer closure); - -#endif /* __ADDRESSBOOK_H__ */ diff --git a/addressbook/gui/component/autocompletion-config.c b/addressbook/gui/component/autocompletion-config.c index 8c259c6a7a..3341f26147 100644 --- a/addressbook/gui/component/autocompletion-config.c +++ b/addressbook/gui/component/autocompletion-config.c @@ -22,45 +22,31 @@ * */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - - #include "autocompletion-config.h" -#include "Evolution.h" - -#include <bonobo/bonobo-exception.h> - +#include <gtk/gtk.h> +#include <glib/gi18n.h> #include <libedataserver/e-source-list.h> #include <libedataserverui/e-source-selector.h> #include <libedataserverui/e-name-selector-entry.h> -#include <gtk/gtk.h> -#include <glib/gi18n.h> - - -typedef struct { - EvolutionConfigControl *config_control; - GtkWidget *control_widget; - - ESourceList *source_list; - GConfClient *gconf; -} AutocompletionConfig; +#include "widgets/misc/e-preferences-window.h" static void -source_selection_changed (ESourceSelector *selector, - AutocompletionConfig *ac) +source_selection_changed_cb (ESourceSelector *source_selector) { + ESourceList *source_list; GSList *selection; GSList *l; GSList *groups; + source_list = e_source_selector_get_source_list (source_selector); + /* first we clear all the completion flags from all sources */ - for (groups = e_source_list_peek_groups (ac->source_list); groups; groups = groups->next) { + for (groups = e_source_list_peek_groups (source_list); groups; groups = groups->next) { ESourceGroup *group = E_SOURCE_GROUP (groups->data); GSList *sources; + for (sources = e_source_group_peek_sources (group); sources; sources = sources->next) { ESource *source = E_SOURCE (sources->data); @@ -70,149 +56,82 @@ source_selection_changed (ESourceSelector *selector, /* then we loop over the selector's selection, setting the property on those sources */ - selection = e_source_selector_get_selection (selector); + selection = e_source_selector_get_selection (source_selector); for (l = selection; l; l = l->next) { - e_source_set_property (E_SOURCE (l->data), "completion", "true"); + ESource *source = E_SOURCE (l->data); + + e_source_set_property (source, "completion", "true"); } e_source_selector_free_selection (selection); - e_source_list_sync (ac->source_list, NULL); /* XXX we should pop up a dialog if this fails */ -} - -static void -config_control_destroy_notify (void *data, - GObject *where_the_config_control_was) -{ - AutocompletionConfig *ac = (AutocompletionConfig *) data; - - g_object_unref (ac->source_list); - g_object_unref (ac->gconf); - - g_free (ac); + /* XXX we should pop up a dialog if this fails */ + e_source_list_sync (source_list, NULL); } static void -initialize_selection (AutocompletionConfig *ac) +initialize_selection (ESourceSelector *source_selector) { + ESourceList *source_list; GSList *groups; - for (groups = e_source_list_peek_groups (ac->source_list); groups; groups = groups->next) { + source_list = e_source_selector_get_source_list (source_selector); + + for (groups = e_source_list_peek_groups (source_list); groups; groups = groups->next) { ESourceGroup *group = E_SOURCE_GROUP (groups->data); GSList *sources; + for (sources = e_source_group_peek_sources (group); sources; sources = sources->next) { ESource *source = E_SOURCE (sources->data); - const char *completion = e_source_get_property (source, "completion"); + const char *completion; + + completion = e_source_get_property (source, "completion"); if (completion && !g_ascii_strcasecmp (completion, "true")) - e_source_selector_select_source (E_SOURCE_SELECTOR (ac->control_widget), - source); + e_source_selector_select_source (source_selector, source); } } } -static GtkWidget * -add_section (GtkWidget *vbox, const gchar *caption, gboolean expand) -{ - GtkWidget *label, *hbox, *itembox; - gchar *txt; - - g_return_val_if_fail (vbox != NULL, NULL); - g_return_val_if_fail (caption != NULL, NULL); - - txt = g_strconcat ("<b>", caption, "</b>", NULL); - - label = gtk_label_new (NULL); - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_label_set_use_markup (GTK_LABEL (label), TRUE); - gtk_label_set_markup (GTK_LABEL (label), txt); - - g_free (txt); - - /* bold caption of the section */ - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); - - hbox = gtk_hbox_new (FALSE, 12); - - /* space on the left for the items in the section */ - gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (""), FALSE, FALSE, 0); - - /* itembox, here will all section items go */ - itembox = gtk_vbox_new (FALSE, 2); - gtk_box_pack_start (GTK_BOX (hbox), itembox, TRUE, TRUE, 0); - - gtk_box_pack_start (GTK_BOX (vbox), hbox, expand, expand, 0); - - return itembox; -} - -static void -show_address_check_toggled_cb (GtkToggleButton *check, AutocompletionConfig *ac) +void +autocompletion_config_init (EShell *shell) { - g_return_if_fail (check != NULL); - g_return_if_fail (ac != NULL); - g_return_if_fail (ac->gconf != NULL); - - gconf_client_set_bool (ac->gconf, FORCE_SHOW_ADDRESS, gtk_toggle_button_get_active (check), NULL); -} - -EvolutionConfigControl* -autocompletion_config_control_new (void) -{ - AutocompletionConfig *ac; - CORBA_Environment ev; - GtkWidget *scrolledwin, *vbox, *itembox, *w; - - ac = g_new0 (AutocompletionConfig, 1); - - CORBA_exception_init (&ev); - - ac->gconf = gconf_client_get_default (); - - vbox = gtk_vbox_new (FALSE, 6); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 12); - - itembox = add_section (vbox, _("Autocompletion"), FALSE); + ESourceList *source_list; + GtkWidget *scrolled_window; + GtkWidget *source_selector; + GtkWidget *preferences_window; - w = gtk_check_button_new_with_mnemonic (_("Always _show address of the autocompleted contact")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), gconf_client_get_bool (ac->gconf, FORCE_SHOW_ADDRESS, NULL)); - g_signal_connect (w, "toggled", (GCallback)show_address_check_toggled_cb, ac); - gtk_box_pack_start (GTK_BOX (itembox), w, FALSE, FALSE, 0); + g_return_if_fail (E_IS_SHELL (shell)); - itembox = add_section (vbox, _("Look up in address books"), TRUE); + source_list = e_source_list_new_for_gconf_default ( + "/apps/evolution/addressbook/sources"); - ac->source_list = e_source_list_new_for_gconf_default ("/apps/evolution/addressbook/sources"); /* XXX should we watch for the source list to change and update it in the control? what about our local changes? */ /* g_signal_connect (ac->source_list, "changed", G_CALLBACK (source_list_changed), ac); */ - scrolledwin = gtk_scrolled_window_new (NULL, NULL); - - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwin), - GTK_SHADOW_IN); - - ac->control_widget = e_source_selector_new (ac->source_list); - - gtk_container_add (GTK_CONTAINER (scrolledwin), ac->control_widget); - - initialize_selection (ac); - - gtk_widget_show (ac->control_widget); - gtk_widget_show (scrolledwin); - - gtk_widget_show_all (vbox); - gtk_box_pack_start (GTK_BOX (itembox), scrolledwin, TRUE, TRUE, 0); - - ac->config_control = evolution_config_control_new (vbox); - - g_signal_connect (ac->control_widget, "selection_changed", - G_CALLBACK (source_selection_changed), ac); - - g_object_weak_ref (G_OBJECT (ac->config_control), config_control_destroy_notify, ac); - - CORBA_exception_free (&ev); - - return ac->config_control; + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy ( + GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type ( + GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN); + gtk_widget_show (scrolled_window); + + source_selector = e_source_selector_new (source_list); + g_signal_connect ( + source_selector, "selection_changed", + G_CALLBACK (source_selection_changed_cb), NULL); + gtk_container_add (GTK_CONTAINER (scrolled_window), source_selector); + gtk_widget_show (source_selector); + + initialize_selection (E_SOURCE_SELECTOR (source_selector)); + + preferences_window = e_shell_get_preferences_window (shell); + + e_preferences_window_add_page ( + E_PREFERENCES_WINDOW (preferences_window), + "autocompletion", + "preferences-autocompletion", + _("Autocompletion"), + scrolled_window, + 200); } - diff --git a/addressbook/gui/component/autocompletion-config.h b/addressbook/gui/component/autocompletion-config.h index 2f4f0184c4..f546a9d497 100644 --- a/addressbook/gui/component/autocompletion-config.h +++ b/addressbook/gui/component/autocompletion-config.h @@ -25,8 +25,13 @@ #ifndef _AUTOCOMPLETION_CONFIG_H #define _AUTOCOMPLETION_CONFIG_H -#include "evolution-config-control.h" +#include <glib.h> +#include <shell/e-shell.h> -EvolutionConfigControl* autocompletion_config_control_new (void); +G_BEGIN_DECLS + +void autocompletion_config_init (EShell *shell); + +G_END_DECLS #endif /* _AUTOCOMPLETION_CONFIG_H */ diff --git a/addressbook/gui/component/component-factory.c b/addressbook/gui/component/component-factory.c deleted file mode 100644 index feea79d88f..0000000000 --- a/addressbook/gui/component/component-factory.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * component-factory.c - Factory for Evolution's Addressbook component. - * - * 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: - * Ettore Perazzoli <ettore@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#include <config.h> - -#include <string.h> -#include "addressbook.h" -#include "addressbook-component.h" -#include "addressbook-config.h" -#include "addressbook-view.h" -#include "autocompletion-config.h" -#include "eab-popup-control.h" -#include "eab-vcard-control.h" -#ifdef ENABLE_SMIME -#include "smime/gui/certificate-manager.h" -#endif -#include <bonobo/bonobo-shlib-factory.h> - - -#define FACTORY_ID "OAFIID:GNOME_Evolution_Addressbook_Factory:" BASE_VERSION - -#define VCARD_CONTROL_ID "OAFIID:GNOME_Evolution_Addressbook_VCard_Control:" BASE_VERSION -#define COMPONENT_ID "OAFIID:GNOME_Evolution_Addressbook_Component:" BASE_VERSION -#define ADDRESS_POPUP_ID "OAFIID:GNOME_Evolution_Addressbook_AddressPopup:" BASE_VERSION -#define COMPLETION_CONFIG_CONTROL_ID "OAFIID:GNOME_Evolution_Addressbook_Autocompletion_ConfigControl:" BASE_VERSION -#define CERTIFICATE_MANAGER_CONFIG_CONTROL_ID "OAFIID:GNOME_Evolution_SMime_CertificateManager_ConfigControl:" BASE_VERSION - -#define d(x) - - -static BonoboObject * -factory (BonoboGenericFactory *factory, - const char *component_id, - void *closure) -{ - d(printf ("asked to activate component_id `%s'\n", component_id)); - - if (strcmp (component_id, VCARD_CONTROL_ID) == 0) - return BONOBO_OBJECT (eab_vcard_control_new ()); - if (strcmp (component_id, COMPONENT_ID) == 0) { - BonoboObject *object = BONOBO_OBJECT (addressbook_component_peek ()); - bonobo_object_ref (object); - return object; - } - if (strcmp (component_id, ADDRESS_POPUP_ID) == 0) - return BONOBO_OBJECT (eab_popup_control_new ()); - if (strcmp (component_id, COMPLETION_CONFIG_CONTROL_ID) == 0) - return BONOBO_OBJECT (autocompletion_config_control_new ()); -#ifdef ENABLE_SMIME - if (strcmp (component_id, CERTIFICATE_MANAGER_CONFIG_CONTROL_ID) == 0) - return BONOBO_OBJECT (certificate_manager_config_control_new ()); -#endif - - g_warning (FACTORY_ID ": Don't know what to do with %s", component_id); - return NULL; -} - -BONOBO_ACTIVATION_SHLIB_FACTORY (FACTORY_ID, "Evolution Addressbook component factory", factory, NULL) diff --git a/addressbook/gui/component/e-book-shell-content.c b/addressbook/gui/component/e-book-shell-content.c new file mode 100644 index 0000000000..8830c797e0 --- /dev/null +++ b/addressbook/gui/component/e-book-shell-content.c @@ -0,0 +1,490 @@ +/* + * e-book-shell-content.c + * + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-book-shell-content.h" + +#include <glib/gi18n.h> +#include <e-util/gconf-bridge.h> + +#define E_BOOK_SHELL_CONTENT_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_BOOK_SHELL_CONTENT, EBookShellContentPrivate)) + +struct _EBookShellContentPrivate { + GtkWidget *paned; + GtkWidget *notebook; + GtkWidget *preview; +}; + +enum { + PROP_0, + PROP_CURRENT_VIEW, + PROP_PREVIEW_CONTACT, + PROP_PREVIEW_VISIBLE +}; + +static gpointer parent_class; + +static void +book_shell_content_send_message_cb (EBookShellContent *book_shell_content, + EDestination *destination, + EABContactDisplay *display) +{ + GList node = { destination, NULL, NULL }; + + eab_send_as_to (&node); +} + +static void +book_shell_content_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CURRENT_VIEW: + e_book_shell_content_set_current_view ( + E_BOOK_SHELL_CONTENT (object), + g_value_get_object (value)); + return; + + case PROP_PREVIEW_CONTACT: + e_book_shell_content_set_preview_contact ( + E_BOOK_SHELL_CONTENT (object), + g_value_get_object (value)); + return; + + case PROP_PREVIEW_VISIBLE: + e_book_shell_content_set_preview_visible ( + E_BOOK_SHELL_CONTENT (object), + g_value_get_boolean (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +book_shell_content_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CURRENT_VIEW: + g_value_set_object ( + value, e_book_shell_content_get_current_view ( + E_BOOK_SHELL_CONTENT (object))); + return; + + case PROP_PREVIEW_CONTACT: + g_value_set_object ( + value, e_book_shell_content_get_preview_contact ( + E_BOOK_SHELL_CONTENT (object))); + return; + + case PROP_PREVIEW_VISIBLE: + g_value_set_boolean ( + value, e_book_shell_content_get_preview_visible ( + E_BOOK_SHELL_CONTENT (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +book_shell_content_dispose (GObject *object) +{ + EBookShellContentPrivate *priv; + + priv = E_BOOK_SHELL_CONTENT_GET_PRIVATE (object); + + if (priv->paned != NULL) { + g_object_unref (priv->paned); + priv->paned = NULL; + } + + if (priv->notebook != NULL) { + g_object_unref (priv->notebook); + priv->notebook = NULL; + } + + if (priv->preview != NULL) { + g_object_unref (priv->preview); + priv->preview = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +book_shell_content_constructed (GObject *object) +{ + EBookShellContentPrivate *priv; + GConfBridge *bridge; + GtkWidget *container; + GtkWidget *widget; + const gchar *key; + + priv = E_BOOK_SHELL_CONTENT_GET_PRIVATE (object); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (parent_class)->constructed (object); + + container = GTK_WIDGET (object); + + widget = gtk_vpaned_new (); + gtk_container_add (GTK_CONTAINER (container), widget); + priv->paned = g_object_ref (widget); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_notebook_new (); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE); + gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE); + gtk_paned_add1 (GTK_PANED (container), widget); + priv->notebook = g_object_ref (widget); + gtk_widget_show (widget); + + widget = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy ( + GTK_SCROLLED_WINDOW (widget), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type ( + GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN); + gtk_paned_add2 (GTK_PANED (container), widget); + gtk_widget_show (widget); + + container = widget; + + widget = eab_contact_display_new (); + eab_contact_display_set_mode ( + EAB_CONTACT_DISPLAY (widget), + EAB_CONTACT_DISPLAY_RENDER_NORMAL); + gtk_container_add (GTK_CONTAINER (container), widget); + priv->preview = g_object_ref (widget); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + priv->preview, "send-message", + G_CALLBACK (book_shell_content_send_message_cb), object); + + /* Bind GObject properties to GConf keys. */ + + bridge = gconf_bridge_get (); + + object = G_OBJECT (priv->paned); + key = "/apps/evolution/addressbook/display/vpane_position"; + gconf_bridge_bind_property_delayed (bridge, key, object, "position"); +} + +static guint32 +book_shell_content_check_state (EShellContent *shell_content) +{ + EBookShellContent *book_shell_content; + ESelectionModel *selection_model; + EAddressbookModel *model; + EAddressbookView *view; + guint32 state = 0; + gint n_contacts; + gint n_selected; + + book_shell_content = E_BOOK_SHELL_CONTENT (shell_content); + view = e_book_shell_content_get_current_view (book_shell_content); + model = e_addressbook_view_get_model (view); + + selection_model = e_addressbook_view_get_selection_model (view); + n_contacts = (selection_model != NULL) ? + e_selection_model_row_count (selection_model) : 0; + n_selected = (selection_model != NULL) ? + e_selection_model_selected_count (selection_model) : 0; + + /* FIXME Finish the rest of the flags. */ + if (n_selected == 1) + state |= E_BOOK_SHELL_CONTENT_SELECTION_SINGLE; + if (n_selected > 1) + state |= E_BOOK_SHELL_CONTENT_SELECTION_MULTIPLE; + if (e_addressbook_model_can_stop (model)) + state |= E_BOOK_SHELL_CONTENT_SOURCE_IS_BUSY; + if (e_addressbook_model_get_editable (model)) + state |= E_BOOK_SHELL_CONTENT_SOURCE_IS_EDITABLE; + if (n_contacts == 0) + state |= E_BOOK_SHELL_CONTENT_SOURCE_IS_EMPTY; + + return state; +} + +static void +book_shell_content_class_init (EBookShellContentClass *class) +{ + GObjectClass *object_class; + EShellContentClass *shell_content_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EBookShellContentPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = book_shell_content_set_property; + object_class->get_property = book_shell_content_get_property; + object_class->dispose = book_shell_content_dispose; + object_class->constructed = book_shell_content_constructed; + + shell_content_class = E_SHELL_CONTENT_CLASS (class); + shell_content_class->check_state = book_shell_content_check_state; + + g_object_class_install_property ( + object_class, + PROP_CURRENT_VIEW, + g_param_spec_object ( + "current-view", + _("Current View"), + _("The currently selected address book view"), + E_TYPE_ADDRESSBOOK_VIEW, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_PREVIEW_CONTACT, + g_param_spec_object ( + "preview-contact", + _("Previewed Contact"), + _("The contact being shown in the preview pane"), + E_TYPE_CONTACT, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_PREVIEW_VISIBLE, + g_param_spec_boolean ( + "preview-visible", + _("Preview is Visible"), + _("Whether the preview pane is visible"), + TRUE, + G_PARAM_READWRITE)); +} + +static void +book_shell_content_init (EBookShellContent *book_shell_content) +{ + book_shell_content->priv = + E_BOOK_SHELL_CONTENT_GET_PRIVATE (book_shell_content); + + /* Postpone widget construction until we have a shell view. */ +} + +GType +e_book_shell_content_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EBookShellContentClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) book_shell_content_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EBookShellContent), + 0, /* n_preallocs */ + (GInstanceInitFunc) book_shell_content_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + E_TYPE_SHELL_CONTENT, "EBookShellContent", + &type_info, 0); + } + + return type; +} + +GtkWidget * +e_book_shell_content_new (EShellView *shell_view) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); + + return g_object_new ( + E_TYPE_BOOK_SHELL_CONTENT, + "shell-view", shell_view, NULL); +} + +void +e_book_shell_content_insert_view (EBookShellContent *book_shell_content, + EAddressbookView *addressbook_view) +{ + GtkNotebook *notebook; + GtkWidget *child; + + g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content)); + g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (addressbook_view)); + + notebook = GTK_NOTEBOOK (book_shell_content->priv->notebook); + child = GTK_WIDGET (addressbook_view); + gtk_notebook_append_page (notebook, child, NULL); +} + +void +e_book_shell_content_remove_view (EBookShellContent *book_shell_content, + EAddressbookView *addressbook_view) +{ + GtkNotebook *notebook; + GtkWidget *child; + gint page_num; + + g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content)); + g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (addressbook_view)); + + notebook = GTK_NOTEBOOK (book_shell_content->priv->notebook); + child = GTK_WIDGET (addressbook_view); + page_num = gtk_notebook_page_num (notebook, child); + g_return_if_fail (page_num >= 0); + + gtk_notebook_remove_page (notebook, page_num); +} + +EAddressbookView * +e_book_shell_content_get_current_view (EBookShellContent *book_shell_content) +{ + GtkNotebook *notebook; + GtkWidget *widget; + gint page_num; + + g_return_val_if_fail ( + E_IS_BOOK_SHELL_CONTENT (book_shell_content), NULL); + + notebook = GTK_NOTEBOOK (book_shell_content->priv->notebook); + page_num = gtk_notebook_get_current_page (notebook); + widget = gtk_notebook_get_nth_page (notebook, page_num); + g_return_val_if_fail (widget != NULL, NULL); + + return E_ADDRESSBOOK_VIEW (widget); +} + +void +e_book_shell_content_set_current_view (EBookShellContent *book_shell_content, + EAddressbookView *addressbook_view) +{ + GtkNotebook *notebook; + GtkWidget *child; + gint page_num; + + g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content)); + g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (addressbook_view)); + + notebook = GTK_NOTEBOOK (book_shell_content->priv->notebook); + child = GTK_WIDGET (addressbook_view); + page_num = gtk_notebook_page_num (notebook, child); + g_return_if_fail (page_num >= 0); + + gtk_notebook_set_current_page (notebook, page_num); + g_object_notify (G_OBJECT (book_shell_content), "current-view"); +} + +EContact * +e_book_shell_content_get_preview_contact (EBookShellContent *book_shell_content) +{ + EABContactDisplay *display; + + g_return_val_if_fail ( + E_IS_BOOK_SHELL_CONTENT (book_shell_content), NULL); + + display = EAB_CONTACT_DISPLAY (book_shell_content->priv->preview); + + return eab_contact_display_get_contact (display); +} + +void +e_book_shell_content_set_preview_contact (EBookShellContent *book_shell_content, + EContact *preview_contact) +{ + EABContactDisplay *display; + + g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content)); + + display = EAB_CONTACT_DISPLAY (book_shell_content->priv->preview); + + eab_contact_display_set_contact (display, preview_contact); + g_object_notify (G_OBJECT (book_shell_content), "preview-contact"); +} + +gboolean +e_book_shell_content_get_preview_visible (EBookShellContent *book_shell_content) +{ + GtkPaned *paned; + GtkWidget *child; + + g_return_val_if_fail ( + E_IS_BOOK_SHELL_CONTENT (book_shell_content), FALSE); + + paned = GTK_PANED (book_shell_content->priv->paned); + child = gtk_paned_get_child2 (paned); + + return GTK_WIDGET_VISIBLE (child); +} + +void +e_book_shell_content_set_preview_visible (EBookShellContent *book_shell_content, + gboolean preview_visible) +{ + GtkPaned *paned; + GtkWidget *child; + + g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content)); + + paned = GTK_PANED (book_shell_content->priv->paned); + child = gtk_paned_get_child2 (paned); + + if (preview_visible) + gtk_widget_show (child); + else + gtk_widget_hide (child); + + g_object_notify (G_OBJECT (book_shell_content), "preview-visible"); +} + +void +e_book_shell_content_clipboard_copy (EBookShellContent *book_shell_content) +{ + EAddressbookView *addressbook_view; + GtkHTML *html; + gchar *selection; + + g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content)); + + html = GTK_HTML (book_shell_content->priv->preview); + addressbook_view = + e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (addressbook_view != NULL); + + if (!GTK_WIDGET_HAS_FOCUS (html)) { + e_addressbook_view_copy (addressbook_view); + return; + } + + selection = gtk_html_get_selection_html (html, NULL); + if (selection != NULL) + gtk_html_copy (html); + g_free (selection); +} diff --git a/addressbook/gui/component/e-book-shell-content.h b/addressbook/gui/component/e-book-shell-content.h new file mode 100644 index 0000000000..e8fe856a86 --- /dev/null +++ b/addressbook/gui/component/e-book-shell-content.h @@ -0,0 +1,106 @@ +/* + * e-book-shell-content.h + * + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_BOOK_SHELL_CONTENT_H +#define E_BOOK_SHELL_CONTENT_H + +#include <libebook/e-contact.h> + +#include "shell/e-shell-content.h" +#include "shell/e-shell-view.h" + +#include "addressbook/gui/component/eab-composer-util.h" +#include "addressbook/gui/widgets/e-addressbook-view.h" + +/* Standard GObject macros */ +#define E_TYPE_BOOK_SHELL_CONTENT \ + (e_book_shell_content_get_type ()) +#define E_BOOK_SHELL_CONTENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_BOOK_SHELL_CONTENT, EBookShellContent)) +#define E_BOOK_SHELL_CONTENT_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_BOOK_SHELL_CONTENT, EBookShellContentClass)) +#define E_IS_BOOK_SHELL_CONTENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_BOOK_SHELL_CONTENT)) +#define E_IS_BOOK_SHELL_CONTENT_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_BOOK_SHELL_CONTENT)) +#define E_BOOK_SHELL_CONTENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_BOOK_SHELL_CONTENT, EBookShellContentClass)) + +G_BEGIN_DECLS + +typedef struct _EBookShellContent EBookShellContent; +typedef struct _EBookShellContentClass EBookShellContentClass; +typedef struct _EBookShellContentPrivate EBookShellContentPrivate; + +enum { + E_BOOK_SHELL_CONTENT_SELECTION_SINGLE = 1 << 0, + E_BOOK_SHELL_CONTENT_SELECTION_MULTIPLE = 1 << 1, + E_BOOK_SHELL_CONTENT_SELECTION_HAS_EMAIL = 1 << 2, + E_BOOK_SHELL_CONTENT_SELECTION_IS_CONTACT_LIST = 1 << 3, + E_BOOK_SHELL_CONTENT_SELECTION_HAS_HTTP_URI = 1 << 4, + E_BOOK_SHELL_CONTENT_SELECTION_HAS_MAILTO_URI = 1 << 5, + E_BOOK_SHELL_CONTENT_SOURCE_IS_BUSY = 1 << 6, + E_BOOK_SHELL_CONTENT_SOURCE_IS_EDITABLE = 1 << 7, + E_BOOK_SHELL_CONTENT_SOURCE_IS_EMPTY = 1 << 8 +}; + +struct _EBookShellContent { + EShellContent parent; + EBookShellContentPrivate *priv; +}; + +struct _EBookShellContentClass { + EShellContentClass parent_class; +}; + +GType e_book_shell_content_get_type (void); +GtkWidget * e_book_shell_content_new (EShellView *shell_view); +void e_book_shell_content_insert_view(EBookShellContent *book_shell_content, + EAddressbookView *addressbook_view); +void e_book_shell_content_remove_view(EBookShellContent *book_shell_content, + EAddressbookView *addressbook_view); +EAddressbookView * + e_book_shell_content_get_current_view + (EBookShellContent *book_shell_content); +void e_book_shell_content_set_current_view + (EBookShellContent *book_shell_content, + EAddressbookView *addressbook_view); +EContact * e_book_shell_content_get_preview_contact + (EBookShellContent *book_shell_content); +void e_book_shell_content_set_preview_contact + (EBookShellContent *book_shell_content, + EContact *preview_contact); +gboolean e_book_shell_content_get_preview_visible + (EBookShellContent *book_shell_content); +void e_book_shell_content_set_preview_visible + (EBookShellContent *book_shell_content, + gboolean preview_visible); +void e_book_shell_content_clipboard_copy + (EBookShellContent *book_shell_content); + +G_END_DECLS + +#endif /* E_BOOK_SHELL_CONTENT_H */ diff --git a/addressbook/gui/component/addressbook-migrate.c b/addressbook/gui/component/e-book-shell-module-migrate.c index f0e106e14c..e4e2c04098 100644 --- a/addressbook/gui/component/addressbook-migrate.c +++ b/addressbook/gui/component/e-book-shell-module-migrate.c @@ -1,4 +1,6 @@ /* + * e-book-shell-module-migrate.c + * * 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 @@ -45,7 +47,7 @@ #include "e-util/e-xml-utils.h" #include "e-util/e-folder-map.h" -#include "addressbook-migrate.h" +#include "e-book-shell-module-migrate.h" /*#define SLOW_MIGRATION*/ @@ -57,7 +59,7 @@ typedef struct { ESourceList *source_list; - AddressbookComponent *component; + const gchar *data_dir; GtkWidget *window; GtkWidget *label; @@ -450,14 +452,12 @@ create_groups (MigrationContext *context, GSList *groups; ESourceGroup *group; char *base_uri, *base_uri_proto; - const gchar *base_dir; *on_this_computer = NULL; *on_ldap_servers = NULL; *personal_source = NULL; - base_dir = addressbook_component_peek_base_directory (context->component); - base_uri = g_build_filename (base_dir, "local", NULL); + base_uri = g_build_filename (context->data_dir, "local", NULL); base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL); @@ -744,12 +744,17 @@ get_source_by_name (ESourceList *source_list, const char *name) static gboolean migrate_completion_folders (MigrationContext *context) { - char *uris_xml = gconf_client_get_string (addressbook_component_peek_gconf_client (context->component), - "/apps/evolution/addressbook/completion/uris", - NULL); + GConfClient *client; + const gchar *key; + gchar *uris_xml; printf ("trying to migrate completion folders\n"); + client = gconf_client_get_default (); + key = "/apps/evolution/addressbook/completion/uris"; + uris_xml = gconf_client_get_string (client, key, NULL); + g_object_unref (client); + if (uris_xml) { xmlDoc *doc = xmlParseMemory (uris_xml, strlen (uris_xml)); xmlNode *root; @@ -1076,17 +1081,20 @@ migrate_pilot_data (const char *old_path, const char *new_path) g_dir_close (dir); } -static MigrationContext* -migration_context_new (AddressbookComponent *component) +static MigrationContext * +migration_context_new (const gchar *data_dir) { MigrationContext *context = g_new (MigrationContext, 1); /* set up the mapping from old uris to new uids */ - context->folder_uid_map = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, (GDestroyNotify)g_free); + context->folder_uid_map = g_hash_table_new_full ( + g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_free); e_book_get_addressbooks (&context->source_list, NULL); - context->component = component; + context->data_dir = data_dir; return context; } @@ -1103,16 +1111,24 @@ migration_context_free (MigrationContext *context) g_free (context); } -int -addressbook_migrate (AddressbookComponent *component, int major, int minor, int revision, GError **err) +gboolean +e_book_shell_module_migrate (EShellModule *shell_module, + gint major, + gint minor, + gint micro, + GError **error) { ESourceGroup *on_this_computer; ESourceGroup *on_ldap_servers; ESource *personal_source; - MigrationContext *context = migration_context_new (component); + MigrationContext *context; gboolean need_dialog = FALSE; + const gchar *data_dir; + + g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), FALSE); - printf ("addressbook_migrate (%d.%d.%d)\n", major, minor, revision); + data_dir = e_shell_module_get_data_dir (shell_module); + context = migration_context_new (data_dir); /* we call this unconditionally now - create_groups either creates the groups/sources or it finds the necessary @@ -1123,7 +1139,7 @@ addressbook_migrate (AddressbookComponent *component, int major, int minor, int if (major == 1 /* we only need the most recent upgrade point here. further decomposition will happen below. */ - && (minor < 5 || (minor == 5 && revision <= 10))) + && (minor < 5 || (minor == 5 && micro <= 10))) need_dialog = TRUE; if (need_dialog) @@ -1131,7 +1147,7 @@ addressbook_migrate (AddressbookComponent *component, int major, int minor, int if (major == 1) { - if (minor < 5 || (minor == 5 && revision <= 2)) { + if (minor < 5 || (minor == 5 && micro <= 2)) { /* initialize our dialog */ dialog_set_label (context, _("The location and hierarchy of the Evolution contact " @@ -1146,7 +1162,7 @@ addressbook_migrate (AddressbookComponent *component, int major, int minor, int migrate_completion_folders (context); } - if (minor < 5 || (minor == 5 && revision <= 7)) { + if (minor < 5 || (minor == 5 && micro <= 7)) { dialog_set_label (context, _("The format of mailing list contacts has changed.\n\n" "Please be patient while Evolution migrates your " @@ -1155,7 +1171,7 @@ addressbook_migrate (AddressbookComponent *component, int major, int minor, int migrate_contact_lists_for_local_folders (context, on_this_computer); } - if (minor < 5 || (minor == 5 && revision <= 8)) { + if (minor < 5 || (minor == 5 && micro <= 8)) { dialog_set_label (context, _("The way Evolution stores some phone numbers has changed.\n\n" "Please be patient while Evolution migrates your " @@ -1164,15 +1180,14 @@ addressbook_migrate (AddressbookComponent *component, int major, int minor, int migrate_company_phone_for_local_folders (context, on_this_computer); } - if (minor < 5 || (minor == 5 && revision <= 10)) { + if (minor < 5 || (minor == 5 && micro <= 10)) { char *old_path, *new_path; dialog_set_label (context, _("Evolution's Palm Sync changelog and map files have changed.\n\n" "Please be patient while Evolution migrates your Pilot Sync data...")); old_path = g_build_filename (g_get_home_dir (), "evolution", "local", "Contacts", NULL); - new_path = g_build_filename (addressbook_component_peek_base_directory (component), - "local", "system", NULL); + new_path = g_build_filename (data_dir, "local", "system", NULL); migrate_pilot_data (old_path, new_path); g_free (new_path); g_free (old_path); @@ -1184,7 +1199,7 @@ addressbook_migrate (AddressbookComponent *component, int major, int minor, int during one phase of development, as they take precedent over relative uris (but aren't updated when editing an ESource). */ - if (minor == 5 && revision <= 11) { + if (minor == 5 && micro <= 11) { GSList *g; for (g = e_source_list_peek_groups (context->source_list); g; g = g->next) { ESourceGroup *group = g->data; diff --git a/addressbook/gui/component/addressbook-migrate.h b/addressbook/gui/component/e-book-shell-module-migrate.h index ad3df6b26a..8e19c73989 100644 --- a/addressbook/gui/component/addressbook-migrate.h +++ b/addressbook/gui/component/e-book-shell-module-migrate.h @@ -1,4 +1,5 @@ /* + * e-book-shell-module-migrate.h * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,13 +22,20 @@ * */ -#ifndef _ADDRESSBOOK_MIGRATE_H_ -#define _ADDRESSBOOK_MIGRATE_H_ +#ifndef E_BOOK_SHELL_MODULE_MIGRATE_H +#define E_BOOK_SHELL_MODULE_MIGRATE_H -#include "addressbook-component.h" +#include <glib.h> +#include <shell/e-shell-module.h> -struct _GError; +G_BEGIN_DECLS -int addressbook_migrate (AddressbookComponent *component, int major, int minor, int revision, struct _GError **err); +gboolean e_book_shell_module_migrate (EShellModule *shell_module, + gint major, + gint minor, + gint micro, + GError **error); -#endif /* _ADDRESSBOOK_MIGRATE_H_ */ +G_END_DECLS + +#endif /* E_BOOK_SHELL_MODULE_MIGRATE_H */ diff --git a/addressbook/gui/component/e-book-shell-module.c b/addressbook/gui/component/e-book-shell-module.c new file mode 100644 index 0000000000..80bbc8318e --- /dev/null +++ b/addressbook/gui/component/e-book-shell-module.c @@ -0,0 +1,479 @@ +/* + * e-book-shell-module.c + * + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include <string.h> +#include <glib/gi18n.h> +#include <libebook/e-book.h> +#include <libedataserver/e-url.h> +#include <libedataserver/e-source.h> +#include <libedataserver/e-source-list.h> +#include <libedataserver/e-source-group.h> + +#include "shell/e-shell.h" +#include "shell/e-shell-module.h" +#include "shell/e-shell-window.h" + +#include "e-util/e-import.h" +#include "addressbook/gui/widgets/eab-gui-util.h" +#include "addressbook/gui/contact-editor/e-contact-editor.h" +#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h" +#include "addressbook/importers/evolution-addressbook-importers.h" + +#include <eab-config.h> +#include <addressbook-config.h> +#include <autocompletion-config.h> + +#include "e-book-shell-view.h" +#include "e-book-shell-module-migrate.h" + +#ifdef ENABLE_SMIME +#include "smime/gui/component.h" +#include "smime/gui/certificate-manager.h" +#endif + +#define MODULE_NAME "addressbook" +#define MODULE_ALIASES "contacts" +#define MODULE_SCHEMES "" +#define MODULE_SORT_ORDER 300 + +#define LDAP_BASE_URI "ldap://" +#define PERSONAL_RELATIVE_URI "system" + +/* Module Entry Point */ +void e_shell_module_init (GTypeModule *type_module); + +static void +book_module_ensure_sources (EShellModule *shell_module) +{ + /* XXX This is basically the same algorithm across all modules. + * Maybe we could somehow integrate this into EShellModule? */ + + ESourceList *source_list; + ESourceGroup *on_this_computer; + ESourceGroup *on_ldap_servers; + ESource *personal; + GSList *groups, *iter; + const gchar *data_dir; + const gchar *name; + gchar *base_uri; + gchar *filename; + + on_this_computer = NULL; + on_ldap_servers = NULL; + personal = NULL; + + if (!e_book_get_addressbooks (&source_list, NULL)) { + g_warning ("Could not get addressbook sources from GConf!"); + return; + } + + /* Share the source list with all address book views. This + * is accessible via e_book_shell_view_get_source_list(). + * Note: EShellModule takes ownership of the reference. + * + * XXX I haven't yet decided if I want to add a proper + * EShellModule API for this. The mail module would + * not use it. */ + g_object_set_data_full ( + G_OBJECT (shell_module), "source-list", + source_list, (GDestroyNotify) g_object_unref); + + data_dir = e_shell_module_get_data_dir (shell_module); + filename = g_build_filename (data_dir, "local", NULL); + base_uri = g_filename_to_uri (filename, NULL, NULL); + g_free (filename); + + groups = e_source_list_peek_groups (source_list); + for (iter = groups; iter != NULL; iter = iter->next) { + ESourceGroup *source_group = iter->data; + const gchar *group_base_uri; + + group_base_uri = e_source_group_peek_base_uri (source_group); + + /* Compare only "file://" part. If the user's home + * changes, we do not want to create another group. */ + if (on_this_computer == NULL && + strncmp (base_uri, group_base_uri, 7) == 0) + on_this_computer = source_group; + + else if (on_ldap_servers == NULL && + strcmp (LDAP_BASE_URI, group_base_uri) == 0) + on_ldap_servers = source_group; + } + + name = _("On This Computer"); + + if (on_this_computer != NULL) { + GSList *sources; + const gchar *group_base_uri; + + /* Force the group name to the current locale. */ + e_source_group_set_name (on_this_computer, name); + + sources = e_source_group_peek_sources (on_this_computer); + group_base_uri = e_source_group_peek_base_uri (on_this_computer); + + /* Make sure this group includes a "Personal" source. */ + for (iter = sources; iter != NULL; iter = iter->next) { + ESource *source = iter->data; + const gchar *relative_uri; + + relative_uri = e_source_peek_relative_uri (source); + if (relative_uri == NULL) + continue; + + if (strcmp (PERSONAL_RELATIVE_URI, relative_uri) != 0) + continue; + + personal = source; + break; + } + + /* Make sure we have the correct base URI. This can + * change when the user's home directory changes. */ + if (strcmp (base_uri, group_base_uri) != 0) { + e_source_group_set_base_uri ( + on_this_computer, base_uri); + + /* XXX We shouldn't need this sync call here as + * set_base_uri() results in synching to GConf, + * but that happens in an idle loop and too late + * to prevent the user from seeing a "Cannot + * Open ... because of invalid URI" error. */ + e_source_list_sync (source_list, NULL); + } + + } else { + ESourceGroup *source_group; + + source_group = e_source_group_new (name, base_uri); + e_source_list_add_group (source_list, source_group, -1); + g_object_unref (source_group); + } + + name = _("Personal"); + + if (personal == NULL) { + ESource *source; + + /* Create the default Personal address book. */ + source = e_source_new (name, PERSONAL_RELATIVE_URI); + e_source_group_add_source (on_this_computer, source, -1); + e_source_set_property (source, "completion", "true"); + g_object_unref (source); + } else { + /* Force the source name to the current locale. */ + e_source_set_name (personal, name); + } + + name = _("On LDAP Servers"); + + if (on_ldap_servers == NULL) { + ESourceGroup *source_group; + + source_group = e_source_group_new (name, LDAP_BASE_URI); + e_source_list_add_group (source_list, source_group, -1); + g_object_unref (source_group); + } else { + /* Force the group name to the current locale. */ + e_source_group_set_name (on_ldap_servers, name); + } + + g_free (base_uri); +} + +static void +book_module_init_importers (void) +{ + EImportClass *import_class; + EImportImporter *importer; + + import_class = g_type_class_ref (e_import_get_type ()); + + importer = evolution_ldif_importer_peek (); + e_import_class_add_importer (import_class, importer, NULL, NULL); + + importer = evolution_vcard_importer_peek (); + e_import_class_add_importer (import_class, importer, NULL, NULL); + + importer = evolution_csv_outlook_importer_peek (); + e_import_class_add_importer (import_class, importer, NULL, NULL); + + importer = evolution_csv_mozilla_importer_peek (); + e_import_class_add_importer (import_class, importer, NULL, NULL); + + importer = evolution_csv_evolution_importer_peek (); + e_import_class_add_importer (import_class, importer, NULL, NULL); +} + +static void +book_module_book_loaded_cb (EBook *book, + EBookStatus status, + gpointer user_data) +{ + EContact *contact; + GtkAction *action; + GtkWidget *editor; + const gchar *action_name; + + /* XXX Handle errors better. */ + if (status != E_BOOK_ERROR_OK) + return; + + contact = e_contact_new (); + action = GTK_ACTION (user_data); + action_name = gtk_action_get_name (action); + + if (strcmp (action_name, "contact-new") == 0) + editor = e_contact_editor_new (book, contact, TRUE, TRUE); + + if (strcmp (action_name, "contact-new-list") == 0) + editor = e_contact_list_editor_new (book, contact, TRUE, TRUE); + + eab_editor_show (EAB_EDITOR (editor)); + + g_object_unref (contact); + g_object_unref (book); +} + +static void +action_contact_new_cb (GtkAction *action, + EShellWindow *shell_window) +{ + EShell *shell; + EBook *book = NULL; + GConfClient *client; + ESourceList *source_list; + const gchar *key; + gchar *uid; + + /* This callback is used for both contacts and contact lists. */ + + if (!e_book_get_addressbooks (&source_list, NULL)) { + g_warning ("Could not get addressbook sources from GConf!"); + return; + } + + shell = e_shell_window_get_shell (shell_window); + client = e_shell_get_gconf_client (shell); + + key = "/apps/evolution/addressbook/display/primary_addressbook"; + uid = gconf_client_get_string (client, key, NULL); + + if (uid != NULL) { + ESource *source; + + source = e_source_list_peek_source_by_uid (source_list, uid); + if (source != NULL) + book = e_book_new (source, NULL); + g_free (uid); + } + + if (book == NULL) + book = e_book_new_default_addressbook (NULL); + + e_book_async_open (book, FALSE, book_module_book_loaded_cb, action); +} + +static void +action_address_book_new_cb (GtkAction *action, + EShellWindow *shell_window) +{ + addressbook_config_create_new_source (NULL); +} + +static GtkActionEntry item_entries[] = { + + { "contact-new", + "contact-new", + NC_("New", "_Contact"), + "<Shift><Control>c", + N_("Create a new contact"), + G_CALLBACK (action_contact_new_cb) }, + + { "contact-new-list", + "stock_contact-list", + N_("Contact _List"), + "<Shift><Control>l", + N_("Create a new contact list"), + G_CALLBACK (action_contact_new_cb) } +}; + +static GtkActionEntry source_entries[] = { + + { "address-book-new", + "address-book-new", + NC_("New", "Address _Book"), + NULL, + N_("Create a new address book"), + G_CALLBACK (action_address_book_new_cb) } +}; + +static gboolean +book_module_is_busy (EShellModule *shell_module) +{ + return !eab_editor_request_close_all (); +} + +static gboolean +book_module_shutdown (EShellModule *shell_module) +{ + /* FIXME */ + return TRUE; +} + +static gboolean +book_module_handle_uri_cb (EShellModule *shell_module, + const gchar *uri) +{ + EUri *euri; + const gchar *cp; + gchar *source_uid = NULL; + gchar *contact_uid = NULL; + + if (!g_str_has_prefix (uri, "contacts:")) + return FALSE; + + euri = e_uri_new (uri); + cp = euri->query; + + if (cp == NULL) { + e_uri_free (euri); + return FALSE; + } + + while (*cp != '\0') { + gchar *header; + gchar *content; + gsize length; + gsize content_length; + + length = strcspn (cp, "=&"); + + /* If it's malformed, give up. */ + if (cp[length] != '=') + break; + + header = (gchar *) cp; + header[length] = '\0'; + cp += length + 1; + + content_length = strcspn (cp, "&"); + content = g_strndup (cp, content_length); + + if (g_ascii_strcasecmp (header, "source-uid") == 0) + source_uid = g_strdup (content); + + if (g_ascii_strcasecmp (header, "contact-uid") == 0) + contact_uid = g_strdup (content); + + g_free (content); + + cp += content_length; + if (*cp == '&') { + cp++; + if (strcmp (cp, "amp;")) + cp += 4; + } + } + + /* FIXME */ + /*addressbook_view_edit_contact (view, source_uid, contact_uid);*/ + + g_free (source_uid); + g_free (contact_uid); + + e_uri_free (euri); + + return TRUE; +} + +static void +book_module_window_created_cb (EShellModule *shell_module, + GtkWindow *window) +{ + const gchar *module_name; + + if (!E_IS_SHELL_WINDOW (window)) + return; + + module_name = G_TYPE_MODULE (shell_module)->name; + + e_shell_window_register_new_item_actions ( + E_SHELL_WINDOW (window), module_name, + item_entries, G_N_ELEMENTS (item_entries)); + + e_shell_window_register_new_source_actions ( + E_SHELL_WINDOW (window), module_name, + source_entries, G_N_ELEMENTS (source_entries)); +} + +static EShellModuleInfo module_info = { + + MODULE_NAME, + MODULE_ALIASES, + MODULE_SCHEMES, + MODULE_SORT_ORDER, + + /* Methods */ + /* start */ NULL, + book_module_is_busy, + book_module_shutdown, + e_book_shell_module_migrate +}; + +void +e_shell_module_init (GTypeModule *type_module) +{ + EShell *shell; + EShellModule *shell_module; + + shell_module = E_SHELL_MODULE (type_module); + shell = e_shell_module_get_shell (shell_module); + + e_shell_module_set_info ( + shell_module, &module_info, + e_book_shell_view_get_type (type_module)); + + /* XXX Why is this here? Address books aren't the only + * things that use S/MIME. Maybe put it in EShell? */ +#ifdef ENABLE_SMIME + smime_component_init (); + certificate_manager_config_init (shell); +#endif + + book_module_init_importers (); + book_module_ensure_sources (shell_module); + + e_plugin_hook_register_type (eab_config_get_type ()); + + g_signal_connect_swapped ( + shell, "handle-uri", + G_CALLBACK (book_module_handle_uri_cb), shell_module); + + g_signal_connect_swapped ( + shell, "window-created", + G_CALLBACK (book_module_window_created_cb), shell_module); + + autocompletion_config_init (shell); +} diff --git a/addressbook/gui/component/e-book-shell-sidebar.c b/addressbook/gui/component/e-book-shell-sidebar.c new file mode 100644 index 0000000000..fd9cdbe925 --- /dev/null +++ b/addressbook/gui/component/e-book-shell-sidebar.c @@ -0,0 +1,228 @@ +/* + * e-book-shell-sidebar.c + * + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-book-shell-sidebar.h" + +#include <string.h> +#include <glib/gi18n.h> + +#include <e-book-shell-view.h> +#include <e-addressbook-selector.h> + +#define E_BOOK_SHELL_SIDEBAR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_BOOK_SHELL_SIDEBAR, EBookShellSidebarPrivate)) + +struct _EBookShellSidebarPrivate { + GtkWidget *selector; +}; + +enum { + PROP_0, + PROP_SELECTOR +}; + +static gpointer parent_class; + +static void +book_shell_sidebar_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SELECTOR: + g_value_set_object ( + value, e_book_shell_sidebar_get_selector ( + E_BOOK_SHELL_SIDEBAR (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +book_shell_sidebar_dispose (GObject *object) +{ + EBookShellSidebarPrivate *priv; + + priv = E_BOOK_SHELL_SIDEBAR_GET_PRIVATE (object); + + if (priv->selector != NULL) { + g_object_unref (priv->selector); + priv->selector = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +book_shell_sidebar_constructed (GObject *object) +{ + EBookShellSidebarPrivate *priv; + EShellView *shell_view; + EShellSidebar *shell_sidebar; + EBookShellView *book_shell_view; + ESourceList *source_list; + GtkContainer *container; + GtkWidget *widget; + + priv = E_BOOK_SHELL_SIDEBAR_GET_PRIVATE (object); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (parent_class)->constructed (object); + + shell_sidebar = E_SHELL_SIDEBAR (object); + shell_view = e_shell_sidebar_get_shell_view (shell_sidebar); + book_shell_view = E_BOOK_SHELL_VIEW (shell_view); + source_list = e_book_shell_view_get_source_list (book_shell_view); + + container = GTK_CONTAINER (shell_sidebar); + + widget = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy ( + GTK_SCROLLED_WINDOW (widget), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type ( + GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN); + gtk_container_add (container, widget); + gtk_widget_show (widget); + + container = GTK_CONTAINER (widget); + + widget = e_addressbook_selector_new (source_list); + e_source_selector_show_selection (E_SOURCE_SELECTOR (widget), FALSE); + gtk_container_add (GTK_CONTAINER (container), widget); + priv->selector = g_object_ref (widget); + gtk_widget_show (widget); +} + +static guint32 +book_shell_sidebar_check_state (EShellSidebar *shell_sidebar) +{ + EBookShellSidebar *book_shell_sidebar; + ESourceSelector *selector; + ESource *source; + gboolean is_system = FALSE; + guint32 state = 0; + + book_shell_sidebar = E_BOOK_SHELL_SIDEBAR (shell_sidebar); + selector = e_book_shell_sidebar_get_selector (book_shell_sidebar); + source = e_source_selector_peek_primary_selection (selector); + + if (source != NULL) { + const gchar *uri; + + uri = e_source_peek_relative_uri (source); + is_system = (uri == NULL || strcmp (uri, "system") == 0); + } + + if (source != NULL) + state |= E_BOOK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE; + if (is_system) + state |= E_BOOK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM; + + return state; +} + +static void +book_shell_sidebar_class_init (EBookShellSidebarClass *class) +{ + GObjectClass *object_class; + EShellSidebarClass *shell_sidebar_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EBookShellSidebarPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->get_property = book_shell_sidebar_get_property; + object_class->dispose = book_shell_sidebar_dispose; + object_class->constructed = book_shell_sidebar_constructed; + + shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class); + shell_sidebar_class->check_state = book_shell_sidebar_check_state; + + g_object_class_install_property ( + object_class, + PROP_SELECTOR, + g_param_spec_object ( + "selector", + _("Source Selector Widget"), + _("This widget displays groups of address books"), + E_TYPE_SOURCE_SELECTOR, + G_PARAM_READABLE)); +} + +static void +book_shell_sidebar_init (EBookShellSidebar *book_shell_sidebar) +{ + book_shell_sidebar->priv = + E_BOOK_SHELL_SIDEBAR_GET_PRIVATE (book_shell_sidebar); + + /* Postpone widget construction until we have a shell view. */ +} + +GType +e_book_shell_sidebar_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EBookShellSidebarClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) book_shell_sidebar_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EBookShellSidebar), + 0, /* n_preallocs */ + (GInstanceInitFunc) book_shell_sidebar_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + E_TYPE_SHELL_SIDEBAR, "EBookShellSidebar", + &type_info, 0); + } + + return type; +} + +GtkWidget * +e_book_shell_sidebar_new (EShellView *shell_view) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); + + return g_object_new ( + E_TYPE_BOOK_SHELL_SIDEBAR, + "shell-view", shell_view, NULL); +} + +ESourceSelector * +e_book_shell_sidebar_get_selector (EBookShellSidebar *book_shell_sidebar) +{ + g_return_val_if_fail ( + E_IS_BOOK_SHELL_SIDEBAR (book_shell_sidebar), NULL); + + return E_SOURCE_SELECTOR (book_shell_sidebar->priv->selector); +} diff --git a/addressbook/gui/component/e-book-shell-sidebar.h b/addressbook/gui/component/e-book-shell-sidebar.h new file mode 100644 index 0000000000..159c9c7afc --- /dev/null +++ b/addressbook/gui/component/e-book-shell-sidebar.h @@ -0,0 +1,77 @@ +/* + * e-book-shell-sidebar.h + * + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_BOOK_SHELL_SIDEBAR_H +#define E_BOOK_SHELL_SIDEBAR_H + +#include <libedataserverui/e-source-selector.h> + +#include <e-shell-sidebar.h> +#include <e-shell-view.h> + +/* Standard GObject macros */ +#define E_TYPE_BOOK_SHELL_SIDEBAR \ + (e_book_shell_sidebar_get_type ()) +#define E_BOOK_SHELL_SIDEBAR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_BOOK_SHELL_SIDEBAR, EBookShellSidebar)) +#define E_BOOK_SHELL_SIDEBAR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_BOOK_SHELL_SIDEBAR, EBookShellSidebarClass)) +#define E_IS_BOOK_SHELL_SIDEBAR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_BOOK_SHELL_SIDEBAR)) +#define E_IS_BOOK_SHELL_SIDEBAR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_BOOK_SHELL_SIDEBAR)) +#define E_BOOK_SHELL_SIDEBAR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_BOOK_SHELL_SIDEBAR, EBookShellSidebarClass)) + +G_BEGIN_DECLS + +typedef struct _EBookShellSidebar EBookShellSidebar; +typedef struct _EBookShellSidebarClass EBookShellSidebarClass; +typedef struct _EBookShellSidebarPrivate EBookShellSidebarPrivate; + +enum { + E_BOOK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE = 1 << 0, + E_BOOK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM = 1 << 1 +}; + +struct _EBookShellSidebar { + EShellSidebar parent; + EBookShellSidebarPrivate *priv; +}; + +struct _EBookShellSidebarClass { + EShellSidebarClass parent_class; +}; + +GType e_book_shell_sidebar_get_type (void); +GtkWidget * e_book_shell_sidebar_new (EShellView *shell_view); +ESourceSelector * + e_book_shell_sidebar_get_selector + (EBookShellSidebar *book_shell_sidebar); + +G_END_DECLS + +#endif /* E_BOOK_SHELL_SIDEBAR_H */ diff --git a/addressbook/gui/component/e-book-shell-view-actions.c b/addressbook/gui/component/e-book-shell-view-actions.c new file mode 100644 index 0000000000..ed88b54855 --- /dev/null +++ b/addressbook/gui/component/e-book-shell-view-actions.c @@ -0,0 +1,979 @@ +/* + * e-book-shell-view-actions.c + * + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-book-shell-view-private.h" + +#include <e-util/e-error.h> +#include <e-util/e-util.h> +#include <filter/filter-rule.h> + +#include <addressbook-config.h> + +static void +action_address_book_copy_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + e_addressbook_view_copy_to_folder (view, TRUE); +} + +static void +action_address_book_delete_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EShellView *shell_view; + EShellWindow *shell_window; + EBookShellSidebar *book_shell_sidebar; + ESource *source; + ESourceSelector *selector; + ESourceGroup *source_group; + ESourceList *source_list; + EBook *book; + gint response; + GError *error = NULL; + + shell_view = E_SHELL_VIEW (book_shell_view); + shell_window = e_shell_view_get_shell_window (shell_view); + + book_shell_sidebar = book_shell_view->priv->book_shell_sidebar; + selector = e_book_shell_sidebar_get_selector (book_shell_sidebar); + source = e_source_selector_peek_primary_selection (selector); + g_return_if_fail (source != NULL); + + response = e_error_run ( + GTK_WINDOW (shell_window), + "addressbook:ask-delete-addressbook", + e_source_peek_name (source)); + + if (response != GTK_RESPONSE_YES) + return; + + book = e_book_new (source, &error); + if (error != NULL) { + g_warning ("Error removing addressbook: %s", error->message); + g_error_free (error); + return; + } + + if (!e_book_remove (book, NULL)) { + e_error_run ( + GTK_WINDOW (shell_window), + "addressbook:remove-addressbook", NULL); + g_object_unref (book); + return; + } + + if (e_source_selector_source_is_selected (selector, source)) + e_source_selector_unselect_source (selector, source); + + source_group = e_source_peek_group (source); + e_source_group_remove_source (source_group, source); + + source_list = book_shell_view->priv->source_list; + e_source_list_sync (source_list, NULL); + + g_object_unref (book); +} + +static void +action_address_book_move_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + e_addressbook_view_move_to_folder (view, TRUE); +} + +static void +action_address_book_new_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EShellView *shell_view; + EShellWindow *shell_window; + + shell_view = E_SHELL_VIEW (book_shell_view); + shell_window = e_shell_view_get_shell_window (shell_view); + + addressbook_config_create_new_source (GTK_WIDGET (shell_window)); +} + +static void +action_address_book_properties_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EShellView *shell_view; + EShellWindow *shell_window; + EBookShellSidebar *book_shell_sidebar; + ESource *source; + ESourceSelector *selector; + EditorUidClosure *closure; + GHashTable *uid_to_editor; + const gchar *uid; + + shell_view = E_SHELL_VIEW (book_shell_view); + shell_window = e_shell_view_get_shell_window (shell_view); + + book_shell_sidebar = book_shell_view->priv->book_shell_sidebar; + selector = e_book_shell_sidebar_get_selector (book_shell_sidebar); + source = e_source_selector_peek_primary_selection (selector); + g_return_if_fail (source != NULL); + + uid = e_source_peek_uid (source); + uid_to_editor = book_shell_view->priv->uid_to_editor; + + closure = g_hash_table_lookup (uid_to_editor, uid); + if (closure == NULL) { + GtkWidget *editor; + + editor = addressbook_config_edit_source ( + GTK_WIDGET (shell_window), source); + + closure = g_new (EditorUidClosure, 1); + closure->editor = editor; + closure->uid = g_strdup (uid); + closure->view = book_shell_view; + + g_hash_table_insert (uid_to_editor, closure->uid, closure); + + g_object_weak_ref ( + G_OBJECT (closure->editor), (GWeakNotify) + e_book_shell_view_editor_weak_notify, closure); + } + + gtk_window_present (GTK_WINDOW (closure->editor)); +} + +static void +action_address_book_rename_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellSidebar *book_shell_sidebar; + ESourceSelector *selector; + + book_shell_sidebar = book_shell_view->priv->book_shell_sidebar; + selector = e_book_shell_sidebar_get_selector (book_shell_sidebar); + + e_source_selector_edit_primary_selection (selector); +} + +static void +action_address_book_save_as_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + e_addressbook_view_save_as (view, TRUE); +} + +static void +action_address_book_stop_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + e_addressbook_view_stop (view); +} + +static void +action_contact_clipboard_copy_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + + book_shell_content = book_shell_view->priv->book_shell_content; + e_book_shell_content_clipboard_copy (book_shell_content); +} + +static void +action_contact_clipboard_cut_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + e_addressbook_view_cut (view); +} + +static void +action_contact_clipboard_paste_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + e_addressbook_view_paste (view); +} + +static void +action_contact_copy_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + e_addressbook_view_copy_to_folder (view, FALSE); +} + +static void +action_contact_delete_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + e_addressbook_view_delete_selection (view, TRUE); +} + +static void +action_contact_forward_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + GList *list, *iter; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + list = e_addressbook_view_get_selected (view); + g_return_if_fail (list != NULL); + + /* Convert the list of contacts to a list of destinations. */ + for (iter = list; iter != NULL; iter = iter->next) { + EContact *contact = iter->data; + EDestination *destination; + + destination = e_destination_new (); + e_destination_set_contact (destination, contact, 0); + g_object_unref (contact); + + iter->data = destination; + } + + eab_send_as_attachment (list); + g_list_foreach (list, (GFunc) g_object_unref, NULL); + g_list_free (list); +} + +static void +action_contact_move_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + e_addressbook_view_move_to_folder (view, FALSE); +} + +static void +action_contact_new_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + EAddressbookModel *model; + EContact *contact; + GtkWidget *editor; + EBook *book; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + model = e_addressbook_view_get_model (view); + book = e_addressbook_model_get_book (model); + g_return_if_fail (book != NULL); + + contact = e_contact_new (); + editor = e_contact_editor_new (book, contact, TRUE, TRUE); + eab_editor_show (EAB_EDITOR (editor)); + g_object_unref (contact); +} + +static void +action_contact_new_list_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + EAddressbookModel *model; + EContact *contact; + GtkWidget *editor; + EBook *book; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + model = e_addressbook_view_get_model (view); + book = e_addressbook_model_get_book (model); + g_return_if_fail (book != NULL); + + contact = e_contact_new (); + editor = e_contact_list_editor_new (book, contact, TRUE, TRUE); + eab_editor_show (EAB_EDITOR (editor)); + g_object_unref (contact); +} + +static void +action_contact_open_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + e_addressbook_view_view (view); +} + +static void +action_contact_preview_cb (GtkToggleAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + gboolean visible; + + book_shell_content = book_shell_view->priv->book_shell_content; + visible = gtk_toggle_action_get_active (action); + e_book_shell_content_set_preview_visible (book_shell_content, visible); +} + +static void +action_contact_print_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + GtkPrintOperationAction print_action; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG; + e_addressbook_view_print (view, print_action); +} + +static void +action_contact_print_preview_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + GtkPrintOperationAction print_action; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW; + e_addressbook_view_print (view, print_action); +} + +static void +action_contact_save_as_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + e_addressbook_view_save_as (view, FALSE); +} + +static void +action_contact_select_all_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + e_addressbook_view_select_all (view); +} + +static void +action_contact_send_message_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + GList *list, *iter; + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + g_return_if_fail (view != NULL); + + list = e_addressbook_view_get_selected (view); + g_return_if_fail (list != NULL); + + /* Convert the list of contacts to a list of destinations. */ + for (iter = list; iter != NULL; iter = iter->next) { + EContact *contact = iter->data; + EDestination *destination; + + destination = e_destination_new (); + e_destination_set_contact (destination, contact, 0); + g_object_unref (contact); + + iter->data = destination; + } + + eab_send_as_to (list); + g_list_foreach (list, (GFunc) g_object_unref, NULL); + g_list_free (list); +} + +static void +action_gal_save_custom_view_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EShellView *shell_view; + EAddressbookView *address_view; + GalViewInstance *view_instance; + + /* All shell views respond to the activation of this action, + * which is defined by EShellWindow. But only the currently + * active shell view proceeds with saving the custom view. */ + shell_view = E_SHELL_VIEW (book_shell_view); + if (!e_shell_view_is_active (shell_view)) + return; + + book_shell_content = book_shell_view->priv->book_shell_content; + address_view = e_book_shell_content_get_current_view (book_shell_content); + view_instance = e_addressbook_view_get_view_instance (address_view); + gal_view_instance_save_as (view_instance); +} + +static void +action_search_execute_cb (GtkAction *action, + EBookShellView *book_shell_view) +{ + EShellView *shell_view; + + /* All shell views respond to the activation of this action, + * which is defined by EShellWindow. But only the currently + * active shell view proceeds with executing the search. */ + shell_view = E_SHELL_VIEW (book_shell_view); + if (!e_shell_view_is_active (shell_view)) + return; + + e_book_shell_view_execute_search (book_shell_view); +} + +static void +action_search_filter_cb (GtkRadioAction *action, + GtkRadioAction *current, + EBookShellView *book_shell_view) +{ + e_book_shell_view_execute_search (book_shell_view); +} + +static GtkActionEntry contact_entries[] = { + + { "address-book-copy", + GTK_STOCK_COPY, + N_("Co_py All Contacts To..."), + NULL, + N_("Copy the contacts of the selected address book to another"), + G_CALLBACK (action_address_book_copy_cb) }, + + { "address-book-delete", + GTK_STOCK_DELETE, + N_("Del_ete Address Book"), + NULL, + N_("Delete the selected address book"), + G_CALLBACK (action_address_book_delete_cb) }, + + { "address-book-move", + "folder-move", + N_("Mo_ve All Contacts To..."), + NULL, + N_("Move the contacts of the selected address book to another"), + G_CALLBACK (action_address_book_move_cb) }, + + { "address-book-new", + "address-book-new", + N_("_New Address Book"), + NULL, + N_("Create a new address book"), + G_CALLBACK (action_address_book_new_cb) }, + + { "address-book-properties", + GTK_STOCK_PROPERTIES, + N_("Address _Book Properties"), + NULL, + N_("Show properties of the selected address book"), + G_CALLBACK (action_address_book_properties_cb) }, + + { "address-book-rename", + NULL, + N_("_Rename..."), + "F2", + N_("Rename the selected address book"), + G_CALLBACK (action_address_book_rename_cb) }, + + { "address-book-save-as", + GTK_STOCK_SAVE_AS, + N_("S_ave Address Book as vCard"), + NULL, + N_("Save the contacts of the selected address book as a vCard"), + G_CALLBACK (action_address_book_save_as_cb) }, + + { "address-book-stop", + GTK_STOCK_STOP, + NULL, + NULL, + N_("Stop loading"), + G_CALLBACK (action_address_book_stop_cb) }, + + { "contact-clipboard-copy", + GTK_STOCK_COPY, + NULL, + NULL, + N_("Copy the selection"), + G_CALLBACK (action_contact_clipboard_copy_cb) }, + + { "contact-clipboard-cut", + GTK_STOCK_CUT, + NULL, + NULL, + N_("Cut the selection"), + G_CALLBACK (action_contact_clipboard_cut_cb) }, + + { "contact-clipboard-paste", + GTK_STOCK_PASTE, + NULL, + NULL, + N_("Paste the clipboard"), + G_CALLBACK (action_contact_clipboard_paste_cb) }, + + { "contact-copy", + NULL, + N_("_Copy Contact To..."), + "<Control><Shift>y", + N_("Copy selected contacts to another address book"), + G_CALLBACK (action_contact_copy_cb) }, + + { "contact-delete", + GTK_STOCK_DELETE, + N_("_Delete Contact"), + "<Control>d", + N_("Delete selected contacts"), + G_CALLBACK (action_contact_delete_cb) }, + + { "contact-forward", + "mail-forward", + N_("_Forward Contact..."), + NULL, + N_("Send selected contacts to another person"), + G_CALLBACK (action_contact_forward_cb) }, + + { "contact-move", + NULL, + N_("_Move Contact To..."), + "<Control><Shift>v", + N_("Move selected contacts to another address book"), + G_CALLBACK (action_contact_move_cb) }, + + { "contact-new", + "contact-new", + N_("_New Contact..."), + NULL, + N_("Create a new contact"), + G_CALLBACK (action_contact_new_cb) }, + + { "contact-new-list", + "stock_contact-list", + N_("New Contact _List..."), + NULL, + N_("Create a new contact list"), + G_CALLBACK (action_contact_new_list_cb) }, + + { "contact-open", + NULL, + N_("_Open"), + "<Control>o", + N_("View the current contact"), + G_CALLBACK (action_contact_open_cb) }, + + { "contact-save-as", + GTK_STOCK_SAVE_AS, + N_("Save as vCard..."), + NULL, + N_("Save selected contacts as a vCard"), + G_CALLBACK (action_contact_save_as_cb) }, + + { "contact-select-all", + GTK_STOCK_SELECT_ALL, + NULL, + NULL, + N_("Select all contacts"), + G_CALLBACK (action_contact_select_all_cb) }, + + { "contact-send-message", + "mail-message-new", + N_("_Send Message to Contact..."), + NULL, + N_("Send a message to the selected contacts"), + G_CALLBACK (action_contact_send_message_cb) }, + + /*** Menus ***/ + + { "actions-menu", + NULL, + N_("_Actions"), + NULL, + NULL, + NULL } +}; + +static EPopupActionEntry contact_popup_entries[] = { + + { "address-book-popup-delete", + N_("_Delete"), + "address-book-delete" }, + + { "address-book-popup-properties", + N_("_Properties"), + "address-book-properties" }, + + { "address-book-popup-rename", + NULL, + "address-book-rename" }, + + { "address-book-popup-save-as", + N_("_Save as vCard..."), + "address-book-save-as" }, + + { "contact-popup-clipboard-copy", + NULL, + "contact-clipboard-copy" }, + + { "contact-popup-clipboard-cut", + NULL, + "contact-clipboard-cut" }, + + { "contact-popup-clipboard-paste", + NULL, + "contact-clipboard-paste" }, + + { "contact-popup-copy", + NULL, + "contact-copy" }, + + { "contact-popup-delete", + NULL, + "contact-delete" }, + + { "contact-popup-forward", + NULL, + "contact-forward" }, + + { "contact-popup-move", + NULL, + "contact-move" }, + + { "contact-popup-open", + NULL, + "contact-open" }, + + { "contact-popup-save-as", + NULL, + "contact-save-as" }, + + { "contact-popup-send-message", + NULL, + "contact-send-message" }, +}; + +static GtkToggleActionEntry contact_toggle_entries[] = { + + { "contact-preview", + NULL, + N_("Contact _Preview"), + "<Control>m", + N_("Show contact preview window"), + G_CALLBACK (action_contact_preview_cb), + TRUE } +}; + +static GtkRadioActionEntry contact_filter_entries[] = { + + { "contact-filter-any-category", + NULL, + N_("Any Category"), + NULL, + NULL, + CONTACT_FILTER_ANY_CATEGORY }, + + { "contact-filter-unmatched", + NULL, + N_("Unmatched"), + NULL, + NULL, + CONTACT_FILTER_UNMATCHED } +}; + +static GtkRadioActionEntry contact_search_entries[] = { + + { "contact-search-any-field-contains", + NULL, + N_("Any field contains"), + NULL, + NULL, /* XXX Add a tooltip! */ + CONTACT_SEARCH_ANY_FIELD_CONTAINS }, + + { "contact-search-email-begins-with", + NULL, + N_("Email begins with"), + NULL, + NULL, /* XXX Add a tooltip! */ + CONTACT_SEARCH_EMAIL_BEGINS_WITH }, + + { "contact-search-name-contains", + NULL, + N_("Name contains"), + NULL, + NULL, /* XXX Add a tooltip! */ + CONTACT_SEARCH_NAME_CONTAINS } +}; + +static GtkActionEntry lockdown_printing_entries[] = { + + { "contact-print", + GTK_STOCK_PRINT, + NULL, + "<Control>p", + N_("Print selected contacts"), + G_CALLBACK (action_contact_print_cb) }, + + { "contact-print-preview", + GTK_STOCK_PRINT_PREVIEW, + NULL, + NULL, + N_("Preview the contacts to be printed"), + G_CALLBACK (action_contact_print_preview_cb) } +}; + +static EPopupActionEntry lockdown_printing_popup_entries[] = { + + { "contact-popup-print", + NULL, + "contact-print" } +}; + +void +e_book_shell_view_actions_init (EBookShellView *book_shell_view) +{ + EShellView *shell_view; + EShellWindow *shell_window; + GtkActionGroup *action_group; + GConfBridge *bridge; + GtkAction *action; + GObject *object; + const gchar *key; + + shell_view = E_SHELL_VIEW (book_shell_view); + shell_window = e_shell_view_get_shell_window (shell_view); + + /* Contact Actions */ + action_group = ACTION_GROUP (CONTACTS); + gtk_action_group_add_actions ( + action_group, contact_entries, + G_N_ELEMENTS (contact_entries), book_shell_view); + e_action_group_add_popup_actions ( + action_group, contact_popup_entries, + G_N_ELEMENTS (contact_popup_entries)); + gtk_action_group_add_toggle_actions ( + action_group, contact_toggle_entries, + G_N_ELEMENTS (contact_toggle_entries), book_shell_view); + gtk_action_group_add_radio_actions ( + action_group, contact_search_entries, + G_N_ELEMENTS (contact_search_entries), + CONTACT_SEARCH_NAME_CONTAINS, + NULL, NULL); + + /* Lockdown Printing Actions */ + action_group = ACTION_GROUP (LOCKDOWN_PRINTING); + gtk_action_group_add_actions ( + action_group, lockdown_printing_entries, + G_N_ELEMENTS (lockdown_printing_entries), book_shell_view); + e_action_group_add_popup_actions ( + action_group, lockdown_printing_popup_entries, + G_N_ELEMENTS (lockdown_printing_popup_entries)); + + /* Bind GObject properties to GConf keys. */ + + bridge = gconf_bridge_get (); + + object = G_OBJECT (ACTION (CONTACT_PREVIEW)); + key = "/apps/evolution/addressbook/display/show_preview"; + gconf_bridge_bind_property (bridge, key, object, "active"); + + /* Fine tuning. */ + + action = ACTION (CONTACT_DELETE); + g_object_set (action, "short-label", _("Delete"), NULL); + + g_signal_connect ( + ACTION (GAL_SAVE_CUSTOM_VIEW), "activate", + G_CALLBACK (action_gal_save_custom_view_cb), book_shell_view); + + g_signal_connect ( + ACTION (SEARCH_EXECUTE), "activate", + G_CALLBACK (action_search_execute_cb), book_shell_view); +} + +void +e_book_shell_view_update_search_filter (EBookShellView *book_shell_view) +{ + EShellView *shell_view; + EShellContent *shell_content; + EShellWindow *shell_window; + GtkActionGroup *action_group; + GtkRadioAction *radio_action; + GList *list, *iter; + GSList *group; + gint ii; + + shell_view = E_SHELL_VIEW (book_shell_view); + shell_content = e_shell_view_get_shell_content (shell_view); + shell_window = e_shell_view_get_shell_window (shell_view); + + action_group = ACTION_GROUP (CONTACTS_FILTER); + e_action_group_remove_all_actions (action_group); + + /* Add the standard filter actions. */ + gtk_action_group_add_radio_actions ( + action_group, contact_filter_entries, + G_N_ELEMENTS (contact_filter_entries), + CONTACT_FILTER_ANY_CATEGORY, + G_CALLBACK (action_search_filter_cb), + book_shell_view); + + /* Retrieve the radio group from an action we just added. */ + list = gtk_action_group_list_actions (action_group); + radio_action = GTK_RADIO_ACTION (list->data); + group = gtk_radio_action_get_group (radio_action); + g_list_free (list); + + /* Build the category actions. */ + + list = e_categories_get_list (); + for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) { + const gchar *category_name = iter->data; + const gchar *filename; + GtkAction *action; + gchar *action_name; + + action_name = g_strdup_printf ( + "contact-filter-category-%d", ii); + radio_action = gtk_radio_action_new ( + action_name, category_name, NULL, NULL, ii); + g_free (action_name); + + /* Convert the category icon file to a themed icon name. */ + filename = e_categories_get_icon_file_for (category_name); + if (filename != NULL && *filename != '\0') { + gchar *basename; + gchar *cp; + + basename = g_path_get_basename (filename); + + /* Lose the file extension. */ + if ((cp = strrchr (basename, '.')) != NULL) + *cp = '\0'; + + g_object_set ( + radio_action, "icon-name", basename, NULL); + + g_free (basename); + } + + gtk_radio_action_set_group (radio_action, group); + group = gtk_radio_action_get_group (radio_action); + + /* The action group takes ownership of the action. */ + action = GTK_ACTION (radio_action); + gtk_action_group_add_action (action_group, action); + g_object_unref (radio_action); + } + g_list_free (list); + + /* Use any action in the group; doesn't matter which. */ + e_shell_content_set_filter_action (shell_content, radio_action); + + ii = CONTACT_FILTER_UNMATCHED; + e_shell_content_add_filter_separator_after (shell_content, ii); +} diff --git a/addressbook/gui/component/e-book-shell-view-actions.h b/addressbook/gui/component/e-book-shell-view-actions.h new file mode 100644 index 0000000000..503855dda6 --- /dev/null +++ b/addressbook/gui/component/e-book-shell-view-actions.h @@ -0,0 +1,91 @@ +/* + * e-book-shell-view-actions.h + * + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_BOOK_SHELL_VIEW_ACTIONS_H +#define E_BOOK_SHELL_VIEW_ACTIONS_H + +#include <shell/e-shell-window-actions.h> + +/* Address Book Actions */ +#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_COPY(window) \ + E_SHELL_WINDOW_ACTION ((window), "address-book-copy") +#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_DELETE(window) \ + E_SHELL_WINDOW_ACTION ((window), "address-book-delete") +#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_MOVE(window) \ + E_SHELL_WINDOW_ACTION ((window), "address-book-move") +#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_PROPERTIES(window) \ + E_SHELL_WINDOW_ACTION ((window), "address-book-properties") +#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_RENAME(window) \ + E_SHELL_WINDOW_ACTION ((window), "address-book-rename") +#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_SAVE_AS(window) \ + E_SHELL_WINDOW_ACTION ((window), "address-book-save-as") +#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_STOP(window) \ + E_SHELL_WINDOW_ACTION ((window), "address-book-stop") + +/* Contact Actions */ +#define E_SHELL_WINDOW_ACTION_CONTACT_CLIPBOARD_COPY(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-clipboard-copy") +#define E_SHELL_WINDOW_ACTION_CONTACT_CLIPBOARD_CUT(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-clipboard-cut") +#define E_SHELL_WINDOW_ACTION_CONTACT_CLIPBOARD_PASTE(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-clipboard-paste") +#define E_SHELL_WINDOW_ACTION_CONTACT_COPY(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-copy") +#define E_SHELL_WINDOW_ACTION_CONTACT_DELETE(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-delete") +#define E_SHELL_WINDOW_ACTION_CONTACT_FORWARD(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-forward") +#define E_SHELL_WINDOW_ACTION_CONTACT_MOVE(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-move") +#define E_SHELL_WINDOW_ACTION_CONTACT_NEW(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-new") +#define E_SHELL_WINDOW_ACTION_CONTACT_NEW_LIST(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-new-list") +#define E_SHELL_WINDOW_ACTION_CONTACT_OPEN(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-open") +#define E_SHELL_WINDOW_ACTION_CONTACT_PREVIEW(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-preview") +#define E_SHELL_WINDOW_ACTION_CONTACT_PRINT(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-print") +#define E_SHELL_WINDOW_ACTION_CONTACT_PRINT_PREVIEW(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-print-preview") +#define E_SHELL_WINDOW_ACTION_CONTACT_SAVE_AS(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-save-as") +#define E_SHELL_WINDOW_ACTION_CONTACT_SELECT_ALL(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-select-all") +#define E_SHELL_WINDOW_ACTION_CONTACT_SEND_MESSAGE(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-send-message") + +/* Search Actions */ +#define E_SHELL_WINDOW_ACTION_CONTACT_SEARCH_ANY_FIELD_CONTAINS(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-search-any-field-contains") +#define E_SHELL_WINDOW_ACTION_CONTACT_SEARCH_EMAIL_BEGINS_WITH(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-search-email-begins-with") +#define E_SHELL_WINDOW_ACTION_CONTACT_SEARCH_NAME_CONTAINS(window) \ + E_SHELL_WINDOW_ACTION ((window), "contact-search-name-contains") + +/* Action Groups */ +#define E_SHELL_WINDOW_ACTION_GROUP_CONTACTS(window) \ + E_SHELL_WINDOW_ACTION_GROUP ((window), "contacts") +#define E_SHELL_WINDOW_ACTION_GROUP_CONTACTS_FILTER(window) \ + E_SHELL_WINDOW_ACTION_GROUP ((window), "contacts-filter") + +#endif /* E_BOOK_SHELL_VIEW_ACTIONS_H */ diff --git a/addressbook/gui/component/e-book-shell-view-private.c b/addressbook/gui/component/e-book-shell-view-private.c new file mode 100644 index 0000000000..33fe07291d --- /dev/null +++ b/addressbook/gui/component/e-book-shell-view-private.c @@ -0,0 +1,626 @@ +/* + * e-book-shell-view-private.c + * + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-book-shell-view-private.h" + +#include <gal-view-factory-etable.h> +#include <gal-view-factory-minicard.h> + +#include <addressbook.h> + +static void +open_contact (EBookShellView *book_shell_view, + EContact *contact, + gboolean is_new_contact, + EAddressbookView *view) +{ + EAddressbookModel *model; + GtkWidget *editor; + EBook *book; + gboolean editable; + + model = e_addressbook_view_get_model (view); + book = e_addressbook_model_get_book (model); + editable = e_addressbook_model_get_editable (model); + + if (e_contact_get (contact, E_CONTACT_IS_LIST)) + editor = e_contact_list_editor_new ( + book, contact, is_new_contact, editable); + else + editor = e_contact_editor_new ( + book, contact, is_new_contact, editable); + + eab_editor_show (EAB_EDITOR (editor)); +} + +static void +popup_event (EBookShellView *book_shell_view, + GdkEventButton *event) +{ + EShellView *shell_view; + const gchar *widget_path; + + widget_path = "/contact-popup"; + shell_view = E_SHELL_VIEW (book_shell_view); + + e_shell_view_show_popup_menu (shell_view, widget_path, event); +} + +static void +book_shell_view_selection_change_foreach (gint row, + EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *view; + EAddressbookModel *model; + EContact *contact; + + /* XXX A "foreach" function is kind of a silly way to retrieve + * the one and only selected contact, but this is the only + * means that ESelectionModel provides. */ + + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + model = e_addressbook_view_get_model (view); + contact = e_addressbook_model_get_contact (model, row); + + e_book_shell_content_set_preview_contact (book_shell_content, contact); +} + +static void +selection_change (EBookShellView *book_shell_view, + EAddressbookView *view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *current_view; + ESelectionModel *selection_model; + EShellView *shell_view; + gint n_selected; + + shell_view = E_SHELL_VIEW (book_shell_view); + book_shell_content = book_shell_view->priv->book_shell_content; + current_view = e_book_shell_content_get_current_view (book_shell_content); + + if (view != current_view) + return; + + e_shell_view_update_actions (shell_view); + + selection_model = e_addressbook_view_get_selection_model (view); + + n_selected = (selection_model != NULL) ? + e_selection_model_selected_count (selection_model) : 0; + + if (n_selected == 1) + e_selection_model_foreach ( + selection_model, (EForeachFunc) + book_shell_view_selection_change_foreach, + book_shell_view); + else + e_book_shell_content_set_preview_contact ( + book_shell_content, NULL); +} + +static void +contact_changed (EBookShellView *book_shell_view, + EContact *contact) +{ + EBookShellContent *book_shell_content; + EContact *preview_contact; + + book_shell_content = book_shell_view->priv->book_shell_content; + + preview_contact = + e_book_shell_content_get_preview_contact (book_shell_content); + + if (contact != preview_contact) + return; + + /* Re-render the same contact. */ + e_book_shell_content_set_preview_contact (book_shell_content, contact); +} + +static void +contacts_removed (EBookShellView *book_shell_view, + GArray *removed_indices, + EAddressbookModel *model) +{ + EBookShellContent *book_shell_content; + EContact *preview_contact; + + book_shell_content = book_shell_view->priv->book_shell_content; + + preview_contact = + e_book_shell_content_get_preview_contact (book_shell_content); + + if (preview_contact == NULL) + return; + + /* Is the displayed contact still in the model? */ + if (e_addressbook_model_find (model, preview_contact) < 0) + return; + + /* If not, clear the contact display. */ + e_book_shell_content_set_preview_contact (book_shell_content, NULL); +} + +static void +book_open_cb (EBook *book, + EBookStatus status, + gpointer user_data) +{ + EAddressbookView *view = user_data; + EAddressbookModel *model; + ESource *source; + + source = e_book_get_source (book); + model = e_addressbook_view_get_model (view); + + if (status == E_BOOK_ERROR_OK) { + e_addressbook_model_set_book (model, book); + e_addressbook_model_force_folder_bar_message (model); + } else if (status != E_BOOK_ERROR_CANCELLED) + eab_load_error_dialog (NULL /* XXX */, source, status); +} + +static void +book_shell_view_activate_selected_source (EBookShellView *book_shell_view, + ESourceSelector *selector) +{ + EShellView *shell_view; + EBookShellContent *book_shell_content; + EAddressbookView *view; + EAddressbookModel *model; + ESource *source; + GalViewInstance *view_instance; + GHashTable *hash_table; + GtkWidget *widget; + const gchar *uid; + gchar *view_id; + + shell_view = E_SHELL_VIEW (book_shell_view); + book_shell_content = book_shell_view->priv->book_shell_content; + source = e_source_selector_peek_primary_selection (selector); + + if (source == NULL) + return; + + uid = e_source_peek_uid (source); + hash_table = book_shell_view->priv->uid_to_view; + widget = g_hash_table_lookup (hash_table, uid); + + if (widget != NULL) { + EBook *book; + + /* There is a view for this UID. Make sure the view + * actually contains an EBook. The absence of an EBook + * suggests a previous load failed, so try again. */ + view = E_ADDRESSBOOK_VIEW (widget); + model = e_addressbook_view_get_model (view); + source = e_addressbook_view_get_source (view); + + if (e_addressbook_model_get_book (model) == NULL) { + book = e_book_new (source, NULL); + + if (book != NULL) + addressbook_load (book, book_open_cb, view); + } + + } else { + EBook *book; + + /* Create a view for this UID. */ + widget = e_addressbook_view_new (shell_view, source); + gtk_widget_show (widget); + + e_book_shell_content_insert_view ( + book_shell_content, + E_ADDRESSBOOK_VIEW (widget)); + + g_hash_table_insert ( + hash_table, g_strdup (uid), + g_object_ref (widget)); + + g_signal_connect_swapped ( + widget, "open-contact", + G_CALLBACK (open_contact), book_shell_view); + + g_signal_connect_swapped ( + widget, "popup-event", + G_CALLBACK (popup_event), book_shell_view); + + g_signal_connect_swapped ( + widget, "command-state-change", + G_CALLBACK (e_shell_view_update_actions), + book_shell_view); + + g_signal_connect_swapped ( + widget, "selection-change", + G_CALLBACK (selection_change), book_shell_view); + + book = e_book_new (source, NULL); + view = E_ADDRESSBOOK_VIEW (widget); + + if (book != NULL) + addressbook_load (book, book_open_cb, view); + + model = e_addressbook_view_get_model (view); + + g_signal_connect_swapped ( + model, "contact-changed", + G_CALLBACK (contact_changed), book_shell_view); + + g_signal_connect_swapped ( + model, "contacts-removed", + G_CALLBACK (contacts_removed), book_shell_view); + } + + e_book_shell_content_set_current_view ( + book_shell_content, E_ADDRESSBOOK_VIEW (widget)); + + /* XXX We have to keep the addressbook selector informed of the + * current view so it can move contacts via drag-and-drop. */ + e_addressbook_selector_set_current_view ( + E_ADDRESSBOOK_SELECTOR (selector), + E_ADDRESSBOOK_VIEW (widget)); + + view_instance = e_addressbook_view_get_view_instance (view); + view_id = gal_view_instance_get_current_view_id (view_instance); + e_shell_view_set_view_id (shell_view, view_id); + g_free (view_id); + + e_addressbook_model_force_folder_bar_message (model); + selection_change (book_shell_view, view); +} + +static gboolean +book_shell_view_show_popup_menu (GdkEventButton *event, + EShellView *shell_view) +{ + const gchar *widget_path; + + widget_path = "/address-book-popup"; + e_shell_view_show_popup_menu (shell_view, widget_path, event); + + return TRUE; +} + +static gboolean +book_shell_view_selector_button_press_event_cb (EShellView *shell_view, + GdkEventButton *event) +{ + /* XXX Use ESourceSelector's "popup-event" signal instead. */ + + if (event->button == 3 && event->type == GDK_BUTTON_PRESS) + return book_shell_view_show_popup_menu (event, shell_view); + + return FALSE; +} + +static gboolean +book_shell_view_selector_popup_menu_cb (EShellView *shell_view) +{ + /* XXX Use ESourceSelector's "popup-event" signal instead. */ + + return book_shell_view_show_popup_menu (NULL, shell_view); +} + +static gboolean +book_shell_view_selector_key_press_event_cb (EShellView *shell_view, + GdkEventKey *event) +{ + EShellWindow *shell_window; + + /* Needed for the ACTION() macro. */ + shell_window = e_shell_view_get_shell_window (shell_view); + + if (event->keyval == GDK_Delete) { + gtk_action_activate (ACTION (ADDRESS_BOOK_DELETE)); + return TRUE; + } + + return FALSE; +} + +static void +book_shell_view_load_view_collection (EShellViewClass *shell_view_class) +{ + GalViewCollection *collection; + GalViewFactory *factory; + ETableSpecification *spec; + const gchar *base_dir; + gchar *filename; + + collection = shell_view_class->view_collection; + + base_dir = EVOLUTION_ETSPECDIR; + spec = e_table_specification_new (); + filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL); + if (!e_table_specification_load_from_file (spec, filename)) + g_critical ("Unable to load ETable specification file " + "for address book"); + g_free (filename); + + factory = gal_view_factory_etable_new (spec); + gal_view_collection_add_factory (collection, factory); + g_object_unref (factory); + g_object_unref (spec); + + factory = gal_view_factory_minicard_new (); + gal_view_collection_add_factory (collection, factory); + g_object_unref (factory); + + gal_view_collection_load (collection); +} + +static void +book_shell_view_notify_view_id_cb (EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EAddressbookView *address_view; + GalViewInstance *view_instance; + const gchar *view_id; + + book_shell_content = book_shell_view->priv->book_shell_content; + address_view = e_book_shell_content_get_current_view (book_shell_content); + view_instance = e_addressbook_view_get_view_instance (address_view); + view_id = e_shell_view_get_view_id (E_SHELL_VIEW (book_shell_view)); + + /* A NULL view ID implies we're in a custom view. But you can + * only get to a custom view via the "Define Views" dialog, which + * would have already modified the view instance appropriately. + * Furthermore, there's no way to refer to a custom view by ID + * anyway, since custom views have no IDs. */ + if (view_id == NULL) + return; + + gal_view_instance_set_current_view_id (view_instance, view_id); +} + +void +e_book_shell_view_private_init (EBookShellView *book_shell_view, + EShellViewClass *shell_view_class) +{ + EBookShellViewPrivate *priv = book_shell_view->priv; + ESourceList *source_list; + GHashTable *uid_to_view; + GHashTable *uid_to_editor; + GObject *object; + + object = G_OBJECT (shell_view_class->type_module); + source_list = g_object_get_data (object, "source-list"); + g_return_if_fail (E_IS_SOURCE_LIST (source_list)); + + uid_to_view = g_hash_table_new_full ( + g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); + + uid_to_editor = g_hash_table_new_full ( + g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_free); + + priv->source_list = g_object_ref (source_list); + priv->uid_to_view = uid_to_view; + priv->uid_to_editor = uid_to_editor; + + if (!gal_view_collection_loaded (shell_view_class->view_collection)) + book_shell_view_load_view_collection (shell_view_class); + + g_signal_connect ( + book_shell_view, "notify::view-id", + G_CALLBACK (book_shell_view_notify_view_id_cb), NULL); +} + +void +e_book_shell_view_private_constructed (EBookShellView *book_shell_view) +{ + EBookShellViewPrivate *priv = book_shell_view->priv; + EShellContent *shell_content; + EShellSidebar *shell_sidebar; + EShellView *shell_view; + EShellWindow *shell_window; + ESourceSelector *selector; + + shell_view = E_SHELL_VIEW (book_shell_view); + shell_content = e_shell_view_get_shell_content (shell_view); + shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); + shell_window = e_shell_view_get_shell_window (shell_view); + + e_shell_window_add_action_group (shell_window, "contacts"); + e_shell_window_add_action_group (shell_window, "contacts-filter"); + + /* Cache these to avoid lots of awkward casting. */ + priv->book_shell_content = g_object_ref (shell_content); + priv->book_shell_sidebar = g_object_ref (shell_sidebar); + + selector = e_book_shell_sidebar_get_selector ( + E_BOOK_SHELL_SIDEBAR (shell_sidebar)); + + g_signal_connect_swapped ( + selector, "button-press-event", + G_CALLBACK (book_shell_view_selector_button_press_event_cb), + book_shell_view); + + g_signal_connect_swapped ( + selector, "key-press-event", + G_CALLBACK (book_shell_view_selector_key_press_event_cb), + book_shell_view); + + g_signal_connect_swapped ( + selector, "popup-menu", + G_CALLBACK (book_shell_view_selector_popup_menu_cb), + book_shell_view); + + g_signal_connect_swapped ( + selector, "primary-selection-changed", + G_CALLBACK (book_shell_view_activate_selected_source), + book_shell_view); + + e_categories_register_change_listener ( + G_CALLBACK (e_book_shell_view_update_search_filter), + book_shell_view); + + e_book_shell_view_actions_init (book_shell_view); + book_shell_view_activate_selected_source (book_shell_view, selector); + e_book_shell_view_update_search_filter (book_shell_view); +} + +void +e_book_shell_view_private_dispose (EBookShellView *book_shell_view) +{ + EBookShellViewPrivate *priv = book_shell_view->priv; + + DISPOSE (priv->source_list); + + DISPOSE (priv->book_shell_content); + DISPOSE (priv->book_shell_sidebar); + + g_hash_table_remove_all (priv->uid_to_view); + g_hash_table_remove_all (priv->uid_to_editor); +} + +void +e_book_shell_view_private_finalize (EBookShellView *book_shell_view) +{ + EBookShellViewPrivate *priv = book_shell_view->priv; + + g_hash_table_destroy (priv->uid_to_view); + g_hash_table_destroy (priv->uid_to_editor); +} + +void +e_book_shell_view_execute_search (EBookShellView *book_shell_view) +{ + EBookShellContent *book_shell_content; + EShellView *shell_view; + EShellWindow *shell_window; + EShellContent *shell_content; + GtkAction *action; + GString *string; + EAddressbookView *view; + EAddressbookModel *model; + FilterRule *rule; + const gchar *format; + const gchar *text; + gchar *query; + gchar *temp; + gint value; + + shell_view = E_SHELL_VIEW (book_shell_view); + if (!e_shell_view_is_active (shell_view)) + return; + + shell_content = e_shell_view_get_shell_content (shell_view); + text = e_shell_content_get_search_text (shell_content); + + shell_window = e_shell_view_get_shell_window (shell_view); + action = ACTION (CONTACT_SEARCH_ANY_FIELD_CONTAINS); + value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action)); + + if (text == NULL || *text == '\0') { + text = ""; + value = CONTACT_SEARCH_ANY_FIELD_CONTAINS; + } + + switch (value) { + case CONTACT_SEARCH_NAME_CONTAINS: + format = "(contains \"full_name\" %s)"; + break; + + case CONTACT_SEARCH_EMAIL_BEGINS_WITH: + format = "(beginswith \"email\" %s)"; + break; + + default: + text = ""; + /* fall through */ + + case CONTACT_SEARCH_ANY_FIELD_CONTAINS: + format = "(contains \"x-evolution-any-field\" %s)"; + break; + } + + /* Build the query. */ + string = g_string_new (""); + e_sexp_encode_string (string, text); + query = g_strdup_printf (format, string->str); + g_string_free (string, TRUE); + + /* Apply selected filter. */ + value = e_shell_content_get_filter_value (shell_content); + switch (value) { + case CONTACT_FILTER_ANY_CATEGORY: + break; + + case CONTACT_FILTER_UNMATCHED: + temp = g_strdup_printf ( + "(and (not (and (exists \"CATEGORIES\") " + "(not (is \"CATEGORIES\" \"\")))) %s)", + query); + g_free (query); + query = temp; + break; + + default: + { + GList *categories; + const gchar *category_name; + + categories = e_categories_get_list (); + category_name = g_list_nth_data (categories, value); + g_list_free (categories); + + temp = g_strdup_printf ( + "(and (is \"category_list\" \"%s\") %s)", + category_name, query); + g_free (query); + query = temp; + } + } + + /* XXX This is wrong. We need to programmatically construct a + * FilterRule, tell it to build code, and pass the resulting + * expression string to EAddressbookModel. */ + rule = filter_rule_new (); + e_shell_content_set_search_rule (shell_content, rule); + g_object_unref (rule); + + /* Submit the query. */ + book_shell_content = book_shell_view->priv->book_shell_content; + view = e_book_shell_content_get_current_view (book_shell_content); + model = e_addressbook_view_get_model (view); + e_addressbook_model_set_query (model, query); + g_free (query); + + e_book_shell_content_set_preview_contact (book_shell_content, NULL); +} + +void +e_book_shell_view_editor_weak_notify (EditorUidClosure *closure, + GObject *where_the_object_was) +{ + GHashTable *hash_table; + + hash_table = closure->view->priv->uid_to_editor; + g_hash_table_remove (hash_table, closure->uid); +} diff --git a/addressbook/gui/component/e-book-shell-view-private.h b/addressbook/gui/component/e-book-shell-view-private.h new file mode 100644 index 0000000000..6f0d0af147 --- /dev/null +++ b/addressbook/gui/component/e-book-shell-view-private.h @@ -0,0 +1,133 @@ +/* + * e-book-shell-view-private.h + * + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_BOOK_SHELL_VIEW_PRIVATE_H +#define E_BOOK_SHELL_VIEW_PRIVATE_H + +#include "e-book-shell-view.h" + +#include <string.h> +#include <glib/gi18n.h> +#include <gdk/gdkkeysyms.h> +#include <libebook/e-book.h> +#include <libedataserver/e-categories.h> +#include <libedataserver/e-sexp.h> +#include <libedataserverui/e-source-selector.h> + +#include "e-util/gconf-bridge.h" +#include "shell/e-shell-content.h" +#include "shell/e-shell-sidebar.h" +#include "widgets/misc/e-popup-action.h" + +#include "addressbook/gui/contact-editor/e-contact-editor.h" +#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h" +#include "addressbook/gui/widgets/eab-gui-util.h" +#include "addressbook/gui/widgets/e-addressbook-view.h" +#include "addressbook/gui/widgets/e-addressbook-selector.h" + +#include <e-book-shell-content.h> +#include <e-book-shell-sidebar.h> +#include <e-book-shell-view-actions.h> + +#define E_BOOK_SHELL_VIEW_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_BOOK_SHELL_VIEW, EBookShellViewPrivate)) + +/* Shorthand, requires a variable named "shell_window". */ +#define ACTION(name) \ + (E_SHELL_WINDOW_ACTION_##name (shell_window)) +#define ACTION_GROUP(name) \ + (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window)) + +/* For use in dispose() methods. */ +#define DISPOSE(obj) \ + G_STMT_START { \ + if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \ + } G_STMT_END + +/* ETable Specifications */ +#define ETSPEC_FILENAME "e-addressbook-view.etspec" + +G_BEGIN_DECLS + +typedef struct _EditorUidClosure EditorUidClosure; + +struct _EditorUidClosure { + GtkWidget *editor; + gchar *uid; + EBookShellView *view; +}; + +/* List these in the order to be displayed. + * Positive values are reserved for categories. */ +enum { + CONTACT_FILTER_ANY_CATEGORY = -2, + CONTACT_FILTER_UNMATCHED = -1 +}; + +/* List these in the order to be displayed. */ +enum { + CONTACT_SEARCH_NAME_CONTAINS, + CONTACT_SEARCH_EMAIL_BEGINS_WITH, + CONTACT_SEARCH_ANY_FIELD_CONTAINS +}; + +struct _EBookShellViewPrivate { + + /*** Module Data ***/ + + ESourceList *source_list; + + /*** Other Stuff ***/ + + /* These are just for convenience. */ + EBookShellContent *book_shell_content; + EBookShellSidebar *book_shell_sidebar; + + GHashTable *uid_to_view; + GHashTable *uid_to_editor; +}; + +void e_book_shell_view_private_init + (EBookShellView *book_shell_view, + EShellViewClass *shell_view_class); +void e_book_shell_view_private_constructed + (EBookShellView *book_shell_view); +void e_book_shell_view_private_dispose + (EBookShellView *book_shell_view); +void e_book_shell_view_private_finalize + (EBookShellView *book_shell_view); + +/* Private Utilities */ + +void e_book_shell_view_actions_init + (EBookShellView *book_shell_view); +void e_book_shell_view_execute_search + (EBookShellView *book_shell_view); +void e_book_shell_view_editor_weak_notify + (EditorUidClosure *closure, + GObject *where_the_object_was); +void e_book_shell_view_update_search_filter + (EBookShellView *book_shell_view); + +G_END_DECLS + +#endif /* E_BOOK_SHELL_VIEW_PRIVATE_H */ diff --git a/addressbook/gui/component/e-book-shell-view.c b/addressbook/gui/component/e-book-shell-view.c new file mode 100644 index 0000000000..6244384390 --- /dev/null +++ b/addressbook/gui/component/e-book-shell-view.c @@ -0,0 +1,355 @@ +/* + * e-book-shell-view.c + * + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-book-shell-view-private.h" + +enum { + PROP_0, + PROP_SOURCE_LIST +}; + +GType e_book_shell_view_type = 0; +static gpointer parent_class; + +static void +book_shell_view_source_list_changed_cb (EBookShellView *book_shell_view, + ESourceList *source_list) +{ + EBookShellViewPrivate *priv = book_shell_view->priv; + EBookShellContent *book_shell_content; + EShellView *shell_view; + GList *keys, *iter; + + shell_view = E_SHELL_VIEW (book_shell_view); + book_shell_content = book_shell_view->priv->book_shell_content; + + keys = g_hash_table_get_keys (priv->uid_to_view); + for (iter = keys; iter != NULL; iter = iter->next) { + gchar *uid = iter->data; + EAddressbookView *view; + + /* If the source still exists, move on. */ + if (e_source_list_peek_source_by_uid (source_list, uid)) + continue; + + /* Remove the view for the deleted source. */ + view = g_hash_table_lookup (priv->uid_to_view, uid); + e_book_shell_content_remove_view (book_shell_content, view); + g_hash_table_remove (priv->uid_to_view, uid); + } + g_list_free (keys); + + keys = g_hash_table_get_keys (priv->uid_to_editor); + for (iter = keys; iter != NULL; iter = iter->next) { + gchar *uid = iter->data; + EditorUidClosure *closure; + + /* If the source still exists, move on. */ + if (e_source_list_peek_source_by_uid (source_list, uid)) + continue; + + /* Remove the editor for the deleted source. */ + closure = g_hash_table_lookup (priv->uid_to_editor, uid); + g_object_weak_unref ( + G_OBJECT (closure->editor), (GWeakNotify) + e_book_shell_view_editor_weak_notify, closure); + gtk_widget_destroy (closure->editor); + g_hash_table_remove (priv->uid_to_editor, uid); + } + g_list_free (keys); + + e_shell_view_update_actions (shell_view); +} + +static void +book_shell_view_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SOURCE_LIST: + g_value_set_object ( + value, e_book_shell_view_get_source_list ( + E_BOOK_SHELL_VIEW (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +book_shell_view_dispose (GObject *object) +{ + EBookShellView *book_shell_view; + + book_shell_view = E_BOOK_SHELL_VIEW (object); + e_book_shell_view_private_dispose (book_shell_view); + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +book_shell_view_finalize (GObject *object) +{ + EBookShellView *book_shell_view; + + book_shell_view = E_BOOK_SHELL_VIEW (object); + e_book_shell_view_private_finalize (book_shell_view); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +book_shell_view_constructed (GObject *object) +{ + EBookShellView *book_shell_view; + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (parent_class)->constructed (object); + + book_shell_view = E_BOOK_SHELL_VIEW (object); + e_book_shell_view_private_constructed (book_shell_view); +} + +static void +book_shell_view_update_actions (EShellView *shell_view) +{ + EBookShellViewPrivate *priv; + EShellContent *shell_content; + EShellSidebar *shell_sidebar; + EShellWindow *shell_window; + GtkAction *action; + const gchar *label; + gboolean sensitive; + guint32 state; + + /* Be descriptive. */ + gboolean any_contacts_selected; + gboolean has_primary_source; + gboolean multiple_contacts_selected; + gboolean primary_source_is_system; + gboolean single_contact_selected; + gboolean selection_is_contact_list; + gboolean selection_has_email; + gboolean source_is_busy; + gboolean source_is_editable; + gboolean source_is_empty; + + priv = E_BOOK_SHELL_VIEW_GET_PRIVATE (shell_view); + + shell_window = e_shell_view_get_shell_window (shell_view); + + shell_content = e_shell_view_get_shell_content (shell_view); + state = e_shell_content_check_state (shell_content); + + single_contact_selected = + (state & E_BOOK_SHELL_CONTENT_SELECTION_SINGLE); + multiple_contacts_selected = + (state & E_BOOK_SHELL_CONTENT_SELECTION_MULTIPLE); + selection_has_email = + (state & E_BOOK_SHELL_CONTENT_SELECTION_HAS_EMAIL); + selection_is_contact_list = + (state & E_BOOK_SHELL_CONTENT_SELECTION_IS_CONTACT_LIST); + source_is_busy = + (state & E_BOOK_SHELL_CONTENT_SOURCE_IS_BUSY); + source_is_editable = + (state & E_BOOK_SHELL_CONTENT_SOURCE_IS_EDITABLE); + source_is_empty = + (state & E_BOOK_SHELL_CONTENT_SOURCE_IS_EMPTY); + + shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); + state = e_shell_sidebar_check_state (shell_sidebar); + + has_primary_source = + (state & E_BOOK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE); + primary_source_is_system = + (state & E_BOOK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM); + + any_contacts_selected = + (single_contact_selected || multiple_contacts_selected); + + action = ACTION (ADDRESS_BOOK_DELETE); + sensitive = has_primary_source && !primary_source_is_system; + gtk_action_set_sensitive (action, sensitive); + + action = ACTION (ADDRESS_BOOK_RENAME); + sensitive = has_primary_source; + gtk_action_set_sensitive (action, sensitive); + + action = ACTION (ADDRESS_BOOK_STOP); + sensitive = source_is_busy; + gtk_action_set_sensitive (action, sensitive); + + action = ACTION (CONTACT_CLIPBOARD_COPY); + sensitive = any_contacts_selected; + gtk_action_set_sensitive (action, sensitive); + + action = ACTION (CONTACT_CLIPBOARD_CUT); + sensitive = source_is_editable && any_contacts_selected; + gtk_action_set_sensitive (action, sensitive); + + action = ACTION (CONTACT_CLIPBOARD_PASTE); + sensitive = source_is_editable; + gtk_action_set_sensitive (action, sensitive); + + action = ACTION (CONTACT_COPY); + sensitive = any_contacts_selected; + gtk_action_set_sensitive (action, sensitive); + + action = ACTION (CONTACT_DELETE); + sensitive = source_is_editable && any_contacts_selected; + gtk_action_set_sensitive (action, sensitive); + + action = ACTION (CONTACT_FORWARD); + sensitive = any_contacts_selected; + gtk_action_set_sensitive (action, sensitive); + if (multiple_contacts_selected) + label = _("_Forward Contacts"); + else + label = _("_Forward Contact"); + g_object_set (action, "label", label, NULL); + + action = ACTION (CONTACT_MOVE); + sensitive = source_is_editable && any_contacts_selected; + gtk_action_set_sensitive (action, sensitive); + + action = ACTION (CONTACT_OPEN); + sensitive = any_contacts_selected; + gtk_action_set_sensitive (action, sensitive); + + action = ACTION (CONTACT_PRINT); + sensitive = any_contacts_selected; + gtk_action_set_sensitive (action, sensitive); + + action = ACTION (CONTACT_PRINT_PREVIEW); + sensitive = any_contacts_selected; + gtk_action_set_sensitive (action, sensitive); + + action = ACTION (CONTACT_SAVE_AS); + sensitive = any_contacts_selected; + gtk_action_set_sensitive (action, sensitive); + + action = ACTION (CONTACT_SELECT_ALL); + sensitive = !(source_is_empty); + gtk_action_set_sensitive (action, sensitive); + + action = ACTION (CONTACT_SEND_MESSAGE); + sensitive = any_contacts_selected && selection_has_email; + gtk_action_set_sensitive (action, sensitive); + if (multiple_contacts_selected) + label = _("_Send Message to Contacts"); + else if (selection_is_contact_list) + label = _("_Send Message to List"); + else + label = _("_Send Message to Contact"); + g_object_set (action, "label", label, NULL); +} + +static void +book_shell_view_class_init (EBookShellViewClass *class, + GTypeModule *type_module) +{ + GObjectClass *object_class; + EShellViewClass *shell_view_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EBookShellViewPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->get_property = book_shell_view_get_property; + object_class->dispose = book_shell_view_dispose; + object_class->finalize = book_shell_view_finalize; + object_class->constructed = book_shell_view_constructed; + + shell_view_class = E_SHELL_VIEW_CLASS (class); + shell_view_class->label = _("Contacts"); + shell_view_class->icon_name = "x-office-address-book"; + shell_view_class->ui_definition = "evolution-contacts.ui"; + shell_view_class->ui_manager_id = "org.gnome.evolution.contacts"; + shell_view_class->search_options = "/contact-search-options"; + shell_view_class->search_rules = "addresstypes.xml"; + shell_view_class->type_module = type_module; + shell_view_class->new_shell_content = e_book_shell_content_new; + shell_view_class->new_shell_sidebar = e_book_shell_sidebar_new; + shell_view_class->update_actions = book_shell_view_update_actions; + + g_object_class_install_property ( + object_class, + PROP_SOURCE_LIST, + g_param_spec_object ( + "source-list", + _("Source List"), + _("The registry of address books"), + E_TYPE_SOURCE_LIST, + G_PARAM_READABLE)); +} + +static void +book_shell_view_init (EBookShellView *book_shell_view, + EShellViewClass *shell_view_class) +{ + book_shell_view->priv = + E_BOOK_SHELL_VIEW_GET_PRIVATE (book_shell_view); + + e_book_shell_view_private_init (book_shell_view, shell_view_class); + + g_signal_connect_swapped ( + book_shell_view->priv->source_list, "changed", + G_CALLBACK (book_shell_view_source_list_changed_cb), + book_shell_view); +} + +GType +e_book_shell_view_get_type (GTypeModule *type_module) +{ + if (e_book_shell_view_type == 0) { + const GTypeInfo type_info = { + sizeof (EBookShellViewClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) book_shell_view_class_init, + (GClassFinalizeFunc) NULL, + type_module, + sizeof (EBookShellView), + 0, /* n_preallocs */ + (GInstanceInitFunc) book_shell_view_init, + NULL /* value_table */ + }; + + e_book_shell_view_type = + g_type_module_register_type ( + type_module, E_TYPE_SHELL_VIEW, + "EBookShellView", &type_info, 0); + } + + return e_book_shell_view_type; +} + +ESourceList * +e_book_shell_view_get_source_list (EBookShellView *book_shell_view) +{ + g_return_val_if_fail (E_IS_BOOK_SHELL_VIEW (book_shell_view), NULL); + + return book_shell_view->priv->source_list; +} diff --git a/addressbook/gui/component/e-book-shell-view.h b/addressbook/gui/component/e-book-shell-view.h new file mode 100644 index 0000000000..2b3f02c759 --- /dev/null +++ b/addressbook/gui/component/e-book-shell-view.h @@ -0,0 +1,71 @@ +/* + * e-book-shell-view.h + * + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_BOOK_SHELL_VIEW_H +#define E_BOOK_SHELL_VIEW_H + +#include <e-shell-view.h> +#include <libedataserver/e-source-list.h> + +/* Standard GObject macros */ +#define E_TYPE_BOOK_SHELL_VIEW \ + (e_book_shell_view_type) +#define E_BOOK_SHELL_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_BOOK_SHELL_VIEW, EBookShellView)) +#define E_BOOK_SHELL_VIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_BOOK_SHELL_VIEW, EBookShellViewClass)) +#define E_IS_BOOK_SHELL_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_BOOK_SHELL_VIEW)) +#define E_IS_BOOK_SHELL_VIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_BOOK_SHELL_VIEW)) +#define E_BOOK_SHELL_VIEW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_BOOK_SHELL_VIEW, EBookShellViewClass)) + +G_BEGIN_DECLS + +extern GType e_book_shell_view_type; + +typedef struct _EBookShellView EBookShellView; +typedef struct _EBookShellViewClass EBookShellViewClass; +typedef struct _EBookShellViewPrivate EBookShellViewPrivate; + +struct _EBookShellView { + EShellView parent; + EBookShellViewPrivate *priv; +}; + +struct _EBookShellViewClass { + EShellViewClass parent_class; +}; + +GType e_book_shell_view_get_type + (GTypeModule *type_module); +ESourceList * e_book_shell_view_get_source_list + (EBookShellView *book_shell_view); + +G_END_DECLS + +#endif /* E_BOOK_SHELL_VIEW_H */ diff --git a/addressbook/gui/component/eab-composer-util.c b/addressbook/gui/component/eab-composer-util.c new file mode 100644 index 0000000000..943225b011 --- /dev/null +++ b/addressbook/gui/component/eab-composer-util.c @@ -0,0 +1,197 @@ +/* + * 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/> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "eab-composer-util.h" + +#include <string.h> +#include <glib/gi18n.h> +#include <libebook/e-contact.h> +#include <libebook/e-destination.h> + +#include "composer/e-msg-composer.h" +#include "addressbook/util/eab-book-util.h" +#include "addressbook/gui/widgets/eab-gui-util.h" + +void +eab_send_as_to (GList *destinations) +{ + EMsgComposer *composer; + EComposerHeaderTable *table; + GPtrArray *to_array; + GPtrArray *bcc_array; + + union { + gpointer *pdata; + EDestination **destinations; + } convert; + + if (destinations == NULL) + return; + + composer = e_msg_composer_new (); + table = e_msg_composer_get_header_table (composer); + + to_array = g_ptr_array_new (); + bcc_array = g_ptr_array_new (); + + /* Sort contacts into "To" and "Bcc" destinations. */ + while (destinations != NULL) { + EDestination *destination = destinations->data; + + if (e_destination_is_evolution_list (destination)) { + if (e_destination_list_show_addresses (destination)) + g_ptr_array_add (to_array, destination); + else + g_ptr_array_add (bcc_array, destination); + } else + g_ptr_array_add (to_array, destination); + + destinations = g_list_next (destinations); + } + + /* Add sentinels to each array. */ + g_ptr_array_add (to_array, NULL); + g_ptr_array_add (bcc_array, NULL); + + /* XXX Acrobatics like this make me question whether NULL-terminated + * arrays are really the best argument type for passing a list of + * destinations to the header table. */ + + /* Add "To" destinations. */ + convert.pdata = to_array->pdata; + e_composer_header_table_set_destinations_to ( + table, convert.destinations); + g_ptr_array_free (to_array, FALSE); + e_destination_freev (convert.destinations); + + /* Add "Bcc" destinations. */ + convert.pdata = bcc_array->pdata; + e_composer_header_table_set_destinations_bcc ( + table, convert.destinations); + g_ptr_array_free (bcc_array, FALSE); + e_destination_freev (convert.destinations); + + gtk_widget_show (GTK_WIDGET (composer)); +} + +static const char * +get_email (EContact *contact, EContactField field_id, gchar **to_free) +{ + char *name = NULL, *mail = NULL; + const char *value = e_contact_get_const (contact, field_id); + + *to_free = NULL; + + if (eab_parse_qp_email (value, &name, &mail)) { + *to_free = g_strdup_printf ("%s <%s>", name, mail); + value = *to_free; + } + + g_free (name); + g_free (mail); + + return value; +} + +void +eab_send_as_attachment (GList *destinations) +{ + EMsgComposer *composer; + EComposerHeaderTable *table; + CamelMimePart *attachment; + GList *contacts, *iter; + gchar *data; + + if (destinations == NULL) + return; + + composer = e_msg_composer_new (); + table = e_msg_composer_get_header_table (composer); + + attachment = camel_mime_part_new (); + + contacts = g_list_copy (destinations); + for (iter = contacts; iter != NULL; iter = iter->next) + iter->data = e_destination_get_contact (iter->data); + data = eab_contact_list_to_string (contacts); + g_list_free (contacts); + + camel_mime_part_set_content ( + attachment, data, strlen (data), "text/x-vcard"); + + if (destinations->next != NULL) + camel_mime_part_set_description ( + attachment, _("Multiple vCards")); + else { + EContact *contact; + const gchar *file_as; + gchar *description; + + contact = e_destination_get_contact (destinations->data); + file_as = e_contact_get_const (contact, E_CONTACT_FILE_AS); + description = g_strdup_printf (_("vCard for %s"), file_as); + camel_mime_part_set_description (attachment, description); + g_free (description); + } + + camel_mime_part_set_disposition (attachment, "attachment"); + + e_msg_composer_attach (composer, attachment); + camel_object_unref (attachment); + + if (destinations->next != NULL) + e_composer_header_table_set_subject ( + table, _("Contact information")); + else { + EContact *contact; + gchar *tempstr; + const gchar *tempstr2; + gchar *tempfree = NULL; + + contact = e_destination_get_contact (destinations->data); + tempstr2 = e_contact_get_const (contact, E_CONTACT_FILE_AS); + if (!tempstr2 || !*tempstr2) + tempstr2 = e_contact_get_const (contact, E_CONTACT_FULL_NAME); + if (!tempstr2 || !*tempstr2) + tempstr2 = e_contact_get_const (contact, E_CONTACT_ORG); + if (!tempstr2 || !*tempstr2) { + g_free (tempfree); + tempstr2 = get_email (contact, E_CONTACT_EMAIL_1, &tempfree); + } + if (!tempstr2 || !*tempstr2) { + g_free (tempfree); + tempstr2 = get_email (contact, E_CONTACT_EMAIL_2, &tempfree); + } + if (!tempstr2 || !*tempstr2) { + g_free (tempfree); + tempstr2 = get_email (contact, E_CONTACT_EMAIL_3, &tempfree); + } + + if (!tempstr2 || !*tempstr2) + tempstr = g_strdup_printf (_("Contact information")); + else + tempstr = g_strdup_printf (_("Contact information for %s"), tempstr2); + + e_composer_header_table_set_subject (table, tempstr); + + g_free (tempstr); + g_free (tempfree); + } + + gtk_widget_show (GTK_WIDGET (composer)); +} diff --git a/addressbook/gui/widgets/eab-vcard-control.h b/addressbook/gui/component/eab-composer-util.h index 06ca62727a..ffee76b2b7 100644 --- a/addressbook/gui/widgets/eab-vcard-control.h +++ b/addressbook/gui/component/eab-composer-util.h @@ -1,5 +1,4 @@ /* - * * 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 @@ -13,16 +12,20 @@ * 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/> * - * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ -#ifndef __EAB_VCARD_CONTROL_H__ -#define __EAB_VCARD_CONTROL_H__ +#ifndef EAB_COMPOSER_UTIL_H +#define EAB_COMPOSER_UTIL_H + +#include <gtk/gtk.h> + +G_BEGIN_DECLS -#include <bonobo/bonobo-control.h> +void eab_send_as_to (GList *destinations); +void eab_send_as_attachment (GList *destinations); -BonoboControl *eab_vcard_control_new (void); +G_END_DECLS -#endif /* __EAB_VCARD_CONTROL_H__ */ +#endif /* EAB_COMPOSER_UTIL_H */ diff --git a/addressbook/gui/contact-editor/Makefile.am b/addressbook/gui/contact-editor/Makefile.am index 53ed96fdee..a267f09b13 100644 --- a/addressbook/gui/contact-editor/Makefile.am +++ b/addressbook/gui/contact-editor/Makefile.am @@ -29,10 +29,14 @@ libecontacteditor_la_SOURCES = \ libecontacteditor_la_LDFLAGS = $(NO_UNDEFINED) -libecontacteditor_la_LIBADD = \ - $(WIN32_BOOTSTRAP_LIBS) \ - $(top_builddir)/widgets/misc/libemiscwidgets.la \ - $(top_builddir)/e-util/libeutil.la \ +libecontacteditor_la_LIBADD = \ + $(WIN32_BOOTSTRAP_LIBS) \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/widgets/misc/libemiscwidgets.la \ + $(top_builddir)/addressbook/util/libeabutil.la \ + $(top_builddir)/addressbook/gui/widgets/libeabwidgets.la \ + $(top_builddir)/addressbook/gui/merging/libeabbookmerging.la \ + $(top_builddir)/addressbook/printing/libecontactprint.la \ $(EVOLUTION_ADDRESSBOOK_LIBS) glade_DATA = \ diff --git a/addressbook/gui/contact-editor/e-contact-editor.c b/addressbook/gui/contact-editor/e-contact-editor.c index 9eaf9897ba..e4447b9075 100644 --- a/addressbook/gui/contact-editor/e-contact-editor.c +++ b/addressbook/gui/contact-editor/e-contact-editor.c @@ -33,7 +33,6 @@ #include <gdk-pixbuf/gdk-pixbuf.h> #include <libedataserverui/e-categories-dialog.h> -#include <misc/e-gui-utils.h> #include <libebook/e-address-western.h> #include <libedataserverui/e-category-completion.h> @@ -41,7 +40,7 @@ #include <camel/camel.h> -#include "addressbook/gui/component/addressbook.h" +#include "addressbook/util/addressbook.h" #include "addressbook/printing/e-contact-print.h" #include "addressbook/gui/widgets/eab-gui-util.h" #include "e-util/e-util.h" @@ -49,9 +48,9 @@ #include "misc/e-dateedit.h" #include "misc/e-image-chooser.h" #include "misc/e-url-entry.h" -#include "shell/evolution-shell-component-utils.h" #include "e-util/e-icon-factory.h" #include "e-util/e-util-private.h" +#include "shell/e-shell.h" #include "eab-contact-merging.h" @@ -199,6 +198,54 @@ static const gint email_default [] = { 0, 1, 2, 2 }; #define STRING_IS_EMPTY(x) (!(x) || !(*(x))) #define STRING_MAKE_NON_NULL(x) ((x) ? (x) : "") +static void +e_contact_editor_contact_added (EABEditor *editor, + EBookStatus status, + EContact *contact) +{ + if (status == E_BOOK_ERROR_OK) + return; + + if (status == E_BOOK_ERROR_CANCELLED) + return; + + eab_error_dialog (_("Error adding contact"), status); +} + +static void +e_contact_editor_contact_modified (EABEditor *editor, + EBookStatus status, + EContact *contact) +{ + if (status == E_BOOK_ERROR_OK) + return; + + if (status == E_BOOK_ERROR_CANCELLED) + return; + + eab_error_dialog (_("Error modifying contact"), status); +} + +static void +e_contact_editor_contact_deleted (EABEditor *editor, + EBookStatus status, + EContact *contact) +{ + if (status == E_BOOK_ERROR_OK) + return; + + if (status == E_BOOK_ERROR_CANCELLED) + return; + + eab_error_dialog (_("Error removing contact"), status); +} + +static void +e_contact_editor_closed (EABEditor *editor) +{ + g_object_unref (editor); +} + GType e_contact_editor_get_type (void) { @@ -242,6 +289,10 @@ e_contact_editor_class_init (EContactEditorClass *klass) editor_class->save_contact = e_contact_editor_save_contact; editor_class->is_changed = e_contact_editor_is_changed; editor_class->get_window = e_contact_editor_get_window; + editor_class->contact_added = e_contact_editor_contact_added; + editor_class->contact_modified = e_contact_editor_contact_modified; + editor_class->contact_deleted = e_contact_editor_contact_deleted; + editor_class->editor_closed = e_contact_editor_closed; g_object_class_install_property (object_class, PROP_SOURCE_BOOK, g_param_spec_object ("source_book", @@ -3329,6 +3380,7 @@ static void e_contact_editor_init (EContactEditor *e_contact_editor) { GladeXML *gui; + EShell *shell; GtkWidget *widget, *label; GtkEntryCompletion *completion; char *gladefile; @@ -3406,6 +3458,10 @@ e_contact_editor_init (EContactEditor *e_contact_editor) /* show window */ gtk_widget_show (e_contact_editor->app); + + /* FIXME Shell should be passed in. */ + shell = e_shell_get_default (); + e_shell_watch_window (shell, GTK_WINDOW (e_contact_editor->app)); } static void @@ -3501,7 +3557,7 @@ contact_editor_destroy_notify (void *data, eab_editor_remove (EAB_EDITOR (data)); } -EContactEditor * +GtkWidget * e_contact_editor_new (EBook *book, EContact *contact, gboolean is_new_contact, @@ -3527,7 +3583,7 @@ e_contact_editor_new (EBook *book, if (book) e_book_async_get_supported_fields (book, (EBookEListCallback)supported_fields_cb, ce); - return ce; + return GTK_WIDGET (ce); } static void diff --git a/addressbook/gui/contact-editor/e-contact-editor.h b/addressbook/gui/contact-editor/e-contact-editor.h index 02b837fb46..d216fe0435 100644 --- a/addressbook/gui/contact-editor/e-contact-editor.h +++ b/addressbook/gui/contact-editor/e-contact-editor.h @@ -23,7 +23,6 @@ #ifndef __E_CONTACT_EDITOR_H__ #define __E_CONTACT_EDITOR_H__ -#include <bonobo/bonobo-ui-component.h> #include <glade/glade.h> #include "addressbook/gui/contact-editor/eab-editor.h" @@ -63,9 +62,6 @@ struct _EContactEditor EBook *target_book; EContact *contact; - /* UI handler */ - BonoboUIComponent *uic; - GladeXML *gui; GtkWidget *app; @@ -111,11 +107,11 @@ struct _EContactEditorClass EABEditorClass parent_class; }; -EContactEditor *e_contact_editor_new (EBook *book, - EContact *contact, - gboolean is_new_contact, - gboolean editable); -GType e_contact_editor_get_type (void); +GType e_contact_editor_get_type (void); +GtkWidget *e_contact_editor_new (EBook *book, + EContact *contact, + gboolean is_new_contact, + gboolean editable); G_END_DECLS diff --git a/addressbook/gui/contact-editor/e-contact-quick-add.c b/addressbook/gui/contact-editor/e-contact-quick-add.c index 418bdbc1ae..d30559e34f 100644 --- a/addressbook/gui/contact-editor/e-contact-quick-add.c +++ b/addressbook/gui/contact-editor/e-contact-quick-add.c @@ -28,7 +28,7 @@ #include <libebook/e-book.h> #include <libebook/e-contact.h> #include <libedataserverui/e-source-combo-box.h> -#include <addressbook/gui/component/addressbook.h> +#include <addressbook/util/addressbook.h> #include <addressbook/util/eab-book-util.h> #include "e-contact-editor.h" #include "e-contact-quick-add.h" @@ -194,7 +194,7 @@ ce_have_book (EBook *book, EBookStatus status, gpointer closure) g_warning ("Couldn't open local address book."); quick_add_unref (qa); } else { - EContactEditor *contact_editor = e_contact_editor_new (book, qa->contact, TRUE, TRUE /* XXX */); + GtkWidget *contact_editor = e_contact_editor_new (book, qa->contact, TRUE, TRUE /* XXX */); /* mark it as changed so the Save buttons are enabled when we bring up the dialog. */ g_object_set (contact_editor, diff --git a/addressbook/gui/contact-editor/eab-editor.c b/addressbook/gui/contact-editor/eab-editor.c index b94dff2953..d45fb688ea 100644 --- a/addressbook/gui/contact-editor/eab-editor.c +++ b/addressbook/gui/contact-editor/eab-editor.c @@ -28,8 +28,8 @@ #include <glib/gi18n.h> #include "eab-editor.h" -#include "addressbook/gui/widgets/eab-gui-util.h" #include "e-util/e-util.h" +#include "addressbook/gui/widgets/eab-gui-util.h" static void eab_editor_default_show (EABEditor *editor); static void eab_editor_default_raise (EABEditor *editor); @@ -310,51 +310,6 @@ eab_editor_get_all_editors (void) return all_editors; } -gboolean -eab_editor_confirm_delete (GtkWindow *parent, gboolean plural, gboolean is_list, char *name) -{ - GtkWidget *dialog; - gint result; - char *msg; - - if (is_list) { - /* contact list(s) */ - if (!plural) - msg = g_strdup_printf (_("Are you sure you want\nto delete contact list (%s)?"), - name?name:""); - else - msg = g_strdup (_("Are you sure you want\nto delete these contact lists?")); - } - else { - /* contact(s) */ - if (!plural) - msg = g_strdup_printf (_("Are you sure you want\nto delete contact (%s)?"), - name?name:""); - else - msg = g_strdup (_("Are you sure you want\nto delete these contacts?")); - } - - dialog = gtk_message_dialog_new (parent, - 0, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_NONE, - "%s", - msg); - g_free (msg); - - gtk_dialog_add_buttons (GTK_DIALOG (dialog), - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT, - NULL); - - result = gtk_dialog_run(GTK_DIALOG (dialog)); - - gtk_widget_destroy (dialog); - - return (result == GTK_RESPONSE_ACCEPT); -} - - void eab_editor_contact_added (EABEditor *editor, EBookStatus status, EContact *contact) { diff --git a/addressbook/gui/contact-editor/eab-editor.h b/addressbook/gui/contact-editor/eab-editor.h index ae13270fe0..4f108f509f 100644 --- a/addressbook/gui/contact-editor/eab-editor.h +++ b/addressbook/gui/contact-editor/eab-editor.h @@ -24,7 +24,6 @@ #ifndef __EAB_EDITOR_H__ #define __EAB_EDITOR_H__ -#include <bonobo/bonobo-ui-component.h> #include <glade/glade.h> #include <libebook/e-book.h> @@ -91,7 +90,6 @@ gboolean eab_editor_is_changed (EABEditor *editor); GtkWindow* eab_editor_get_window (EABEditor *editor); gboolean eab_editor_prompt_to_save_changes (EABEditor *editor, GtkWindow *window); -gboolean eab_editor_confirm_delete (GtkWindow *parent, gboolean plural, gboolean is_list, char *name); /* these four generate EABEditor signals */ void eab_editor_contact_added (EABEditor *editor, EBookStatus status, EContact *contact); diff --git a/addressbook/gui/contact-list-editor/e-contact-list-editor.c b/addressbook/gui/contact-list-editor/e-contact-list-editor.c index 8fec8b315d..ccaf9b740f 100644 --- a/addressbook/gui/contact-list-editor/e-contact-list-editor.c +++ b/addressbook/gui/contact-list-editor/e-contact-list-editor.c @@ -34,10 +34,8 @@ #include <libedataserverui/e-source-combo-box.h> -#include "shell/evolution-shell-component-utils.h" - -#include "addressbook/gui/component/addressbook.h" #include "addressbook/gui/widgets/eab-gui-util.h" +#include "addressbook/util/addressbook.h" #include "addressbook/util/eab-book-util.h" #include "eab-editor.h" @@ -924,87 +922,6 @@ contact_list_editor_create_name_selector (gchar *name, return GTK_WIDGET (name_selector_entry); } -/**************************** EABEditor Callbacks ****************************/ - -static void -contact_list_editor_show (EABEditor *editor) -{ - gtk_widget_show (WIDGET (DIALOG)); -} - -static void -contact_list_editor_close (EABEditor *editor) -{ - gtk_widget_destroy (WIDGET (DIALOG)); - eab_editor_closed (editor); -} - -static void -contact_list_editor_raise (EABEditor *editor) -{ - gdk_window_raise (WIDGET (DIALOG)->window); -} - -static void -contact_list_editor_save_contact (EABEditor *eab_editor, - gboolean should_close) -{ - EContactListEditor *editor = E_CONTACT_LIST_EDITOR (eab_editor); - EContactListEditorPrivate *priv = editor->priv; - EditorCloseStruct *ecs; - EContact *contact; - - contact = e_contact_list_editor_get_contact (editor); - - if (priv->book == NULL) - return; - - ecs = g_new (EditorCloseStruct, 1); - ecs->editor = g_object_ref (editor); - ecs->should_close = should_close; - - gtk_widget_set_sensitive (WIDGET (DIALOG), FALSE); - priv->in_async_call = TRUE; - - if (priv->is_new_list) - eab_merging_book_add_contact ( - priv->book, contact, (EBookIdCallback) - contact_list_editor_list_added_cb, ecs); - else - eab_merging_book_commit_contact ( - priv->book, contact, (EBookCallback) - contact_list_editor_list_modified_cb, ecs); - - priv->changed = FALSE; -} - -static gboolean -contact_list_editor_is_valid (EABEditor *editor) -{ - GtkEditable *editable; - gboolean valid; - gchar *chars; - - editable = GTK_EDITABLE (WIDGET (LIST_NAME_ENTRY)); - chars = gtk_editable_get_chars (editable, 0, -1); - valid = (chars != NULL && *chars != '\0'); - g_free (chars); - - return valid; -} - -static gboolean -contact_list_editor_is_changed (EABEditor *editor) -{ - return E_CONTACT_LIST_EDITOR_GET_PRIVATE (editor)->changed; -} - -static GtkWindow* -contact_list_editor_get_window (EABEditor *editor) -{ - return GTK_WINDOW (WIDGET (DIALOG)); -} - /***************************** GObject Callbacks *****************************/ static GObject * @@ -1114,6 +1031,135 @@ contact_list_editor_dispose (GObject *object) G_OBJECT_CLASS (parent_class)->dispose (object); } +/**************************** EABEditor Callbacks ****************************/ + +static void +contact_list_editor_show (EABEditor *editor) +{ + gtk_widget_show (WIDGET (DIALOG)); +} + +static void +contact_list_editor_close (EABEditor *editor) +{ + gtk_widget_destroy (WIDGET (DIALOG)); + eab_editor_closed (editor); +} + +static void +contact_list_editor_raise (EABEditor *editor) +{ + gdk_window_raise (WIDGET (DIALOG)->window); +} + +static void +contact_list_editor_save_contact (EABEditor *eab_editor, + gboolean should_close) +{ + EContactListEditor *editor = E_CONTACT_LIST_EDITOR (eab_editor); + EContactListEditorPrivate *priv = editor->priv; + EditorCloseStruct *ecs; + EContact *contact; + + contact = e_contact_list_editor_get_contact (editor); + + if (priv->book == NULL) + return; + + ecs = g_new (EditorCloseStruct, 1); + ecs->editor = g_object_ref (editor); + ecs->should_close = should_close; + + gtk_widget_set_sensitive (WIDGET (DIALOG), FALSE); + priv->in_async_call = TRUE; + + if (priv->is_new_list) + eab_merging_book_add_contact ( + priv->book, contact, (EBookIdCallback) + contact_list_editor_list_added_cb, ecs); + else + eab_merging_book_commit_contact ( + priv->book, contact, (EBookCallback) + contact_list_editor_list_modified_cb, ecs); + + priv->changed = FALSE; +} + +static gboolean +contact_list_editor_is_valid (EABEditor *editor) +{ + GtkEditable *editable; + gboolean valid; + gchar *chars; + + editable = GTK_EDITABLE (WIDGET (LIST_NAME_ENTRY)); + chars = gtk_editable_get_chars (editable, 0, -1); + valid = (chars != NULL && *chars != '\0'); + g_free (chars); + + return valid; +} + +static gboolean +contact_list_editor_is_changed (EABEditor *editor) +{ + return E_CONTACT_LIST_EDITOR_GET_PRIVATE (editor)->changed; +} + +static GtkWindow * +contact_list_editor_get_window (EABEditor *editor) +{ + return GTK_WINDOW (WIDGET (DIALOG)); +} + +static void +contact_list_editor_contact_added (EABEditor *editor, + EBookStatus status, + EContact *contact) +{ + if (status == E_BOOK_ERROR_OK) + return; + + if (status == E_BOOK_ERROR_CANCELLED) + return; + + eab_error_dialog (_("Error adding list"), status); +} + +static void +contact_list_editor_contact_modified (EABEditor *editor, + EBookStatus status, + EContact *contact) +{ + if (status == E_BOOK_ERROR_OK) + return; + + if (status == E_BOOK_ERROR_CANCELLED) + return; + + eab_error_dialog (_("Error modifying list"), status); +} + +static void +contact_list_editor_contact_deleted (EABEditor *editor, + EBookStatus status, + EContact *contact) +{ + if (status == E_BOOK_ERROR_OK) + return; + + if (status == E_BOOK_ERROR_CANCELLED) + return; + + eab_error_dialog (_("Error removing list"), status); +} + +static void +contact_list_editor_closed (EABEditor *editor) +{ + g_object_unref (editor); +} + /****************************** GType Callbacks ******************************/ static void @@ -1139,6 +1185,10 @@ contact_list_editor_class_init (EContactListEditorClass *class) editor_class->is_valid = contact_list_editor_is_valid; editor_class->is_changed = contact_list_editor_is_changed; editor_class->get_window = contact_list_editor_get_window; + editor_class->contact_added = contact_list_editor_contact_added; + editor_class->contact_modified = contact_list_editor_contact_modified; + editor_class->contact_deleted = contact_list_editor_contact_deleted; + editor_class->editor_closed = contact_list_editor_closed; g_object_class_install_property ( object_class, @@ -1276,7 +1326,7 @@ contact_list_editor_destroy_notify (gpointer data, eab_editor_remove (EAB_EDITOR (data)); } -EContactListEditor * +GtkWidget * e_contact_list_editor_new (EBook *book, EContact *list_contact, gboolean is_new_list, @@ -1297,7 +1347,7 @@ e_contact_list_editor_new (EBook *book, "editable", editable, NULL); - return editor; + return GTK_WIDGET (editor); } EBook * diff --git a/addressbook/gui/contact-list-editor/e-contact-list-editor.h b/addressbook/gui/contact-list-editor/e-contact-list-editor.h index deed3f60c0..13b6864a9a 100644 --- a/addressbook/gui/contact-list-editor/e-contact-list-editor.h +++ b/addressbook/gui/contact-list-editor/e-contact-list-editor.h @@ -68,7 +68,7 @@ struct _EContactListEditorClass }; GType e_contact_list_editor_get_type (void); -EContactListEditor * e_contact_list_editor_new (EBook *book, +GtkWidget * e_contact_list_editor_new (EBook *book, EContact *list_contact, gboolean is_new_list, gboolean editable); diff --git a/addressbook/gui/merging/eab-contact-compare.c b/addressbook/gui/merging/eab-contact-compare.c index adc6938c8d..b5597abb29 100644 --- a/addressbook/gui/merging/eab-contact-compare.c +++ b/addressbook/gui/merging/eab-contact-compare.c @@ -24,8 +24,8 @@ #include <config.h> #include <ctype.h> #include <string.h> -#include "util/eab-book-util.h" -#include "../component/addressbook.h" +#include "addressbook/util/addressbook.h" +#include "addressbook/util/eab-book-util.h" #include "eab-contact-compare.h" /* This is an "optimistic" combiner: the best of the two outcomes is diff --git a/addressbook/gui/merging/eab-contact-merging.c b/addressbook/gui/merging/eab-contact-merging.c index 502fe381b6..2a97169459 100644 --- a/addressbook/gui/merging/eab-contact-merging.c +++ b/addressbook/gui/merging/eab-contact-merging.c @@ -472,12 +472,18 @@ match_query_callback (EContact *contact, EContact *match, EABContactMatchType ty } widget = glade_xml_get_widget (ui, "custom-old-contact"); - eab_contact_display_render (EAB_CONTACT_DISPLAY (widget), - match, EAB_CONTACT_DISPLAY_RENDER_COMPACT); + eab_contact_display_set_mode ( + EAB_CONTACT_DISPLAY (widget), + EAB_CONTACT_DISPLAY_RENDER_COMPACT); + eab_contact_display_set_contact ( + EAB_CONTACT_DISPLAY (widget), match); widget = glade_xml_get_widget (ui, "custom-new-contact"); - eab_contact_display_render (EAB_CONTACT_DISPLAY (widget), - contact, EAB_CONTACT_DISPLAY_RENDER_COMPACT); + eab_contact_display_set_mode ( + EAB_CONTACT_DISPLAY (widget), + EAB_CONTACT_DISPLAY_RENDER_COMPACT); + eab_contact_display_set_contact ( + EAB_CONTACT_DISPLAY (widget), contact); widget = glade_xml_get_widget (ui, "dialog-duplicate-contact"); diff --git a/addressbook/gui/widgets/Makefile.am b/addressbook/gui/widgets/Makefile.am index c3a14d8aeb..9e3affcb2f 100644 --- a/addressbook/gui/widgets/Makefile.am +++ b/addressbook/gui/widgets/Makefile.am @@ -7,11 +7,11 @@ INCLUDES = \ -DEVOLUTION_GALVIEWSDIR=\""$(viewsdir)"\" \ -DSEARCH_RULE_DIR=\"$(ruledir)\" \ -I$(top_srcdir) \ + -I$(top_srcdir)/filter \ -I$(top_srcdir)/widgets \ -I$(top_srcdir)/addressbook \ - -I$(top_srcdir)/addressbook/gui/contact-editor \ -I$(top_srcdir)/addressbook/gui/merging \ - -I$(top_srcdir)/addressbook/gui/component \ + -I$(top_srcdir)/addressbook/util \ -I$(top_srcdir)/widgets/misc \ -I$(top_builddir)/shell \ $(EVOLUTION_ADDRESSBOOK_CFLAGS) @@ -22,9 +22,7 @@ noinst_LTLIBRARIES = \ eabincludedir = $(privincludedir)/addressbook/gui/widgets eabinclude_HEADERS = \ - eab-config.h \ - eab-menu.h \ - eab-popup.h + eab-config.h libeabwidgets_la_SOURCES = \ eab-config.c \ @@ -32,13 +30,6 @@ libeabwidgets_la_SOURCES = \ eab-contact-display.h \ eab-gui-util.c \ eab-gui-util.h \ - eab-menu.c \ - eab-popup.c \ - eab-popup.h \ - eab-popup-control.c \ - eab-popup-control.h \ - eab-vcard-control.c \ - eab-vcard-control.h \ e-minicard.c \ e-minicard.h \ e-minicard-label.c \ @@ -53,6 +44,8 @@ libeabwidgets_la_SOURCES = \ e-addressbook-table-adapter.h \ e-addressbook-model.c \ e-addressbook-model.h \ + e-addressbook-selector.c \ + e-addressbook-selector.h \ e-addressbook-view.c \ e-addressbook-view.h \ gal-view-minicard.c \ @@ -60,6 +53,10 @@ libeabwidgets_la_SOURCES = \ gal-view-factory-minicard.c \ gal-view-factory-minicard.h +libeabwidgets_la_LIBADD = \ + $(top_builddir)/widgets/misc/libemiscwidgets.la \ + $(top_builddir)/a11y/addressbook/libevolution-addressbook-a11y.la + dist-hook: cd $(distdir); rm -f $(BUILT_SOURCES) @@ -67,6 +64,6 @@ etspec_DATA= e-addressbook-view.etspec EXTRA_DIST = \ $(etspec_DATA) \ - addresstypes.xml + $(rule_DATA) -include $(top_srcdir)/git.mk diff --git a/addressbook/gui/widgets/e-addressbook-model.c b/addressbook/gui/widgets/e-addressbook-model.c index 7273689fd1..772e72e3af 100644 --- a/addressbook/gui/widgets/e-addressbook-model.c +++ b/addressbook/gui/widgets/e-addressbook-model.c @@ -22,32 +22,45 @@ #include <config.h> #include <string.h> -#include <gtk/gtk.h> #include <glib/gi18n.h> -#include "e-util/e-util.h" #include "e-addressbook-model.h" -#include <libxml/tree.h> -#include <libxml/parser.h> -#include <libxml/xmlmemory.h> +#include <e-util/e-util.h> #include <misc/e-gui-utils.h> #include "eab-gui-util.h" -#define PARENT_TYPE G_TYPE_OBJECT -static GObjectClass *parent_class; - -/* - * EABModel callbacks - * These are the callbacks that define the behavior of our custom model. - */ -static void eab_model_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void eab_model_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); - +#define E_ADDRESSBOOK_MODEL_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_ADDRESSBOOK_MODEL, EAddressbookModelPrivate)) + +struct _EAddressbookModelPrivate { + EBook *book; + EBookQuery *query; + EBookView *book_view; + guint book_view_idle_id; + + /* Query Results */ + GPtrArray *contacts; + + /* Signal Handler IDs */ + gulong create_contact_id; + gulong remove_contact_id; + gulong modify_contact_id; + gulong status_message_id; + gulong writable_status_id; + gulong sequence_complete_id; + gulong backend_died_id; + + guint search_in_progress : 1; + guint editable : 1; + guint editable_set : 1; + guint first_get_view : 1; +}; enum { PROP_0, PROP_BOOK, - PROP_QUERY, PROP_EDITABLE, + PROP_QUERY }; enum { @@ -65,673 +78,799 @@ enum { LAST_SIGNAL }; -static guint eab_model_signals [LAST_SIGNAL] = {0, }; +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; static void -free_data (EABModel *model) +free_data (EAddressbookModel *model) { - if (model->data) { - int i; - - for ( i = 0; i < model->data_count; i++ ) { - g_object_unref (model->data[i]); - } + GPtrArray *array; - g_free(model->data); - model->data = NULL; - model->data_count = 0; - model->allocated_count = 0; - } + array = model->priv->contacts; + g_ptr_array_foreach (array, (GFunc) g_object_unref, NULL); + g_ptr_array_set_size (array, 0); } static void -remove_book_view(EABModel *model) -{ - if (model->book_view && model->create_contact_id) - g_signal_handler_disconnect (model->book_view, - model->create_contact_id); - if (model->book_view && model->remove_contact_id) - g_signal_handler_disconnect (model->book_view, - model->remove_contact_id); - if (model->book_view && model->modify_contact_id) - g_signal_handler_disconnect (model->book_view, - model->modify_contact_id); - if (model->book_view && model->status_message_id) - g_signal_handler_disconnect (model->book_view, - model->status_message_id); - if (model->book_view && model->sequence_complete_id) - g_signal_handler_disconnect (model->book_view, - model->sequence_complete_id); - - model->create_contact_id = 0; - model->remove_contact_id = 0; - model->modify_contact_id = 0; - model->status_message_id = 0; - model->sequence_complete_id = 0; - - model->search_in_progress = FALSE; - - if (model->book_view) { - e_book_view_stop (model->book_view); - g_object_unref (model->book_view); - model->book_view = NULL; - } -} - -static void -addressbook_dispose(GObject *object) +remove_book_view(EAddressbookModel *model) { - EABModel *model = EAB_MODEL(object); - - remove_book_view(model); - free_data (model); - - if (model->book) { - if (model->writable_status_id) - g_signal_handler_disconnect (model->book, - model->writable_status_id); - model->writable_status_id = 0; - - if (model->backend_died_id) - g_signal_handler_disconnect (model->book, - model->backend_died_id); - model->backend_died_id = 0; - - g_object_unref (model->book); - model->book = NULL; + if (model->priv->book_view && model->priv->create_contact_id) + g_signal_handler_disconnect ( + model->priv->book_view, + model->priv->create_contact_id); + if (model->priv->book_view && model->priv->remove_contact_id) + g_signal_handler_disconnect ( + model->priv->book_view, + model->priv->remove_contact_id); + if (model->priv->book_view && model->priv->modify_contact_id) + g_signal_handler_disconnect ( + model->priv->book_view, + model->priv->modify_contact_id); + if (model->priv->book_view && model->priv->status_message_id) + g_signal_handler_disconnect ( + model->priv->book_view, + model->priv->status_message_id); + if (model->priv->book_view && model->priv->sequence_complete_id) + g_signal_handler_disconnect ( + model->priv->book_view, + model->priv->sequence_complete_id); + + model->priv->create_contact_id = 0; + model->priv->remove_contact_id = 0; + model->priv->modify_contact_id = 0; + model->priv->status_message_id = 0; + model->priv->sequence_complete_id = 0; + + model->priv->search_in_progress = FALSE; + + if (model->priv->book_view) { + e_book_view_stop (model->priv->book_view); + g_object_unref (model->priv->book_view); + model->priv->book_view = NULL; } - - if (model->query) { - e_book_query_unref (model->query); - model->query = NULL; - } - - if (G_OBJECT_CLASS(parent_class)->dispose) - G_OBJECT_CLASS(parent_class)->dispose(object); } static void -update_folder_bar_message (EABModel *model) +update_folder_bar_message (EAddressbookModel *model) { - int count; + guint count; char *message; - count = model->data_count; + count = model->priv->contacts->len; switch (count) { case 0: message = g_strdup (_("No contacts")); break; default: - message = g_strdup_printf (ngettext("%d contact", "%d contacts", count), count); + message = g_strdup_printf ( + ngettext ("%d contact", "%d contacts", count), count); break; } - g_signal_emit (model, - eab_model_signals [FOLDER_BAR_MESSAGE], 0, - message); + g_signal_emit (model, signals[FOLDER_BAR_MESSAGE], 0, message); g_free (message); } static void -create_contact(EBookView *book_view, - const GList *contacts, - EABModel *model) +create_contact (EBookView *book_view, + const GList *contact_list, + EAddressbookModel *model) { - int old_count = model->data_count; - int length = g_list_length ((GList *)contacts); + GPtrArray *array; + guint count; + guint index; - if (model->data_count + length > model->allocated_count) { - while (model->data_count + length > model->allocated_count) - model->allocated_count = model->allocated_count * 2 + 1; - model->data = g_renew(EContact *, model->data, model->allocated_count); - } + array = model->priv->contacts; + index = array->len; + count = g_list_length ((GList *) contact_list); - for ( ; contacts; contacts = contacts->next) { - model->data[model->data_count++] = contacts->data; - g_object_ref (contacts->data); - } + while (contact_list != NULL) { + EContact *contact = contact_list->data; - g_signal_emit (model, - eab_model_signals [CONTACT_ADDED], 0, - old_count, model->data_count - old_count); + g_ptr_array_add (array, g_object_ref (contact)); + contact_list = contact_list->next; + } + g_signal_emit (model, signals[CONTACT_ADDED], 0, index, count); update_folder_bar_message (model); } static void remove_contact(EBookView *book_view, GList *ids, - EABModel *model) + EAddressbookModel *model) { /* XXX we should keep a hash around instead of this O(n*m) loop */ - gint i = 0; - GList *l; + GList *iter; GArray *indices; + GPtrArray *array; + gint ii; + array = model->priv->contacts; indices = g_array_new (FALSE, FALSE, sizeof (gint)); - for (l = ids; l; l = l->next) { - char *id = l->data; - for ( i = 0; i < model->data_count; i++) { - if ( !strcmp(e_contact_get_const (model->data[i], E_CONTACT_UID), id) ) { - g_object_unref (model->data[i]); - memmove(model->data + i, model->data + i + 1, (model->data_count - i - 1) * sizeof (EContact *)); - model->data_count--; - g_array_append_val (indices, i); - break; + + for (iter = ids; iter != NULL; iter = iter->next) { + const gchar *target_uid = iter->data; + + for (ii = 0; ii < array->len; ii++) { + EContact *contact; + const gchar *uid; + + contact = array->pdata[ii]; + uid = e_contact_get_const (contact, E_CONTACT_UID); + if (strcmp (uid, target_uid) == 0) { + g_object_unref (contact); + g_array_append_val (indices, ii); } } } - g_signal_emit (model, - eab_model_signals [CONTACTS_REMOVED], 0, - indices); + + for (ii = 0; ii < indices->len; ii++) { + gint index; + + index = g_array_index (indices, gint, ii); + g_ptr_array_remove_index (array, index); + } + + g_signal_emit (model, signals[CONTACTS_REMOVED], 0, indices); g_array_free (indices, FALSE); + update_folder_bar_message (model); } static void modify_contact(EBookView *book_view, - const GList *contacts, - EABModel *model) -{ - for ( ; contacts; contacts = contacts->next) { - int i; - for ( i = 0; i < model->data_count; i++) { - if ( !strcmp(e_contact_get_const(model->data[i], E_CONTACT_UID), - e_contact_get_const(E_CONTACT(contacts->data), E_CONTACT_UID)) ) { - g_object_unref (model->data[i]); - model->data[i] = e_contact_duplicate(E_CONTACT(contacts->data)); - g_signal_emit (model, - eab_model_signals [CONTACT_CHANGED], 0, - i); - break; - } + const GList *contact_list, + EAddressbookModel *model) +{ + GPtrArray *array; + + array = model->priv->contacts; + + while (contact_list != NULL) { + EContact *contact = contact_list->data; + const gchar *target_uid; + gint ii; + + target_uid = e_contact_get_const (contact, E_CONTACT_UID); + + for (ii = 0; ii < array->len; ii++) { + const gchar *uid; + + uid = e_contact_get_const ( + array->pdata[ii], E_CONTACT_UID); + + if (strcmp (uid, target_uid) != 0) + continue; + + g_object_unref (array->pdata[ii]); + contact = e_contact_duplicate (contact); + array->pdata[ii] = contact; + + g_signal_emit ( + model, signals[CONTACT_CHANGED], 0, contact); + break; } + + contact_list = contact_list->next; } } static void status_message (EBookView *book_view, char* status, - EABModel *model) + EAddressbookModel *model) { - g_signal_emit (model, - eab_model_signals [STATUS_MESSAGE], 0, - status); + g_signal_emit (model, signals[STATUS_MESSAGE], 0, status); } static void sequence_complete (EBookView *book_view, - EBookViewStatus status, - EABModel *model) + EBookViewStatus status, + EAddressbookModel *model) { - model->search_in_progress = FALSE; + model->priv->search_in_progress = FALSE; status_message (book_view, NULL, model); - g_signal_emit (model, - eab_model_signals [SEARCH_RESULT], 0, - status); - g_signal_emit (model, - eab_model_signals [STOP_STATE_CHANGED], 0); + g_signal_emit (model, signals[SEARCH_RESULT], 0, status); + g_signal_emit (model, signals[STOP_STATE_CHANGED], 0); } static void writable_status (EBook *book, gboolean writable, - EABModel *model) + EAddressbookModel *model) { - if (!model->editable_set) { - model->editable = writable; + if (!model->priv->editable_set) { + model->priv->editable = writable; - g_signal_emit (model, - eab_model_signals [WRITABLE_STATUS], 0, - writable); + g_signal_emit (model, signals[WRITABLE_STATUS], 0, writable); } } static void backend_died (EBook *book, - EABModel *model) + EAddressbookModel *model) +{ + g_signal_emit (model, signals[BACKEND_DIED], 0); +} + +static void +book_view_loaded (EBook *book, + EBookStatus status, + EBookView *book_view, + gpointer closure) +{ + EAddressbookModel *model = closure; + + if (status != E_BOOK_ERROR_OK) { + eab_error_dialog (_("Error getting book view"), status); + return; + } + + remove_book_view (model); + free_data (model); + + model->priv->book_view = book_view; + if (model->priv->book_view) + g_object_ref (model->priv->book_view); + + model->priv->create_contact_id = g_signal_connect ( + model->priv->book_view, "contacts-added", + G_CALLBACK (create_contact), model); + model->priv->remove_contact_id = g_signal_connect ( + model->priv->book_view, "contacts-removed", + G_CALLBACK (remove_contact), model); + model->priv->modify_contact_id = g_signal_connect ( + model->priv->book_view, "contacts-changed", + G_CALLBACK (modify_contact), model); + model->priv->status_message_id = g_signal_connect ( + model->priv->book_view, "status-message", + G_CALLBACK (status_message), model); + model->priv->sequence_complete_id = g_signal_connect ( + model->priv->book_view, "sequence-complete", + G_CALLBACK (sequence_complete), model); + + model->priv->search_in_progress = TRUE; + g_signal_emit (model, signals[MODEL_CHANGED], 0); + g_signal_emit (model, signals[SEARCH_STARTED], 0); + g_signal_emit (model, signals[STOP_STATE_CHANGED], 0); + + e_book_view_start (model->priv->book_view); +} + +static gboolean +addressbook_model_idle_cb (EAddressbookModel *model) +{ + model->priv->book_view_idle_id = 0; + + if (model->priv->book && model->priv->query) { + ESource *source; + const char *limit_str; + int limit = -1; + + source = e_book_get_source (model->priv->book); + + limit_str = e_source_get_property (source, "limit"); + if (limit_str && *limit_str) + limit = atoi (limit_str); + + remove_book_view(model); + + if (model->priv->first_get_view) { + model->priv->first_get_view = FALSE; + + if (e_book_check_static_capability (model->priv->book, "do-initial-query")) { + e_book_async_get_book_view ( + model->priv->book, model->priv->query, + NULL, limit, book_view_loaded, model); + } else { + free_data (model); + + g_signal_emit (model, + signals[MODEL_CHANGED], 0); + g_signal_emit (model, + signals[STOP_STATE_CHANGED], 0); + } + } else + e_book_async_get_book_view ( + model->priv->book, model->priv->query, + NULL, limit, book_view_loaded, model); + + } + + g_object_unref (model); + + return FALSE; +} + +static void +addressbook_model_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id){ + case PROP_BOOK: + e_addressbook_model_set_book ( + E_ADDRESSBOOK_MODEL (object), + g_value_get_object (value)); + return; + + case PROP_EDITABLE: + e_addressbook_model_set_editable ( + E_ADDRESSBOOK_MODEL (object), + g_value_get_boolean (value)); + return; + + case PROP_QUERY: + e_addressbook_model_set_query ( + E_ADDRESSBOOK_MODEL (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + +} + +static void +addressbook_model_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_BOOK: + g_value_set_object ( + value, e_addressbook_model_get_book ( + E_ADDRESSBOOK_MODEL (object))); + return; + + case PROP_EDITABLE: + g_value_set_boolean ( + value, e_addressbook_model_get_editable ( + E_ADDRESSBOOK_MODEL (object))); + return; + + case PROP_QUERY: + g_value_take_string ( + value, e_addressbook_model_get_query ( + E_ADDRESSBOOK_MODEL (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +addressbook_model_dispose (GObject *object) { - g_signal_emit (model, - eab_model_signals [BACKEND_DIED], 0); + EAddressbookModel *model = E_ADDRESSBOOK_MODEL(object); + + remove_book_view (model); + free_data (model); + + if (model->priv->book) { + if (model->priv->writable_status_id) + g_signal_handler_disconnect ( + model->priv->book, + model->priv->writable_status_id); + model->priv->writable_status_id = 0; + + if (model->priv->backend_died_id) + g_signal_handler_disconnect ( + model->priv->book, + model->priv->backend_died_id); + model->priv->backend_died_id = 0; + + g_object_unref (model->priv->book); + model->priv->book = NULL; + } + + if (model->priv->query) { + e_book_query_unref (model->priv->query); + model->priv->query = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); } static void -eab_model_class_init (GObjectClass *object_class) -{ - parent_class = g_type_class_ref (PARENT_TYPE); - - object_class->dispose = addressbook_dispose; - object_class->set_property = eab_model_set_property; - object_class->get_property = eab_model_get_property; - - g_object_class_install_property (object_class, PROP_BOOK, - g_param_spec_object ("book", - _("Book"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_BOOK, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_QUERY, - g_param_spec_string ("query", - _("Query"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_EDITABLE, - g_param_spec_boolean ("editable", - _("Editable"), - /*_( */"XXX blurb" /*)*/, - FALSE, - G_PARAM_READWRITE)); - - eab_model_signals [WRITABLE_STATUS] = +addressbook_model_finalize (GObject *object) +{ + EAddressbookModelPrivate *priv; + + priv = E_ADDRESSBOOK_MODEL_GET_PRIVATE (object); + + g_ptr_array_free (priv->contacts, TRUE); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +addressbook_model_class_init (EAddressbookModelClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EAddressbookModelPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = addressbook_model_set_property; + object_class->get_property = addressbook_model_get_property; + object_class->dispose = addressbook_model_dispose; + object_class->finalize = addressbook_model_finalize; + + g_object_class_install_property ( + object_class, + PROP_BOOK, + g_param_spec_object ( + "book", + _("Book"), + NULL, + E_TYPE_BOOK, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_EDITABLE, + g_param_spec_boolean ( + "editable", + _("Editable"), + NULL, + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_QUERY, + g_param_spec_string ( + "query", + _("Query"), + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + signals[WRITABLE_STATUS] = g_signal_new ("writable_status", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, writable_status), + G_STRUCT_OFFSET (EAddressbookModelClass, writable_status), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); - eab_model_signals [STATUS_MESSAGE] = + signals[STATUS_MESSAGE] = g_signal_new ("status_message", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, status_message), + G_STRUCT_OFFSET (EAddressbookModelClass, status_message), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - eab_model_signals [SEARCH_STARTED] = + signals[SEARCH_STARTED] = g_signal_new ("search_started", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, search_started), + G_STRUCT_OFFSET (EAddressbookModelClass, search_started), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - eab_model_signals [SEARCH_RESULT] = + signals[SEARCH_RESULT] = g_signal_new ("search_result", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, search_result), + G_STRUCT_OFFSET (EAddressbookModelClass, search_result), NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); - eab_model_signals [FOLDER_BAR_MESSAGE] = + signals[FOLDER_BAR_MESSAGE] = g_signal_new ("folder_bar_message", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, folder_bar_message), + G_STRUCT_OFFSET (EAddressbookModelClass, folder_bar_message), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - eab_model_signals [CONTACT_ADDED] = + signals[CONTACT_ADDED] = g_signal_new ("contact_added", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, contact_added), + G_STRUCT_OFFSET (EAddressbookModelClass, contact_added), NULL, NULL, e_marshal_NONE__INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); - eab_model_signals [CONTACTS_REMOVED] = + signals[CONTACTS_REMOVED] = g_signal_new ("contacts_removed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, contacts_removed), + G_STRUCT_OFFSET (EAddressbookModelClass, contacts_removed), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - eab_model_signals [CONTACT_CHANGED] = + signals[CONTACT_CHANGED] = g_signal_new ("contact_changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, contact_changed), + G_STRUCT_OFFSET (EAddressbookModelClass, contact_changed), NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, E_TYPE_CONTACT); - eab_model_signals [MODEL_CHANGED] = + signals[MODEL_CHANGED] = g_signal_new ("model_changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, model_changed), + G_STRUCT_OFFSET (EAddressbookModelClass, model_changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - eab_model_signals [STOP_STATE_CHANGED] = + signals[STOP_STATE_CHANGED] = g_signal_new ("stop_state_changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, stop_state_changed), + G_STRUCT_OFFSET (EAddressbookModelClass, stop_state_changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - eab_model_signals [BACKEND_DIED] = + signals[BACKEND_DIED] = g_signal_new ("backend_died", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, backend_died), + G_STRUCT_OFFSET (EAddressbookModelClass, backend_died), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void -eab_model_init (GObject *object) -{ - EABModel *model = EAB_MODEL(object); - model->book = NULL; - model->query = e_book_query_any_field_contains (""); - model->book_view = NULL; - model->create_contact_id = 0; - model->remove_contact_id = 0; - model->modify_contact_id = 0; - model->status_message_id = 0; - model->writable_status_id = 0; - model->backend_died_id = 0; - model->sequence_complete_id = 0; - model->data = NULL; - model->data_count = 0; - model->allocated_count = 0; - model->search_in_progress = FALSE; - model->editable = FALSE; - model->editable_set = FALSE; - model->first_get_view = TRUE; +addressbook_model_init (EAddressbookModel *model) +{ + model->priv = E_ADDRESSBOOK_MODEL_GET_PRIVATE (model); + + model->priv->contacts = g_ptr_array_new (); + model->priv->first_get_view = TRUE; } -static void -book_view_loaded (EBook *book, EBookStatus status, EBookView *book_view, gpointer closure) +GType +e_addressbook_model_get_type (void) { - EABModel *model = closure; + static GType type = 0; - if (status != E_BOOK_ERROR_OK) { - eab_error_dialog (_("Error getting book view"), status); - return; + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EAddressbookModelClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) addressbook_model_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EAddressbookModel), + 0, /* n_preallocs */ + (GInstanceInitFunc) addressbook_model_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + G_TYPE_OBJECT, "EAddressbookModel", &type_info, 0); } - remove_book_view (model); - free_data (model); + return type; +} - model->book_view = book_view; - if (model->book_view) - g_object_ref (model->book_view); - model->create_contact_id = g_signal_connect(model->book_view, - "contacts_added", - G_CALLBACK (create_contact), - model); - model->remove_contact_id = g_signal_connect(model->book_view, - "contacts_removed", - G_CALLBACK (remove_contact), - model); - model->modify_contact_id = g_signal_connect(model->book_view, - "contacts_changed", - G_CALLBACK(modify_contact), - model); - model->status_message_id = g_signal_connect(model->book_view, - "status_message", - G_CALLBACK(status_message), - model); - model->sequence_complete_id = g_signal_connect(model->book_view, - "sequence_complete", - G_CALLBACK(sequence_complete), - model); - - model->search_in_progress = TRUE; - g_signal_emit (model, - eab_model_signals [MODEL_CHANGED], 0); - g_signal_emit (model, - eab_model_signals [SEARCH_STARTED], 0); - g_signal_emit (model, - eab_model_signals [STOP_STATE_CHANGED], 0); - - e_book_view_start (model->book_view); +EAddressbookModel* +e_addressbook_model_new (void) +{ + return g_object_new (E_TYPE_ADDRESSBOOK_MODEL, NULL); } -static void -get_view (EABModel *model) +EContact * +e_addressbook_model_get_contact (EAddressbookModel *model, + gint row) { - /* Should this be checked somehow? */ - gboolean success; + GPtrArray *array; - if (model->book && model->query) { - ESource *source; - const char *limit_str; - int limit = -1; + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), NULL); - source = e_book_get_source (model->book); + array = model->priv->contacts; - limit_str = e_source_get_property (source, "limit"); - if (limit_str && *limit_str) - limit = atoi (limit_str); + if (0 <= row && row < array->len) + return e_contact_duplicate (array->pdata[row]); - remove_book_view(model); + return NULL; +} - if (model->first_get_view) { - model->first_get_view = FALSE; +void +e_addressbook_model_stop (EAddressbookModel *model) +{ + const gchar *message; - if (e_book_check_static_capability (model->book, "do-initial-query")) { - success = e_book_async_get_book_view (model->book, model->query, NULL, limit, book_view_loaded, model); - } else { - free_data (model); + g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model)); - g_signal_emit (model, - eab_model_signals [MODEL_CHANGED], 0); - g_signal_emit (model, - eab_model_signals [STOP_STATE_CHANGED], 0); - return; - } - } - else - success = e_book_async_get_book_view (model->book, model->query, NULL, limit, book_view_loaded, model); + remove_book_view (model); - } + message = _("Search Interrupted"); + g_signal_emit (model, signals[STOP_STATE_CHANGED], 0); + g_signal_emit (model, signals[STATUS_MESSAGE], 0, message); } -static gboolean -get_view_idle (EABModel *model) +gboolean +e_addressbook_model_can_stop (EAddressbookModel *model) { - model->book_view_idle_id = 0; - get_view (model); - g_object_unref (model); - return FALSE; -} + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), FALSE); + return model->priv->search_in_progress; +} -EContact * -eab_model_get_contact(EABModel *model, - int row) +void +e_addressbook_model_force_folder_bar_message (EAddressbookModel *model) { - if (model->data && 0 <= row && row < model->data_count) { - return e_contact_duplicate (model->data[row]); - } - return NULL; + g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model)); + + update_folder_bar_message (model); } -static void -eab_model_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +gint +e_addressbook_model_contact_count (EAddressbookModel *model) { - EABModel *model; - gboolean need_get_book_view = FALSE; + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), 0); - model = EAB_MODEL (object); + return model->priv->contacts->len; +} - switch (prop_id){ - case PROP_BOOK: - if (model->book) { - if (model->writable_status_id) - g_signal_handler_disconnect (model->book, - model->writable_status_id); - model->writable_status_id = 0; +EContact * +e_addressbook_model_contact_at (EAddressbookModel *model, + gint index) +{ + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), NULL); - if (model->backend_died_id) - g_signal_handler_disconnect (model->book, - model->backend_died_id); - model->backend_died_id = 0; + return model->priv->contacts->pdata[index]; +} - g_object_unref (model->book); - } - model->book = E_BOOK(g_value_get_object (value)); - if (model->book) { - model->writable_status_id = - g_signal_connect (model->book, - "writable_status", - G_CALLBACK (writable_status), model); - model->backend_died_id = - g_signal_connect (model->book, - "backend_died", - G_CALLBACK (backend_died), model); - - if (!model->editable_set) { - model->editable = e_book_is_writable (model->book); +gint +e_addressbook_model_find (EAddressbookModel *model, + EContact *contact) +{ + GPtrArray *array; + gint ii; - g_signal_emit (model, - eab_model_signals [WRITABLE_STATUS], 0, - model->editable); - } + /* XXX This searches for a particular EContact instance, + * as opposed to an equivalent but possibly different + * EContact instance. Might have to revise this in + * the future. */ - model->first_get_view = TRUE; - g_object_ref (model->book); - need_get_book_view = TRUE; - } - break; - case PROP_QUERY: - if (model->query) - e_book_query_unref (model->query); - model->query = e_book_query_from_string (g_value_get_string (value)); - need_get_book_view = TRUE; - break; - case PROP_EDITABLE: - model->editable = g_value_get_boolean (value); - model->editable_set = TRUE; - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), -1); + g_return_val_if_fail (E_IS_CONTACT (contact), -1); - if (need_get_book_view) { - if (!model->book_view_idle_id) { - g_object_ref (model); - model->book_view_idle_id = g_idle_add ((GSourceFunc)get_view_idle, model); - } + array = model->priv->contacts; + for (ii = 0; ii < array->len; ii++) { + EContact *candidate = array->pdata[ii]; + + if (contact == candidate) + return ii; } + return -1; } -static void -eab_model_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +EBook * +e_addressbook_model_get_book (EAddressbookModel *model) { - EABModel *eab_model; - - eab_model = EAB_MODEL (object); + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), NULL); - switch (prop_id) { - case PROP_BOOK: - g_value_set_object (value, eab_model->book); - break; - case PROP_QUERY: { - char *query_string = e_book_query_to_string (eab_model->query); - g_value_set_string (value, query_string); - break; - } - case PROP_EDITABLE: - g_value_set_boolean (value, eab_model->editable); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + return model->priv->book; } -GType -eab_model_get_type (void) +void +e_addressbook_model_set_book (EAddressbookModel *model, + EBook *book) { - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof (EABModelClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) eab_model_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (EABModel), - 0, /* n_preallocs */ - (GInstanceInitFunc) eab_model_init, - }; - - type = g_type_register_static (PARENT_TYPE, "EABModel", &info, 0); + g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model)); + g_return_if_fail (E_IS_BOOK (book)); + + if (model->priv->book != NULL) { + if (model->priv->writable_status_id != 0) + g_signal_handler_disconnect ( + model->priv->book, + model->priv->writable_status_id); + model->priv->writable_status_id = 0; + + if (model->priv->backend_died_id != 0) + g_signal_handler_disconnect ( + model->priv->book, + model->priv->backend_died_id); + model->priv->backend_died_id = 0; + + g_object_unref (model->priv->book); } - return type; -} + model->priv->book = g_object_ref (book); + model->priv->first_get_view = TRUE; -EABModel* -eab_model_new (void) -{ - EABModel *et; + model->priv->writable_status_id = g_signal_connect ( + book, "writable-status", + G_CALLBACK (writable_status), model); - et = g_object_new (EAB_TYPE_MODEL, NULL); + model->priv->backend_died_id = g_signal_connect ( + book, "backend-died", + G_CALLBACK (backend_died), model); - return et; -} + if (!model->priv->editable_set) { + model->priv->editable = e_book_is_writable (book); + g_signal_emit ( + model, signals[WRITABLE_STATUS], 0, + model->priv->editable); + } -void eab_model_stop (EABModel *model) -{ - remove_book_view(model); - g_signal_emit (model, - eab_model_signals [STOP_STATE_CHANGED], 0); - g_signal_emit (model, - eab_model_signals [STATUS_MESSAGE], 0, - "Search Interrupted."); + if (model->priv->book_view_idle_id == 0) + model->priv->book_view_idle_id = g_idle_add ( + (GSourceFunc) addressbook_model_idle_cb, + g_object_ref (model)); + + g_object_notify (G_OBJECT (model), "book"); } gboolean -eab_model_can_stop (EABModel *model) +e_addressbook_model_get_editable (EAddressbookModel *model) { - return model->search_in_progress; + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), FALSE); + + return model->priv->editable; } void -eab_model_force_folder_bar_message (EABModel *model) +e_addressbook_model_set_editable (EAddressbookModel *model, + gboolean editable) { - update_folder_bar_message (model); -} + g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model)); -int -eab_model_contact_count (EABModel *model) -{ - return model->data_count; -} + model->priv->editable = editable; + model->priv->editable_set = TRUE; -const EContact * -eab_model_contact_at (EABModel *model, int index) -{ - return model->data[index]; + g_object_notify (G_OBJECT (model), "editable"); } -gboolean -eab_model_editable (EABModel *model) +gchar * +e_addressbook_model_get_query (EAddressbookModel *model) { - return model->editable; + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), NULL); + + return e_book_query_to_string (model->priv->query); } -EBook * -eab_model_get_ebook (EABModel *model) +void +e_addressbook_model_set_query (EAddressbookModel *model, + const gchar *query) { - return model->book; + g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model)); + + if (model->priv->query != NULL) + e_book_query_unref (model->priv->query); + + if (query == NULL) + model->priv->query = e_book_query_any_field_contains (""); + else + model->priv->query = e_book_query_from_string (query); + + if (model->priv->book_view_idle_id == 0) + model->priv->book_view_idle_id = g_idle_add ( + (GSourceFunc) addressbook_model_idle_cb, + g_object_ref (model)); + + g_object_notify (G_OBJECT (model), "query"); } diff --git a/addressbook/gui/widgets/e-addressbook-model.h b/addressbook/gui/widgets/e-addressbook-model.h index 6558d94812..1a7be828f6 100644 --- a/addressbook/gui/widgets/e-addressbook-model.h +++ b/addressbook/gui/widgets/e-addressbook-model.h @@ -18,84 +18,99 @@ * */ -#ifndef _EAB_MODEL_H_ -#define _EAB_MODEL_H_ +#ifndef E_ADDRESSBOOK_MODEL_H +#define E_ADDRESSBOOK_MODEL_H -#include <glib.h> -#include <glib-object.h> #include <libebook/e-book.h> +#include <libebook/e-book-query.h> #include <libebook/e-book-view.h> -#define EAB_TYPE_MODEL (eab_model_get_type ()) -#define EAB_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EAB_TYPE_MODEL, EABModel)) -#define EAB_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EAB_TYPE_MODEL, EABModelClass)) -#define E_IS_ADDRESSBOOK_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EAB_TYPE_MODEL)) -#define E_IS_ADDRESSBOOK_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EAB_TYPE_MODEL)) - -typedef struct _EABModel EABModel; -typedef struct _EABModelClass EABModelClass; - -struct _EABModel { +/* Standard GObject macros */ +#define E_TYPE_ADDRESSBOOK_MODEL \ + (e_addressbook_model_get_type ()) +#define E_ADDRESSBOOK_MODEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_ADDRESSBOOK_MODEL, EAddressbookModel)) +#define E_ADDRESSBOOK_MODEL_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_ADDRESSBOOK_MODEL, EAddressbookModelClass)) +#define E_IS_ADDRESSBOOK_MODEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_ADDRESSBOOK_MODEL)) +#define E_IS_ADDRESSBOOK_MODEL_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_ADDRESSBOOK_MODEL)) +#define E_ADDRESSBOOK_MODEL_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_ADDRESSBOOK_MODEL)) + +G_BEGIN_DECLS + +typedef struct _EAddressbookModel EAddressbookModel; +typedef struct _EAddressbookModelClass EAddressbookModelClass; +typedef struct _EAddressbookModelPrivate EAddressbookModelPrivate; + +struct _EAddressbookModel { GObject parent; - - /* item specific fields */ - EBook *book; - EBookQuery *query; - EBookView *book_view; - - int book_view_idle_id; - - EContact **data; - int data_count; - int allocated_count; - - int create_contact_id, remove_contact_id, modify_contact_id; - int status_message_id, writable_status_id, sequence_complete_id; - int backend_died_id; - - guint search_in_progress : 1; - guint editable : 1; - guint editable_set : 1; - guint first_get_view : 1; + EAddressbookModelPrivate *priv; }; -struct _EABModelClass { +struct _EAddressbookModelClass { GObjectClass parent_class; - /* - * Signals - */ - void (*writable_status) (EABModel *model, gboolean writable); - void (*search_started) (EABModel *model); - void (*search_result) (EABModel *model, EBookViewStatus status); - void (*status_message) (EABModel *model, const gchar *message); - void (*folder_bar_message) (EABModel *model, const gchar *message); - void (*contact_added) (EABModel *model, gint index, gint count); - void (*contacts_removed) (EABModel *model, gpointer id_list); - void (*contact_changed) (EABModel *model, gint index); - void (*model_changed) (EABModel *model); - void (*stop_state_changed) (EABModel *model); - void (*backend_died) (EABModel *model); + /* Signals */ + void (*writable_status) (EAddressbookModel *model, + gboolean writable); + void (*search_started) (EAddressbookModel *model); + void (*search_result) (EAddressbookModel *model, + EBookViewStatus status); + void (*status_message) (EAddressbookModel *model, + const gchar *message); + void (*folder_bar_message) (EAddressbookModel *model, + const gchar *message); + void (*contact_added) (EAddressbookModel *model, + gint index, + gint count); + void (*contacts_removed) (EAddressbookModel *model, + gpointer id_list); + void (*contact_changed) (EAddressbookModel *model, + EContact *contact); + void (*model_changed) (EAddressbookModel *model); + void (*stop_state_changed) (EAddressbookModel *model); + void (*backend_died) (EAddressbookModel *model); }; - -GType eab_model_get_type (void); -EABModel *eab_model_new (void); +GType e_addressbook_model_get_type (void); +EAddressbookModel * + e_addressbook_model_new (void); /* Returns object with ref count of 1. */ -EContact *eab_model_get_contact (EABModel *model, - int row); -EBook *eab_model_get_ebook (EABModel *model); - -void eab_model_stop (EABModel *model); -gboolean eab_model_can_stop (EABModel *model); - -void eab_model_force_folder_bar_message (EABModel *model); - -int eab_model_contact_count (EABModel *model); -const EContact *eab_model_contact_at (EABModel *model, - int index); -gboolean eab_model_editable (EABModel *model); - -#endif /* _EAB_MODEL_H_ */ +EContact * e_addressbook_model_get_contact (EAddressbookModel *model, + gint row); + +void e_addressbook_model_stop (EAddressbookModel *model); +gboolean e_addressbook_model_can_stop (EAddressbookModel *model); + +void e_addressbook_model_force_folder_bar_message + (EAddressbookModel *model); + +gint e_addressbook_model_contact_count + (EAddressbookModel *model); +EContact * e_addressbook_model_contact_at (EAddressbookModel *model, + gint index); +gint e_addressbook_model_find (EAddressbookModel *model, + EContact *contact); +EBook * e_addressbook_model_get_book (EAddressbookModel *model); +void e_addressbook_model_set_book (EAddressbookModel *model, + EBook *book); +gboolean e_addressbook_model_get_editable(EAddressbookModel *model); +void e_addressbook_model_set_editable(EAddressbookModel *model, + gboolean editable); +gchar * e_addressbook_model_get_query (EAddressbookModel *model); +void e_addressbook_model_set_query (EAddressbookModel *model, + const gchar *query); + +G_END_DECLS + +#endif /* E_ADDRESSBOOK_MODEL_H */ diff --git a/addressbook/gui/widgets/e-addressbook-reflow-adapter.c b/addressbook/gui/widgets/e-addressbook-reflow-adapter.c index 1f2b1aad7a..2a2f1a2d87 100644 --- a/addressbook/gui/widgets/e-addressbook-reflow-adapter.c +++ b/addressbook/gui/widgets/e-addressbook-reflow-adapter.c @@ -20,19 +20,18 @@ #include <string.h> #include <glib/gi18n.h> -#include "e-util/e-util.h" #include "e-addressbook-reflow-adapter.h" #include "e-addressbook-model.h" -#include "e-addressbook-view.h" #include "eab-gui-util.h" #include "e-minicard.h" +#include <e-util/e-util.h> #include <misc/e-gui-utils.h> #include "addressbook/printing/e-contact-print.h" struct _EAddressbookReflowAdapterPrivate { - EABModel *model; + EAddressbookModel *model; gboolean loading; @@ -55,10 +54,11 @@ enum { enum { DRAG_BEGIN, + OPEN_CONTACT, LAST_SIGNAL }; -static guint e_addressbook_reflow_adapter_signals [LAST_SIGNAL] = {0, }; +static guint signals [LAST_SIGNAL] = {0, }; static void unlink_model(EAddressbookReflowAdapter *adapter) @@ -130,7 +130,7 @@ addressbook_count (EReflowModel *erm) EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER(erm); EAddressbookReflowAdapterPrivate *priv = adapter->priv; - return eab_model_contact_count (priv->model); + return e_addressbook_model_contact_count (priv->model); } /* This function returns the height of the minicontact in question */ @@ -142,7 +142,7 @@ addressbook_height (EReflowModel *erm, int i, GnomeCanvasGroup *parent) EContactField field; int count = 0; char *string; - EContact *contact = (EContact*)eab_model_contact_at (priv->model, i); + EContact *contact = (EContact*)e_addressbook_model_contact_at (priv->model, i); PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET (GNOME_CANVAS_ITEM (parent)->canvas), ""); int height; @@ -191,8 +191,8 @@ addressbook_compare (EReflowModel *erm, int n1, int n2) return n1-n2; } else { - contact1 = (EContact*)eab_model_contact_at (priv->model, n1); - contact2 = (EContact*)eab_model_contact_at (priv->model, n2); + contact1 = (EContact*)e_addressbook_model_contact_at (priv->model, n1); + contact2 = (EContact*)e_addressbook_model_contact_at (priv->model, n2); if (contact1 && contact2) { const char *file_as1, *file_as2; @@ -228,12 +228,20 @@ adapter_drag_begin (EMinicard *card, GdkEvent *event, EAddressbookReflowAdapter gint ret_val = 0; g_signal_emit (adapter, - e_addressbook_reflow_adapter_signals[DRAG_BEGIN], 0, + signals[DRAG_BEGIN], 0, event, &ret_val); return ret_val; } +static void +adapter_open_contact (EMinicard *card, + EContact *contact, + EAddressbookReflowAdapter *adapter) +{ + g_signal_emit (adapter, signals[OPEN_CONTACT], 0, contact); +} + static GnomeCanvasItem * addressbook_incarnate (EReflowModel *erm, int i, GnomeCanvasGroup *parent) { @@ -243,8 +251,8 @@ addressbook_incarnate (EReflowModel *erm, int i, GnomeCanvasGroup *parent) item = gnome_canvas_item_new(parent, e_minicard_get_type(), - "contact", eab_model_contact_at (priv->model, i), - "editable", eab_model_editable (priv->model), + "contact", e_addressbook_model_contact_at (priv->model, i), + "editable", e_addressbook_model_get_editable (priv->model), NULL); #if 0 @@ -253,7 +261,10 @@ addressbook_incarnate (EReflowModel *erm, int i, GnomeCanvasGroup *parent) #endif g_signal_connect (item, "drag_begin", - G_CALLBACK(adapter_drag_begin), adapter); + G_CALLBACK (adapter_drag_begin), adapter); + + g_signal_connect (item, "open-contact", + G_CALLBACK (adapter_open_contact), adapter); return item; } @@ -265,12 +276,12 @@ addressbook_reincarnate (EReflowModel *erm, int i, GnomeCanvasItem *item) EAddressbookReflowAdapterPrivate *priv = adapter->priv; gnome_canvas_item_set(item, - "contact", eab_model_contact_at (priv->model, i), + "contact", e_addressbook_model_contact_at (priv->model, i), NULL); } static void -create_contact (EABModel *model, +create_contact (EAddressbookModel *model, gint index, gint count, EAddressbookReflowAdapter *adapter) { @@ -280,7 +291,7 @@ create_contact (EABModel *model, } static void -remove_contacts (EABModel *model, +remove_contacts (EAddressbookModel *model, gpointer data, EAddressbookReflowAdapter *adapter) { @@ -295,7 +306,7 @@ remove_contacts (EABModel *model, } static void -modify_contact (EABModel *model, +modify_contact (EAddressbookModel *model, gint index, EAddressbookReflowAdapter *adapter) { @@ -303,14 +314,14 @@ modify_contact (EABModel *model, } static void -model_changed (EABModel *model, +model_changed (EAddressbookModel *model, EAddressbookReflowAdapter *adapter) { e_reflow_model_changed (E_REFLOW_MODEL (adapter)); } static void -search_started (EABModel *model, +search_started (EAddressbookModel *model, EAddressbookReflowAdapter *adapter) { EAddressbookReflowAdapterPrivate *priv = adapter->priv; @@ -319,7 +330,7 @@ search_started (EABModel *model, } static void -search_result (EABModel *model, +search_result (EAddressbookModel *model, EBookViewStatus status, EAddressbookReflowAdapter *adapter) { @@ -425,10 +436,10 @@ e_addressbook_reflow_adapter_class_init (GObjectClass *object_class) g_param_spec_object ("model", _("Model"), /*_( */"XXX blurb" /*)*/, - EAB_TYPE_MODEL, + E_TYPE_ADDRESSBOOK_MODEL, G_PARAM_READABLE)); - e_addressbook_reflow_adapter_signals [DRAG_BEGIN] = + signals [DRAG_BEGIN] = g_signal_new ("drag_begin", G_OBJECT_CLASS_TYPE(object_class), G_SIGNAL_RUN_LAST, @@ -437,6 +448,16 @@ e_addressbook_reflow_adapter_class_init (GObjectClass *object_class) e_marshal_INT__POINTER, G_TYPE_INT, 1, G_TYPE_POINTER); + signals [OPEN_CONTACT] = + g_signal_new ("open-contact", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EAddressbookReflowAdapterClass, open_contact), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + E_TYPE_CONTACT); + model_class->set_width = addressbook_set_width; model_class->count = addressbook_count; model_class->height = addressbook_height; @@ -488,7 +509,7 @@ e_addressbook_reflow_adapter_get_type (void) void e_addressbook_reflow_adapter_construct (EAddressbookReflowAdapter *adapter, - EABModel *model) + EAddressbookModel *model) { EAddressbookReflowAdapterPrivate *priv = adapter->priv; @@ -522,7 +543,7 @@ e_addressbook_reflow_adapter_construct (EAddressbookReflowAdapter *adapter, } EReflowModel * -e_addressbook_reflow_adapter_new (EABModel *model) +e_addressbook_reflow_adapter_new (EAddressbookModel *model) { EAddressbookReflowAdapter *et; @@ -540,5 +561,5 @@ e_addressbook_reflow_adapter_get_contact (EAddressbookReflowAdapter *adapter, { EAddressbookReflowAdapterPrivate *priv = adapter->priv; - return eab_model_get_contact (priv->model, index); + return e_addressbook_model_get_contact (priv->model, index); } diff --git a/addressbook/gui/widgets/e-addressbook-reflow-adapter.h b/addressbook/gui/widgets/e-addressbook-reflow-adapter.h index fd7842684f..5032f3e2d0 100644 --- a/addressbook/gui/widgets/e-addressbook-reflow-adapter.h +++ b/addressbook/gui/widgets/e-addressbook-reflow-adapter.h @@ -48,14 +48,17 @@ struct _EAddressbookReflowAdapterClass { /* * Signals */ - gint (* drag_begin) (EAddressbookReflowAdapter *adapter, GdkEvent *event); + gint (*drag_begin) (EAddressbookReflowAdapter *adapter, + GdkEvent *event); + void (*open_contact) (EAddressbookReflowAdapter *adapter, + EContact *contact); }; GType e_addressbook_reflow_adapter_get_type (void); void e_addressbook_reflow_adapter_construct (EAddressbookReflowAdapter *adapter, - EABModel *model); -EReflowModel *e_addressbook_reflow_adapter_new (EABModel *model); + EAddressbookModel *model); +EReflowModel *e_addressbook_reflow_adapter_new (EAddressbookModel *model); /* Returns object with ref count of 1. */ EContact *e_addressbook_reflow_adapter_get_contact (EAddressbookReflowAdapter *adapter, diff --git a/addressbook/gui/widgets/e-addressbook-selector.c b/addressbook/gui/widgets/e-addressbook-selector.c new file mode 100644 index 0000000000..e7bec99ba2 --- /dev/null +++ b/addressbook/gui/widgets/e-addressbook-selector.c @@ -0,0 +1,443 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-addressbook-selector.c + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU 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 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 "e-addressbook-selector.h" + +#include <eab-book-util.h> +#include <eab-contact-merging.h> + +#define E_ADDRESSBOOK_SELECTOR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_ADDRESSBOOK_SELECTOR, EAddressbookSelectorPrivate)) + +#define PRIMARY_ADDRESSBOOK_KEY \ + "/apps/evolution/addressbook/display/primary_addressbook" + +typedef struct _MergeContext MergeContext; + +struct _EAddressbookSelectorPrivate { + EAddressbookView *current_view; +}; + +struct _MergeContext { + EBook *source_book; + EBook *target_book; + + EContact *current_contact; + GList *remaining_contacts; + guint pending_removals; + + gint remove_from_source : 1; + gint copy_done : 1; +}; + +enum { + PROP_0, + PROP_CURRENT_VIEW +}; + +enum { + DND_TARGET_TYPE_VCARD, + DND_TARGET_TYPE_SOURCE_VCARD +}; + +static GtkTargetEntry drag_types[] = { + { "text/x-vcard", 0, DND_TARGET_TYPE_VCARD }, + { "text/x-source-vcard", 0, DND_TARGET_TYPE_SOURCE_VCARD } +}; + +static gpointer parent_class; + +static void +merge_context_next (MergeContext *merge_context) +{ + GList *list; + + list = merge_context->remaining_contacts; + merge_context->current_contact = list->data; + list = g_list_delete_link (list, list); + merge_context->remaining_contacts = list; +} + +static MergeContext * +merge_context_new (EBook *source_book, + EBook *target_book, + GList *contact_list) +{ + MergeContext *merge_context; + + merge_context = g_slice_new0 (MergeContext); + merge_context->source_book = source_book; + merge_context->target_book = target_book; + merge_context->remaining_contacts = contact_list; + merge_context_next (merge_context); + + return merge_context; +} + +static void +merge_context_free (MergeContext *merge_context) +{ + if (merge_context->source_book != NULL) + g_object_unref (merge_context->source_book); + + if (merge_context->target_book != NULL) + g_object_unref (merge_context->target_book); + + g_slice_free (MergeContext, merge_context); +} + +static void +addressbook_selector_removed_cb (EBook *book, + EBookStatus status, + MergeContext *merge_context) +{ + merge_context->pending_removals--; + + if (merge_context->remaining_contacts != NULL) + return; + + if (merge_context->pending_removals > 0) + return; + + merge_context_free (merge_context); +} + +static void +addressbook_selector_merge_next_cb (EBook *book, + EBookStatus status, + const gchar *id, + MergeContext *merge_context) +{ + if (merge_context->remove_from_source && status == E_BOOK_ERROR_OK) { + /* Remove previous contact from source. */ + e_book_async_remove_contact ( + merge_context->source_book, + merge_context->current_contact, + (EBookCallback) addressbook_selector_removed_cb, + merge_context); + merge_context->pending_removals++; + } + + g_object_unref (merge_context->current_contact); + + if (merge_context->remaining_contacts != NULL) { + merge_context_next (merge_context); + eab_merging_book_add_contact ( + merge_context->target_book, + merge_context->current_contact, + (EBookIdCallback) addressbook_selector_merge_next_cb, + merge_context); + + } else if (merge_context->pending_removals == 0) + merge_context_free (merge_context); +} + +static void +addressbook_selector_load_primary_source (ESourceSelector *selector) +{ + GConfClient *client; + ESourceList *source_list; + ESource *source = NULL; + const gchar *key; + gchar *uid; + + /* XXX If ESourceSelector had a "primary-uid" property, + * we could just bind the GConf key to it. */ + + source_list = e_source_selector_get_source_list (selector); + + client = gconf_client_get_default (); + key = PRIMARY_ADDRESSBOOK_KEY; + uid = gconf_client_get_string (client, key, NULL); + g_object_unref (client); + + if (uid != NULL) { + source = e_source_list_peek_source_by_uid (source_list, uid); + g_free (uid); + } else { + GSList *groups; + + /* Dig up the first source in the source list. + * XXX libedataserver should provide API for this. */ + groups = e_source_list_peek_groups (source_list); + while (groups != NULL) { + ESourceGroup *source_group = groups->data; + GSList *sources; + + sources = e_source_group_peek_sources (source_group); + if (sources != NULL) { + source = sources->data; + break; + } + + groups = g_slist_next (groups); + } + } + + if (source != NULL) + e_source_selector_set_primary_selection (selector, source); +} + +static void +addressbook_selector_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CURRENT_VIEW: + e_addressbook_selector_set_current_view ( + E_ADDRESSBOOK_SELECTOR (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +addressbook_selector_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CURRENT_VIEW: + g_value_set_object ( + value, + e_addressbook_selector_get_current_view ( + E_ADDRESSBOOK_SELECTOR (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +addressbook_selector_dispose (GObject *object) +{ + EAddressbookSelectorPrivate *priv; + + priv = E_ADDRESSBOOK_SELECTOR_GET_PRIVATE (object); + + if (priv->current_view != NULL) { + g_object_unref (priv->current_view); + priv->current_view = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +addressbook_selector_constructed (GObject *object) +{ + ESourceSelector *selector; + + selector = E_SOURCE_SELECTOR (object); + addressbook_selector_load_primary_source (selector); +} + +static void +addressbook_selector_primary_selection_changed (ESourceSelector *selector) +{ + ESource *source; + GConfClient *client; + const gchar *key; + const gchar *string; + + /* XXX If ESourceSelector had a "primary-uid" property, + * we could just bind the GConf key to it. */ + + source = e_source_selector_peek_primary_selection (selector); + if (source == NULL) + return; + + client = gconf_client_get_default (); + key = PRIMARY_ADDRESSBOOK_KEY; + string = e_source_peek_uid (source); + gconf_client_set_string (client, key, string, NULL); + g_object_unref (client); +} + +static gboolean +addressbook_selector_data_dropped (ESourceSelector *selector, + GtkSelectionData *selection_data, + ESource *destination, + GdkDragAction action, + guint info) +{ + EAddressbookSelectorPrivate *priv; + MergeContext *merge_context; + EAddressbookModel *model; + EBook *source_book; + EBook *target_book; + GList *list; + const gchar *string; + gboolean remove_from_source; + + priv = E_ADDRESSBOOK_SELECTOR_GET_PRIVATE (selector); + g_return_val_if_fail (priv->current_view != NULL, FALSE); + + string = (const gchar *) selection_data->data; + remove_from_source = (action == GDK_ACTION_MOVE); + + target_book = e_book_new (destination, NULL); + if (target_book == NULL) + return FALSE; + + e_book_open (target_book, FALSE, NULL); + + /* XXX Function assumes both out arguments are provided. All we + * care about is the contact list; source_book will be NULL. */ + eab_book_and_contact_list_from_string (string, &source_book, &list); + if (list == NULL) + return FALSE; + + model = e_addressbook_view_get_model (priv->current_view); + source_book = e_addressbook_model_get_book (model); + g_return_val_if_fail (E_IS_BOOK (source_book), FALSE); + + merge_context = merge_context_new (source_book, target_book, list); + merge_context->remove_from_source = remove_from_source; + + eab_merging_book_add_contact ( + target_book, merge_context->current_contact, + (EBookIdCallback) addressbook_selector_merge_next_cb, + merge_context); + + return TRUE; +} + +static void +addressbook_selector_class_init (EAddressbookSelectorClass *class) +{ + GObjectClass *object_class; + ESourceSelectorClass *selector_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EAddressbookSelectorPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = addressbook_selector_set_property; + object_class->get_property = addressbook_selector_get_property; + object_class->dispose = addressbook_selector_dispose; + object_class->constructed = addressbook_selector_constructed; + + selector_class = E_SOURCE_SELECTOR_CLASS (class); + selector_class->primary_selection_changed = + addressbook_selector_primary_selection_changed; + selector_class->data_dropped = addressbook_selector_data_dropped; + + g_object_class_install_property ( + object_class, + PROP_CURRENT_VIEW, + g_param_spec_object ( + "current-view", + NULL, + NULL, + E_TYPE_ADDRESSBOOK_VIEW, + G_PARAM_READWRITE)); +} + +static void +addressbook_selector_init (EAddressbookSelector *selector) +{ + selector->priv = E_ADDRESSBOOK_SELECTOR_GET_PRIVATE (selector); + + gtk_drag_dest_set ( + GTK_WIDGET (selector), GTK_DEST_DEFAULT_ALL, + drag_types, G_N_ELEMENTS (drag_types), + GDK_ACTION_COPY | GDK_ACTION_MOVE); +} + +GType +e_addressbook_selector_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + const GTypeInfo type_info = { + sizeof (EAddressbookSelectorClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) addressbook_selector_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EAddressbookSelector), + 0, /* n_preallocs */ + (GInstanceInitFunc) addressbook_selector_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + E_TYPE_SOURCE_SELECTOR, "EAddressbookSelector", + &type_info, 0); + } + + return type; +} + +GtkWidget * +e_addressbook_selector_new (ESourceList *source_list) +{ + g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), NULL); + + return g_object_new ( + E_TYPE_ADDRESSBOOK_SELECTOR, + "source-list", source_list, NULL); +} + +EAddressbookView * +e_addressbook_selector_get_current_view (EAddressbookSelector *selector) +{ + g_return_val_if_fail (E_IS_ADDRESSBOOK_SELECTOR (selector), NULL); + + return selector->priv->current_view; +} + +void +e_addressbook_selector_set_current_view (EAddressbookSelector *selector, + EAddressbookView *current_view) +{ + /* XXX This is only needed for moving contacts via drag-and-drop. + * The selection data doesn't include the source of the data + * (the model for the currently selected address book view), + * so we have to rely on it being provided to us. I would + * be happy to see this function go away. */ + + g_return_if_fail (E_IS_ADDRESSBOOK_SELECTOR (selector)); + + if (current_view != NULL) + g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (current_view)); + + if (selector->priv->current_view != NULL) { + g_object_unref (selector->priv->current_view); + selector->priv->current_view = NULL; + } + + if (current_view != NULL) + g_object_ref (current_view); + + selector->priv->current_view = current_view; + + g_object_notify (G_OBJECT (selector), "current-view"); +} diff --git a/addressbook/gui/widgets/e-addressbook-selector.h b/addressbook/gui/widgets/e-addressbook-selector.h new file mode 100644 index 0000000000..c0102cb3b8 --- /dev/null +++ b/addressbook/gui/widgets/e-addressbook-selector.h @@ -0,0 +1,73 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-addressbook-selector.h + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU 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 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_ADDRESSBOOK_SELECTOR_H +#define E_ADDRESSBOOK_SELECTOR_H + +#include <libedataserver/e-source-list.h> +#include <libedataserverui/e-source-selector.h> +#include "e-addressbook-view.h" + +/* Standard GObject macros */ +#define E_TYPE_ADDRESSBOOK_SELECTOR \ + (e_addressbook_selector_get_type ()) +#define E_ADDRESSBOOK_SELECTOR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_ADDRESSBOOK_SELECTOR, EAddressbookSelector)) +#define E_ADDRESSBOOK_SELECTOR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_ADDRESSBOOK_SELECTOR, EAddressbookSelectorClass)) +#define E_IS_ADDRESSBOOK_SELECTOR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_ADDRESSBOOK_SELECTOR)) +#define E_IS_ADDRESSBOOK_SELECTOR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_ADDRESSBOOK_SELECTOR)) +#define E_ADDRESSBOOK_SELECTOR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_ADDRESSBOOK_SELECTOR, EAddressbookSelectorClass)) + +G_BEGIN_DECLS + +typedef struct _EAddressbookSelector EAddressbookSelector; +typedef struct _EAddressbookSelectorClass EAddressbookSelectorClass; +typedef struct _EAddressbookSelectorPrivate EAddressbookSelectorPrivate; + +struct _EAddressbookSelector { + ESourceSelector parent; + EAddressbookSelectorPrivate *priv; +}; + +struct _EAddressbookSelectorClass { + ESourceSelectorClass parent_class; +}; + +GType e_addressbook_selector_get_type (void); +GtkWidget * e_addressbook_selector_new (ESourceList *source_list); +EAddressbookView * + e_addressbook_selector_get_current_view + (EAddressbookSelector *selector); +void e_addressbook_selector_set_current_view + (EAddressbookSelector *selector, + EAddressbookView *current_view); + +G_END_DECLS + +#endif /* E_ADDRESSBOOK_SELECTOR_H */ diff --git a/addressbook/gui/widgets/e-addressbook-table-adapter.c b/addressbook/gui/widgets/e-addressbook-table-adapter.c index a4440155d9..356aabdf8f 100644 --- a/addressbook/gui/widgets/e-addressbook-table-adapter.c +++ b/addressbook/gui/widgets/e-addressbook-table-adapter.c @@ -31,7 +31,7 @@ #include <libxml/xmlmemory.h> struct _EAddressbookTableAdapterPrivate { - EABModel *model; + EAddressbookModel *model; int create_contact_id, remove_contact_id, modify_contact_id, model_changed_id; @@ -100,7 +100,7 @@ addressbook_row_count (ETableModel *etc) EAddressbookTableAdapter *adapter = EAB_TABLE_ADAPTER(etc); EAddressbookTableAdapterPrivate *priv = adapter->priv; - return eab_model_contact_count (priv->model); + return e_addressbook_model_contact_count (priv->model); } /* This function returns the value at a particular point in our ETableModel. */ @@ -111,10 +111,10 @@ addressbook_value_at (ETableModel *etc, int col, int row) EAddressbookTableAdapterPrivate *priv = adapter->priv; const char *value; - if ( col >= COLS || row >= eab_model_contact_count (priv->model) ) + if ( col >= COLS || row >= e_addressbook_model_contact_count (priv->model) ) return NULL; - value = e_contact_get_const((EContact*)eab_model_contact_at (priv->model, row), col); + value = e_contact_get_const((EContact*)e_addressbook_model_contact_at (priv->model, row), col); if (value && *value && (col == E_CONTACT_EMAIL_1 || col == E_CONTACT_EMAIL_2 || col == E_CONTACT_EMAIL_3)) { char *val = g_hash_table_lookup (priv->emails, value); @@ -156,13 +156,13 @@ addressbook_set_value_at (ETableModel *etc, int col, int row, const void *val) EAddressbookTableAdapter *adapter = EAB_TABLE_ADAPTER(etc); EAddressbookTableAdapterPrivate *priv = adapter->priv; - if (eab_model_editable (priv->model)) { + if (e_addressbook_model_get_editable (priv->model)) { EContact *contact; - if (col >= COLS || row >= eab_model_contact_count (priv->model)) + if (col >= COLS || row >= e_addressbook_model_contact_count (priv->model)) return; - contact = eab_model_get_contact (priv->model, row); + contact = e_addressbook_model_get_contact (priv->model, row); if (!contact) return; @@ -177,7 +177,7 @@ addressbook_set_value_at (ETableModel *etc, int col, int row, const void *val) } e_contact_set(contact, col, (void *) val); - eab_merging_book_commit_contact (eab_model_get_ebook (priv->model), + eab_merging_book_commit_contact (e_addressbook_model_get_book (priv->model), contact, contact_modified_cb, etc); g_object_unref (contact); @@ -196,12 +196,12 @@ addressbook_is_cell_editable (ETableModel *etc, int col, int row) EAddressbookTableAdapterPrivate *priv = adapter->priv; const EContact *contact; - if (row >= 0 && row < eab_model_contact_count (priv->model)) - contact = eab_model_contact_at (priv->model, row); + if (row >= 0 && row < e_addressbook_model_contact_count (priv->model)) + contact = e_addressbook_model_contact_at (priv->model, row); else contact = NULL; - if (!eab_model_editable(priv->model)) + if (!e_addressbook_model_editable(priv->model)) return FALSE; else if (contact && e_contact_get ((EContact *) contact, E_CONTACT_IS_LIST)) /* we only allow editing of the name and file as for @@ -229,7 +229,7 @@ addressbook_append_row (ETableModel *etm, ETableModel *source, gint row) e_contact_set (contact, col, (void *) val); } - eab_merging_book_add_contact (eab_model_get_ebook (priv->model), contact, NULL, NULL); + eab_merging_book_add_contact (e_addressbook_model_get_book (priv->model), contact, NULL, NULL); g_object_unref (contact); } @@ -304,7 +304,7 @@ eab_table_adapter_init (GObject *object) static void -create_contact (EABModel *model, +create_contact (EAddressbookModel *model, gint index, gint count, EAddressbookTableAdapter *adapter) { @@ -313,7 +313,7 @@ create_contact (EABModel *model, } static void -remove_contacts (EABModel *model, +remove_contacts (EAddressbookModel *model, gpointer data, EAddressbookTableAdapter *adapter) { @@ -331,7 +331,7 @@ remove_contacts (EABModel *model, } static void -modify_contact (EABModel *model, +modify_contact (EAddressbookModel *model, gint index, EAddressbookTableAdapter *adapter) { @@ -343,7 +343,7 @@ modify_contact (EABModel *model, } static void -model_changed (EABModel *model, +model_changed (EAddressbookModel *model, EAddressbookTableAdapter *adapter) { /* clear whole cache */ @@ -379,7 +379,7 @@ eab_table_adapter_get_type (void) void eab_table_adapter_construct (EAddressbookTableAdapter *adapter, - EABModel *model) + EAddressbookModel *model) { EAddressbookTableAdapterPrivate *priv = adapter->priv; @@ -407,7 +407,7 @@ eab_table_adapter_construct (EAddressbookTableAdapter *adapter, } ETableModel * -eab_table_adapter_new (EABModel *model) +eab_table_adapter_new (EAddressbookModel *model) { EAddressbookTableAdapter *et; diff --git a/addressbook/gui/widgets/e-addressbook-table-adapter.h b/addressbook/gui/widgets/e-addressbook-table-adapter.h index c4182d2d2b..338c87948c 100644 --- a/addressbook/gui/widgets/e-addressbook-table-adapter.h +++ b/addressbook/gui/widgets/e-addressbook-table-adapter.h @@ -49,7 +49,7 @@ struct _EAddressbookTableAdapterClass { GType eab_table_adapter_get_type (void); void eab_table_adapter_construct (EAddressbookTableAdapter *adapter, - EABModel *model); -ETableModel *eab_table_adapter_new (EABModel *model); + EAddressbookModel *model); +ETableModel *eab_table_adapter_new (EAddressbookModel *model); #endif /* _EAB_TABLE_ADAPTER_H_ */ diff --git a/addressbook/gui/widgets/e-addressbook-view.c b/addressbook/gui/widgets/e-addressbook-view.c index 3c0c28f6ad..a979e5a1cb 100644 --- a/addressbook/gui/widgets/e-addressbook-view.c +++ b/addressbook/gui/widgets/e-addressbook-view.c @@ -30,11 +30,9 @@ #include <widgets/menus/gal-view-factory-etable.h> #include <filter/rule-editor.h> #include <widgets/menus/gal-view-etable.h> -#include <e-util/e-xml-utils.h> +#include <e-shell-sidebar.h> #include "addressbook/printing/e-contact-print.h" -#include "addressbook/gui/widgets/eab-popup.h" -#include "addressbook/gui/widgets/eab-menu.h" #include "a11y/addressbook/ea-addressbook.h" #include "e-util/e-print.h" @@ -55,1532 +53,946 @@ #include "e-util/e-error.h" #include "e-util/e-util-private.h" -#include "e-contact-editor.h" #include <gdk/gdkkeysyms.h> #include <ctype.h> #include <string.h> -#include <libxml/tree.h> -#include <libxml/parser.h> - -#define SHOW_ALL_SEARCH "(contains \"x-evolution-any-field\" \"\")" +#define E_ADDRESSBOOK_VIEW_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_ADDRESSBOOK_VIEW, EAddressbookViewPrivate)) #define d(x) -static void eab_view_init (EABView *card); -static void eab_view_class_init (EABViewClass *class); - -static void eab_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void eab_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); - -static void eab_view_dispose (GObject *object); -static void change_view_type (EABView *view, EABViewType view_type); - -static void status_message (GtkObject *object, const gchar *status, EABView *eav); -static void search_result (GtkObject *object, EBookViewStatus status, EABView *eav); -static void folder_bar_message (GtkObject *object, const gchar *status, EABView *eav); -static void stop_state_changed (GtkObject *object, EABView *eav); -static void writable_status (GtkObject *object, gboolean writable, EABView *eav); -static void backend_died (GtkObject *object, EABView *eav); -static void contact_changed (EABModel *model, gint index, EABView *eav); -static void contacts_removed (EABModel *model, gpointer data, EABView *eav); -static GList *get_selected_contacts (EABView *view); - -static void command_state_change (EABView *eav); - -static void selection_clear_event (GtkWidget *invisible, GdkEventSelection *event, - EABView *view); -static void selection_received (GtkWidget *invisible, GtkSelectionData *selection_data, - guint time, EABView *view); -static void selection_get (GtkWidget *invisible, GtkSelectionData *selection_data, - guint info, guint time_stamp, EABView *view); -static void invisible_destroyed (gpointer data, GObject *where_object_was); - -static void categories_changed_cb (gpointer object, gpointer user_data); -static void make_suboptions (EABView *view); -static void query_changed (ESearchBar *esb, EABView *view); -static void search_activated (ESearchBar *esb, EABView *view); -static void search_menu_activated (ESearchBar *esb, int id, EABView *view); -static GList *get_master_list (gboolean force_rebuild); +static void status_message (EAddressbookView *view, const gchar *status); +static void search_result (EAddressbookView *view, EBookViewStatus status); +static void folder_bar_message (EAddressbookView *view, const gchar *status); +static void stop_state_changed (GtkObject *object, EAddressbookView *view); +static void backend_died (EAddressbookView *view); -static gpointer parent_class; +static void command_state_change (EAddressbookView *view); + +struct _EAddressbookViewPrivate { + gpointer shell_view; /* weak pointer */ + + EAddressbookModel *model; + EActivity *activity; + + GList *clipboard_contacts; + ESource *source; + + GObject *object; + GtkWidget *widget; + + GalViewInstance *view_instance; + + GtkWidget *invisible; +}; -/* The arguments we take */ enum { PROP_0, - PROP_BOOK, - PROP_SOURCE, - PROP_QUERY, - PROP_TYPE, + PROP_MODEL, + PROP_SHELL_VIEW, + PROP_SOURCE }; enum { - STATUS_MESSAGE, - SEARCH_RESULT, - FOLDER_BAR_MESSAGE, + OPEN_CONTACT, + POPUP_EVENT, COMMAND_STATE_CHANGE, + SELECTION_CHANGE, LAST_SIGNAL }; -enum DndTargetType { +enum { DND_TARGET_TYPE_SOURCE_VCARD, DND_TARGET_TYPE_VCARD }; -#define VCARD_TYPE "text/x-vcard" -#define SOURCE_VCARD_TYPE "text/x-source-vcard" - -typedef struct EABSearchBarItem { - ESearchBarItem search; - char *image; -}EABSearchBarItem; static GtkTargetEntry drag_types[] = { - { SOURCE_VCARD_TYPE, 0, DND_TARGET_TYPE_SOURCE_VCARD }, - { VCARD_TYPE, 0, DND_TARGET_TYPE_VCARD } + { "text/x-source-vcard", 0, DND_TARGET_TYPE_SOURCE_VCARD }, + { "text/x-vcard", 0, DND_TARGET_TYPE_VCARD } }; -static const int num_drag_types = sizeof (drag_types) / sizeof (drag_types[0]); - -static guint eab_view_signals [LAST_SIGNAL] = {0, }; +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; static GdkAtom clipboard_atom = GDK_NONE; -static GalViewCollection *collection = NULL; - -enum { - ESB_FULL_NAME, - ESB_EMAIL, - ESB_ANY, -}; - -#if 0 -static ESearchBarItem addressbook_search_option_items[] = { - { N_("Name begins with"), ESB_FULL_NAME, ESB_ITEMTYPE_RADIO }, - { N_("Email begins with"), ESB_EMAIL, ESB_ITEMTYPE_RADIO }, - { N_("Any field contains"), ESB_ANY, ESB_ITEMTYPE_RADIO }, - { NULL, -1, 0 } -}; -#endif - -static ESearchBarItem addressbook_search_items[] = { - E_FILTERBAR_ADVANCED, - {NULL, 0, 0}, - E_FILTERBAR_SAVE, - E_FILTERBAR_EDIT, - {NULL, -1, 0} -}; - -GType -eab_view_get_type (void) +static void +addressbook_view_emit_open_contact (EAddressbookView *view, + EContact *contact, + gboolean is_new_contact) { - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof (EABViewClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) eab_view_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (EABView), - 0, /* n_preallocs */ - (GInstanceInitFunc) eab_view_init, - }; - - type = g_type_register_static (GTK_TYPE_VBOX, "EABView", &info, 0); - } - - return type; + g_signal_emit (view, signals[OPEN_CONTACT], 0, contact, is_new_contact); } static void -eab_view_class_init (EABViewClass *class) +addressbook_view_emit_popup_event (EAddressbookView *view, + GdkEvent *event) { - GObjectClass *object_class; - - parent_class = g_type_class_peek_parent (class); - - object_class = G_OBJECT_CLASS(class); - object_class->set_property = eab_view_set_property; - object_class->get_property = eab_view_get_property; - object_class->dispose = eab_view_dispose; - - g_object_class_install_property (object_class, PROP_BOOK, - g_param_spec_object ("book", - _("Book"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_BOOK, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_SOURCE, - g_param_spec_object ("source", - _("Source"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_SOURCE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_QUERY, - g_param_spec_string ("query", - _("Query"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_TYPE, - g_param_spec_int ("type", - _("Type"), - /*_( */"XXX blurb" /*)*/, - EAB_VIEW_NONE, - EAB_VIEW_TABLE, - EAB_VIEW_NONE, - G_PARAM_READWRITE)); - - eab_view_signals [STATUS_MESSAGE] = - g_signal_new ("status_message", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABViewClass, status_message), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - - eab_view_signals [SEARCH_RESULT] = - g_signal_new ("search_result", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABViewClass, search_result), - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); - - eab_view_signals [FOLDER_BAR_MESSAGE] = - g_signal_new ("folder_bar_message", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABViewClass, folder_bar_message), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - - eab_view_signals [COMMAND_STATE_CHANGE] = - g_signal_new ("command_state_change", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABViewClass, command_state_change), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - if (!clipboard_atom) - clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); - - /* init the accessibility support for e_addressbook_view */ - eab_view_a11y_init(); + g_signal_emit (view, signals[POPUP_EVENT], 0, event); } static void -eab_view_init (EABView *eav) +addressbook_view_emit_selection_change (EAddressbookView *view) { - eav->view_type = EAB_VIEW_NONE; - - eav->model = NULL; - eav->object = NULL; - eav->widget = NULL; - eav->contact_display_window = NULL; - eav->contact_display = NULL; - eav->displayed_contact = -1; - - eav->view_instance = NULL; - eav->view_menus = NULL; - eav->current_view = NULL; - eav->uic = NULL; - - eav->book = NULL; - eav->source = NULL; - eav->query = NULL; - - eav->invisible = NULL; - eav->clipboard_contacts = NULL; + g_signal_emit (view, signals[SELECTION_CHANGE], 0); } static void -eab_view_dispose (GObject *object) +addressbook_view_open_contact (EAddressbookView *view, + EContact *contact) { - EABView *eav = EAB_VIEW(object); - - e_categories_unregister_change_listener (G_CALLBACK (categories_changed_cb), eav); - - if (eav->model) { - g_signal_handlers_disconnect_matched (eav->model, - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - object); - g_object_unref (eav->model); - eav->model = NULL; - } - - if (eav->book) { - g_object_unref (eav->book); - eav->book = NULL; - } - - if (eav->source) { - g_object_unref (eav->source); - eav->source = NULL; - } - - if (eav->query) { - g_free(eav->query); - eav->query = NULL; - } - - eav->uic = NULL; - - if (eav->view_instance) { - g_object_unref (eav->view_instance); - eav->view_instance = NULL; - } - - if (eav->view_menus) { - g_object_unref (eav->view_menus); - eav->view_menus = NULL; - } - - if (eav->clipboard_contacts) { - g_list_foreach (eav->clipboard_contacts, (GFunc)g_object_unref, NULL); - g_list_free (eav->clipboard_contacts); - eav->clipboard_contacts = NULL; - } - - if (eav->invisible) { - gtk_widget_destroy (eav->invisible); - eav->invisible = NULL; - } - - /* - if (eav->search_context) { - g_object_unref (eav->search_context); - eav->search_context = NULL; - } - */ - - if (eav->search_rule) { - g_object_unref (eav->search_rule); - eav->search_rule = NULL; - } - - G_OBJECT_CLASS (parent_class)->dispose (object); + addressbook_view_emit_open_contact (view, contact, FALSE); } static void -set_paned_position (EABView *eav) +addressbook_view_create_contact (EAddressbookView *view) { - GConfClient *gconf_client; - gint pos; - - /* XXX this should use the addressbook's global gconf client */ - gconf_client = gconf_client_get_default (); - pos = gconf_client_get_int (gconf_client, "/apps/evolution/addressbook/display/vpane_position", NULL); - if (pos < 1) - pos = 144; - - gtk_paned_set_position (GTK_PANED (eav->paned), pos); + EContact *contact; - g_object_unref (gconf_client); + contact = e_contact_new (); + addressbook_view_emit_open_contact (view, contact, TRUE); + g_object_unref (contact); } -static gboolean -get_paned_position (EABView *eav) +static void +addressbook_view_create_contact_list (EAddressbookView *view) { - GConfClient *gconf_client; - gint pos; - - /* XXX this should use the addressbook's global gconf client */ - gconf_client = gconf_client_get_default (); - - pos = gtk_paned_get_position (GTK_PANED (eav->paned)); - gconf_client_set_int (gconf_client, "/apps/evolution/addressbook/display/vpane_position", pos, NULL); - - g_object_unref (gconf_client); + EContact *contact; - return FALSE; + contact = e_contact_new (); + e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE)); + addressbook_view_emit_open_contact (view, contact, TRUE); + g_object_unref (contact); } -GtkWidget* -eab_view_new (void) +static void +table_double_click (ETableScrolled *table, + gint row, + gint col, + GdkEvent *event, + EAddressbookView *view) { - GtkWidget *widget = GTK_WIDGET (g_object_new (E_TYPE_AB_VIEW, NULL)); - EABView *eav = EAB_VIEW (widget); - FilterPart *part; - char *xmlfile; - char *userfile; - - /* create our model */ - eav->model = eab_model_new (); - - g_signal_connect (eav->model, "status_message", - G_CALLBACK (status_message), eav); - g_signal_connect (eav->model, "search_result", - G_CALLBACK (search_result), eav); - g_signal_connect (eav->model, "folder_bar_message", - G_CALLBACK (folder_bar_message), eav); - g_signal_connect (eav->model, "stop_state_changed", - G_CALLBACK (stop_state_changed), eav); - g_signal_connect (eav->model, "writable_status", - G_CALLBACK (writable_status), eav); - g_signal_connect (eav->model, "backend_died", - G_CALLBACK (backend_died), eav); - g_signal_connect (eav->model, "contact_changed", - G_CALLBACK (contact_changed), eav); - g_signal_connect (eav->model, "contacts_removed", - G_CALLBACK (contacts_removed), eav); - - eav->editable = FALSE; - eav->query = g_strdup (SHOW_ALL_SEARCH); - - /* create the search context */ - eav->search_context = rule_context_new (); - rule_context_add_part_set (eav->search_context, "partset", filter_part_get_type (), - rule_context_add_part, rule_context_next_part); - rule_context_add_rule_set (eav->search_context, "ruleset", filter_rule_get_type (), - rule_context_add_rule, rule_context_next_rule); - - userfile = g_build_filename ( g_get_home_dir (), ".evolution/addressbook/searches.xml", NULL); - xmlfile = g_build_filename (SEARCH_RULE_DIR, "addresstypes.xml", NULL); - - g_object_set_data_full (G_OBJECT (eav->search_context), "user", userfile, g_free); - g_object_set_data_full (G_OBJECT (eav->search_context), "system", xmlfile, g_free); - - rule_context_load (eav->search_context, xmlfile, userfile); - - eav->search_rule = filter_rule_new (); - part = rule_context_next_part (eav->search_context, NULL); - - if (part == NULL) - g_warning ("Could not load addressbook search; no parts."); - else - filter_rule_add_part (eav->search_rule, filter_part_clone (part)); - - eav->search = e_filter_bar_new (eav->search_context, xmlfile, userfile, NULL, eav); - - g_free (xmlfile); - g_free (userfile); - - e_search_bar_set_menu ( (ESearchBar *) eav->search, addressbook_search_items); - gtk_widget_show (GTK_WIDGET (eav->search)); - make_suboptions (eav); - - e_categories_register_change_listener (G_CALLBACK (categories_changed_cb), eav); - - g_signal_connect (eav->search, "query_changed", - G_CALLBACK (query_changed), eav); - g_signal_connect (eav->search, "search_activated", - G_CALLBACK (search_activated), eav); - g_signal_connect (eav->search, "menu_activated", - G_CALLBACK (search_menu_activated), eav); - - gtk_box_pack_start (GTK_BOX (eav), GTK_WIDGET (eav->search), FALSE, FALSE, 0); - - /* create the paned window and contact display */ - eav->paned = gtk_vpaned_new (); - gtk_box_pack_start (GTK_BOX (eav), eav->paned, TRUE, TRUE, 0); - g_signal_connect_swapped (eav->paned, "button_release_event", - G_CALLBACK (get_paned_position), eav); - - eav->contact_display = eab_contact_display_new (); - eav->contact_display_window = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (eav->contact_display_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (eav->contact_display_window), GTK_SHADOW_IN); - gtk_container_add (GTK_CONTAINER (eav->contact_display_window), eav->contact_display); - gtk_paned_add2 (GTK_PANED (eav->paned), eav->contact_display_window); - gtk_widget_show (eav->contact_display); - gtk_widget_show (eav->contact_display_window); - gtk_widget_show (eav->paned); - - /* gtk selection crap */ - eav->invisible = gtk_invisible_new (); - - gtk_selection_add_target (eav->invisible, - clipboard_atom, - GDK_SELECTION_TYPE_STRING, - 0); - - g_signal_connect (eav->invisible, "selection_get", - G_CALLBACK (selection_get), - eav); - g_signal_connect (eav->invisible, "selection_clear_event", - G_CALLBACK (selection_clear_event), - eav); - g_signal_connect (eav->invisible, "selection_received", - G_CALLBACK (selection_received), - eav); - g_object_weak_ref (G_OBJECT (eav->invisible), invisible_destroyed, eav); - - return widget; -} + EAddressbookModel *model; + EContact *contact; -RuleContext * -eab_view_peek_search_context (EABView *view) -{ - return view->search_context; -} + if (!E_IS_ADDRESSBOOK_TABLE_ADAPTER (view->priv->object)) + return; -FilterRule * -eab_view_peek_search_rule (EABView *view) -{ - return view->search_rule; + model = e_addressbook_view_get_model (view); + contact = e_addressbook_model_get_contact (model, row); + addressbook_view_emit_open_contact (view, contact, FALSE); + g_object_unref (contact); } -static void -writable_status (GtkObject *object, gboolean writable, EABView *eav) +static gint +table_right_click (ETableScrolled *table, + gint row, + gint col, + GdkEvent *event, + EAddressbookView *view) { - eav->editable = writable; - command_state_change (eav); -} + addressbook_view_emit_popup_event (view, event); -static void -init_collection (void) -{ - GalViewFactory *factory; - ETableSpecification *spec; - char *galview; - char *addressbookdir; - char *etspecfile; - - if (collection == NULL) { - collection = gal_view_collection_new(); - - gal_view_collection_set_title (collection, _("Address Book")); - - galview = g_build_filename ( - e_get_user_data_dir (), "addressbook", "views", NULL); - addressbookdir = g_build_filename (EVOLUTION_GALVIEWSDIR, - "addressbook", - NULL); - gal_view_collection_set_storage_directories - (collection, - addressbookdir, - galview); - g_free(addressbookdir); - g_free(galview); - - spec = e_table_specification_new(); - etspecfile = g_build_filename (EVOLUTION_ETSPECDIR, - "e-addressbook-view.etspec", - NULL); - if (!e_table_specification_load_from_file (spec, etspecfile)) - g_error ("Unable to load ETable specification file " - "for address book"); - g_free (etspecfile); - - factory = gal_view_factory_etable_new (spec); - g_object_unref (spec); - gal_view_collection_add_factory (collection, factory); - g_object_unref (factory); - - factory = gal_view_factory_minicard_new(); - gal_view_collection_add_factory (collection, factory); - g_object_unref (factory); - - gal_view_collection_load(collection); - } + return TRUE; } -static void -set_view_preview (EABView *view) +static gint +table_white_space_event (ETableScrolled *table, + GdkEvent *event, + EAddressbookView *view) { - /* XXX this should use the addressbook's global gconf client */ - GConfClient *gconf_client; - gboolean state; - - gconf_client = gconf_client_get_default(); - state = gconf_client_get_bool(gconf_client, "/apps/evolution/addressbook/display/show_preview", NULL); - bonobo_ui_component_set_prop (view->uic, - "/commands/ContactsViewPreview", - "state", - state ? "1" : "0", NULL); + gint button = ((GdkEventButton *) event)->button; - eab_view_show_contact_preview (view, state); - - g_object_unref (gconf_client); -} - -static void -display_view(GalViewInstance *instance, - GalView *view, - gpointer data) -{ - EABView *address_view = data; - if (GAL_IS_VIEW_ETABLE(view)) { - change_view_type (address_view, EAB_VIEW_TABLE); - gal_view_etable_attach_table (GAL_VIEW_ETABLE(view), e_table_scrolled_get_table(E_TABLE_SCROLLED(address_view->widget))); - } - else if (GAL_IS_VIEW_MINICARD(view)) { - change_view_type (address_view, EAB_VIEW_MINICARD); - gal_view_minicard_attach (GAL_VIEW_MINICARD (view), address_view); + if (event->type == GDK_BUTTON_PRESS && button == 3) { + addressbook_view_emit_popup_event (view, event); + return TRUE; } - address_view->current_view = view; - set_paned_position (address_view); - set_view_preview (address_view); + return FALSE; } static void -view_preview(BonoboUIComponent *uic, const char *path, Bonobo_UIComponent_EventType type, const char *state, void *data) -{ - /* XXX this should use the addressbook's global gconf client */ - GConfClient *gconf_client; - EABView *view = EAB_VIEW (data); +table_drag_data_get (ETable *table, + gint row, + gint col, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time, + gpointer user_data) +{ + EAddressbookView *view = user_data; + EAddressbookModel *model; + EBook *book; + GList *contact_list; + gchar *value; - if (type != Bonobo_UIComponent_STATE_CHANGED) + if (!E_IS_ADDRESSBOOK_TABLE_ADAPTER (view->priv->object)) return; - gconf_client = gconf_client_get_default(); - gconf_client_set_bool(gconf_client, "/apps/evolution/addressbook/display/show_preview", state[0] != '0', NULL); + model = e_addressbook_view_get_model (view); + book = e_addressbook_model_get_book (model); - eab_view_show_contact_preview(view, state[0] != '0'); + contact_list = e_addressbook_view_get_selected (view); - g_object_unref (gconf_client); -} + switch (info) { + case DND_TARGET_TYPE_VCARD: + value = eab_contact_list_to_string (contact_list); -static void -setup_menus (EABView *view) -{ - if (view->book && view->view_instance == NULL) { - init_collection (); - view->view_instance = gal_view_instance_new (collection, e_book_get_uri (view->book)); - } + gtk_selection_data_set ( + selection_data, selection_data->target, + 8, (guchar *)value, strlen (value)); - if (view->view_instance && view->uic) { - view->view_menus = gal_view_menus_new(view->view_instance); - gal_view_menus_apply(view->view_menus, view->uic, NULL); + g_free (value); + break; - display_view (view->view_instance, gal_view_instance_get_current_view (view->view_instance), view); + case DND_TARGET_TYPE_SOURCE_VCARD: + value = eab_book_and_contact_list_to_string ( + book, contact_list); - g_signal_connect(view->view_instance, "display_view", - G_CALLBACK (display_view), view); - } + gtk_selection_data_set ( + selection_data, selection_data->target, + 8, (guchar *)value, strlen (value)); - bonobo_ui_component_add_listener(view->uic, "ContactsViewPreview", view_preview, view); + g_free (value); + break; + } - set_view_preview (view); + g_list_foreach (contact_list, (GFunc) g_object_unref, NULL); + g_list_free (contact_list); } static void -eab_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +addressbook_view_create_table_view (EAddressbookView *view) { - EABView *eav = EAB_VIEW(object); + ETableModel *adapter; + ETable *table; + GtkWidget *widget; + gchar *etspecfile; - switch (prop_id){ - case PROP_BOOK: - if (eav->book) { - g_object_unref (eav->book); - } - if (g_value_get_object (value)) { - eav->book = E_BOOK(g_value_get_object (value)); - g_object_ref (eav->book); - gtk_widget_set_sensitive (GTK_WIDGET (eav->search), TRUE); - } - else { - eav->book = NULL; - gtk_widget_set_sensitive (GTK_WIDGET (eav->search), FALSE); - } + adapter = eab_table_adapter_new (view->priv->model); - if (eav->view_instance) { - g_object_unref (eav->view_instance); - eav->view_instance = NULL; - } + /* Here we create the table. We give it the three pieces of + the table we've created, the header, the model, and the + initial layout. It does the rest. */ + etspecfile = g_build_filename ( + EVOLUTION_ETSPECDIR, "e-addressbook-view.etspec", NULL); + widget = e_table_scrolled_new_from_spec_file ( + adapter, NULL, etspecfile, NULL); + table = E_TABLE (E_TABLE_SCROLLED (widget)->table); + g_free (etspecfile); - g_object_set(eav->model, - "book", eav->book, - NULL); + view->priv->object = G_OBJECT (adapter); + view->priv->widget = widget; - setup_menus (eav); + g_signal_connect ( + table, "double_click", + G_CALLBACK(table_double_click), view); + g_signal_connect ( + table, "right_click", + G_CALLBACK(table_right_click), view); + g_signal_connect ( + table, "white_space_event", + G_CALLBACK(table_white_space_event), view); + g_signal_connect_swapped ( + table, "selection_change", + G_CALLBACK (addressbook_view_emit_selection_change), view); - break; - case PROP_SOURCE: - if (eav->source) { - g_warning ("EABView at present does not support multiple writes on the \"source\" property."); - break; - } - else { - if (g_value_get_object (value)) { - eav->source = E_SOURCE(g_value_get_object (value)); - g_object_ref (eav->source); - } - else { - eav->source = NULL; - } - } - break; - case PROP_QUERY: -#if 0 /* This code will mess up ldap a bit. We need to think about the ramifications of this more. */ - if ((g_value_get_string (value) == NULL && !strcmp (eav->query, SHOW_ALL_SEARCH)) || - (g_value_get_string (value) != NULL && !strcmp (eav->query, g_value_get_string (value)))) - break; -#endif - g_free(eav->query); - eav->query = g_strdup(g_value_get_string (value)); - if (!eav->query) - eav->query = g_strdup (SHOW_ALL_SEARCH); - g_object_set(eav->model, - "query", eav->query, - NULL); - break; - case PROP_TYPE: - change_view_type(eav, g_value_get_int (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + e_table_drag_source_set ( + table, GDK_BUTTON1_MASK, + drag_types, G_N_ELEMENTS (drag_types), + GDK_ACTION_MOVE | GDK_ACTION_COPY); + + g_signal_connect ( + table, "table_drag_data_get", + G_CALLBACK (table_drag_data_get), view); + + gtk_box_pack_start (GTK_BOX (view), widget, TRUE, TRUE, 0); + + gtk_widget_show (widget); } static void -eab_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +addressbook_view_create_minicard_view (EAddressbookView *view) { - EABView *eav = EAB_VIEW(object); + GtkWidget *scrolled_window; + GtkWidget *minicard_view; + EAddressbookReflowAdapter *adapter; - switch (prop_id) { - case PROP_BOOK: - if (eav->book) - g_value_set_object (value, eav->book); - else - g_value_set_object (value, NULL); - break; - case PROP_SOURCE: - if (eav->source) - g_value_set_object (value, eav->source); - else - g_value_set_object (value, NULL); - break; - - case PROP_QUERY: - g_value_set_string (value, eav->query); - break; - case PROP_TYPE: - g_value_set_int (value, eav->view_type); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} + adapter = E_ADDRESSBOOK_REFLOW_ADAPTER ( + e_addressbook_reflow_adapter_new (view->priv->model)); + minicard_view = e_minicard_view_widget_new (adapter); -static ESelectionModel* -get_selection_model (EABView *view) -{ - if (view->view_type == EAB_VIEW_TABLE) - return e_table_get_selection_model (e_table_scrolled_get_table (E_TABLE_SCROLLED(view->widget))); - else if (view->view_type == EAB_VIEW_MINICARD) - return e_minicard_view_widget_get_selection_model (E_MINICARD_VIEW_WIDGET(view->object)); - g_return_val_if_reached (NULL); -} + g_signal_connect_swapped ( + adapter, "open-contact", + G_CALLBACK (addressbook_view_open_contact), view); -/* Popup menu stuff */ -typedef struct { - EABView *view; - gpointer closure; -} ContactAndBook; + g_signal_connect_swapped ( + minicard_view, "create-contact", + G_CALLBACK (addressbook_view_create_contact), view); -static ESelectionModel* -contact_and_book_get_selection_model (ContactAndBook *contact_and_book) -{ - return get_selection_model (contact_and_book->view); -} + g_signal_connect_swapped ( + minicard_view, "create-contact-list", + G_CALLBACK (addressbook_view_create_contact_list), view); -static GList * -get_contact_list (EABPopupTargetSelect *t) -{ - GList *list = NULL; - int i; + g_signal_connect_swapped ( + minicard_view, "selection_change", + G_CALLBACK (addressbook_view_emit_selection_change), view); - for (i=0;i<t->cards->len;i++) - list = g_list_prepend(list, t->cards->pdata[i]); + g_signal_connect_swapped ( + minicard_view, "right_click", + G_CALLBACK (addressbook_view_emit_popup_event), view); - return list; -} + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type ( + GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN); + gtk_scrolled_window_set_policy ( + GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); -static void -save_as (EPopup *ep, EPopupItem *pitem, void *data) -{ - /*ContactAndBook *contact_and_book = data;*/ - GList *contacts = get_contact_list ((EABPopupTargetSelect *)ep->target); + view->priv->object = G_OBJECT (minicard_view); + view->priv->widget = scrolled_window; - if (contacts) { - eab_contact_list_save(_("Save as vCard..."), contacts, NULL); - g_list_free(contacts); - } -} + gtk_container_add (GTK_CONTAINER (scrolled_window), minicard_view); + gtk_widget_show (minicard_view); -static void -send_as (EPopup *ep, EPopupItem *pitem, void *data) -{ - /*ContactAndBook *contact_and_book = data;*/ - GList *contacts = get_contact_list ((EABPopupTargetSelect *)ep->target); + gtk_widget_show_all (scrolled_window); - if (contacts) { - eab_send_contact_list(contacts, EAB_DISPOSITION_AS_ATTACHMENT); - g_list_free(contacts); - } + gtk_box_pack_start (GTK_BOX (view), scrolled_window, TRUE, TRUE, 0); + + e_reflow_model_changed (E_REFLOW_MODEL (adapter)); } static void -send_to (EPopup *ep, EPopupItem *pitem, void *data) -{ - /*ContactAndBook *contact_and_book = data;*/ - GList *contacts = get_contact_list ((EABPopupTargetSelect *)ep->target); - - if (contacts) { - eab_send_contact_list(contacts, EAB_DISPOSITION_AS_TO); - g_list_free(contacts); +addressbook_view_display_view_cb (EAddressbookView *view, + GalView *gal_view) +{ + if (view->priv->widget != NULL) { + gtk_container_remove ( + GTK_CONTAINER (view), + view->priv->widget); + view->priv->widget = NULL; + } + view->priv->object = NULL; + + if (GAL_IS_VIEW_ETABLE (gal_view)) { + addressbook_view_create_table_view (view); + gal_view_etable_attach_table ( + GAL_VIEW_ETABLE (gal_view), + e_table_scrolled_get_table ( + E_TABLE_SCROLLED (view->priv->widget))); } + else if (GAL_IS_VIEW_MINICARD (gal_view)) { + addressbook_view_create_minicard_view (view); + gal_view_minicard_attach ( + GAL_VIEW_MINICARD (gal_view), view); + } + + command_state_change (view); } static void -print (EPopup *ep, EPopupItem *pitem, void *data) +addressbook_view_selection_get_cb (EAddressbookView *view, + GtkSelectionData *selection_data, + guint info, + guint time_stamp) { - /*ContactAndBook *contact_and_book = data;*/ - EABPopupTargetSelect *t = (EABPopupTargetSelect *)ep->target; - GList *contact_list; + gchar *string; - contact_list = get_contact_list (t); - e_contact_print ( - NULL, NULL, contact_list, - GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG); - g_list_free (contact_list); -} + string = eab_contact_list_to_string (view->priv->clipboard_contacts); -static void -copy (EPopup *ep, EPopupItem *pitem, void *data) -{ - ContactAndBook *contact_and_book = data; + gtk_selection_data_set ( + selection_data, GDK_SELECTION_TYPE_STRING, + 8, (guchar *) string, strlen (string)); - eab_view_copy (contact_and_book->view); + g_free (string); } static void -paste (EPopup *ep, EPopupItem *pitem, void *data) +addressbook_view_selection_clear_event_cb (EAddressbookView *view, + GdkEventSelection *event) { - ContactAndBook *contact_and_book = data; + GList *list; + + list = view->priv->clipboard_contacts; + view->priv->clipboard_contacts = NULL; - eab_view_paste (contact_and_book->view); + g_list_foreach (list, (GFunc) g_object_unref, NULL); + g_list_free (list); } static void -cut (EPopup *ep, EPopupItem *pitem, void *data) +addressbook_view_selection_received_cb (EAddressbookView *view, + GtkSelectionData *selection_data, + guint time) { - ContactAndBook *contact_and_book = data; + EAddressbookModel *model; + GList *list, *iter; + EBook *book; - eab_view_cut (contact_and_book->view); -} + model = e_addressbook_view_get_model (view); + book = e_addressbook_model_get_book (model); -static void -delete (EPopup *ep, EPopupItem *pitem, void *data) -{ - ContactAndBook *contact_and_book = data; + if (selection_data->length <= 0) + return; - eab_view_delete_selection(contact_and_book->view, TRUE); -} + if (selection_data->type != GDK_SELECTION_TYPE_STRING) + return; -static void -copy_to_folder (EPopup *ep, EPopupItem *pitem, void *data) -{ - ContactAndBook *contact_and_book = data; + if (selection_data->data[selection_data->length - 1] != 0) { + gchar *string; - eab_view_copy_to_folder (contact_and_book->view, FALSE); -} + string = g_malloc0 (selection_data->length + 1); + memcpy (string, selection_data->data, selection_data->length); + list = eab_contact_list_from_string (string); + g_free (string); + } else + list = eab_contact_list_from_string ( + (gchar *) selection_data->data); -static void -move_to_folder (EPopup *ep, EPopupItem *pitem, void *data) -{ - ContactAndBook *contact_and_book = data; + for (iter = list; iter != NULL; iter = iter->next) { + EContact *contact = iter->data; - eab_view_move_to_folder (contact_and_book->view, FALSE); + /* XXX NULL for a callback /sigh */ + eab_merging_book_add_contact ( + book, contact, NULL /* XXX */, NULL); + } + + g_list_foreach (list, (GFunc) g_object_unref, NULL); + g_list_free (list); } static void -open_contact (EPopup *ep, EPopupItem *pitem, void *data) +addressbook_view_set_shell_view (EAddressbookView *view, + EShellView *shell_view) { - ContactAndBook *contact_and_book = data; + g_return_if_fail (view->priv->shell_view == NULL); - eab_view_view (contact_and_book->view); -} + view->priv->shell_view = shell_view; + g_object_add_weak_pointer ( + G_OBJECT (shell_view), + &view->priv->shell_view); +} static void -new_card (EPopup *ep, EPopupItem *pitem, void *data) +addressbook_view_set_source (EAddressbookView *view, + ESource *source) { - /*ContactAndBook *contact_and_book = data;*/ - EContact *contact = e_contact_new(); + g_return_if_fail (view->priv->source == NULL); - eab_show_contact_editor (((EABPopupTargetSelect *)ep->target)->book, contact, TRUE, TRUE); - g_object_unref (contact); + view->priv->source = g_object_ref (source); } static void -new_list (EPopup *ep, EPopupItem *pitem, void *data) -{ - /*ContactAndBook *contact_and_book = data;*/ - EContact *contact = e_contact_new (); +addressbook_view_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id){ + case PROP_SHELL_VIEW: + addressbook_view_set_shell_view ( + E_ADDRESSBOOK_VIEW (object), + g_value_get_object (value)); + return; + + case PROP_SOURCE: + addressbook_view_set_source ( + E_ADDRESSBOOK_VIEW (object), + g_value_get_object (value)); + return; + } - eab_show_contact_list_editor (((EABPopupTargetSelect *)ep->target)->book, contact, TRUE, TRUE); - g_object_unref(contact); + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } -static EPopupItem eabv_popup_items[] = { - { E_POPUP_ITEM, "05.open", N_("_Open"), open_contact, NULL, NULL, EAB_POPUP_SELECT_ANY|EAB_POPUP_SELECT_EDITABLE }, - { E_POPUP_BAR, "10.bar" }, - { E_POPUP_ITEM, "10.new", N_("_New Contact..."), new_card, NULL, "contact-new", 0, EAB_POPUP_SELECT_EDITABLE}, - { E_POPUP_ITEM, "15.newlist", N_("New Contact _List..."), new_list, NULL, "stock_contact-list", 0, EAB_POPUP_SELECT_EDITABLE }, - - { E_POPUP_BAR, "20.bar" }, - { E_POPUP_ITEM, "30.saveas", N_("_Save as vCard..."), save_as, NULL, "document-save-as", 0, EAB_POPUP_SELECT_ANY }, - { E_POPUP_ITEM, "40.forward", N_("_Forward Contact"), send_as, NULL, "mail-forward", EAB_POPUP_SELECT_ONE }, - { E_POPUP_ITEM, "40.forward", N_("_Forward Contacts"), send_as, NULL, "mail-forward", EAB_POPUP_SELECT_MANY }, - { E_POPUP_ITEM, "50.mailto", N_("Send _Message to Contact"), send_to, NULL, "mail-message-new", EAB_POPUP_SELECT_ONE|EAB_POPUP_SELECT_EMAIL|EAB_POPUP_CONTACT }, - { E_POPUP_ITEM, "50.mailto", N_("Send _Message to List"), send_to, NULL, "mail-message-new", EAB_POPUP_SELECT_ONE|EAB_POPUP_SELECT_EMAIL|EAB_POPUP_LIST }, - { E_POPUP_ITEM, "50.mailto", N_("Send _Message to Contacts"), send_to, NULL, "mail-message-new", EAB_POPUP_SELECT_MANY|EAB_POPUP_SELECT_EMAIL }, - { E_POPUP_ITEM, "60.print", N_("_Print"), print, NULL, "document-print", 0, EAB_POPUP_SELECT_ANY }, - - { E_POPUP_BAR, "70.bar" }, - { E_POPUP_ITEM, "80.copyto", N_("Cop_y to Address Book..."), copy_to_folder, NULL, NULL, 0, EAB_POPUP_SELECT_ANY }, - { E_POPUP_ITEM, "90.moveto", N_("Mo_ve to Address Book..."), move_to_folder, NULL, NULL, 0, EAB_POPUP_SELECT_ANY|EAB_POPUP_SELECT_EDITABLE }, - - { E_POPUP_BAR, "a0.bar" }, - { E_POPUP_ITEM, "b0.cut", N_("Cu_t"), cut, NULL, "edit-cut", 0, EAB_POPUP_SELECT_ANY|EAB_POPUP_SELECT_EDITABLE }, - { E_POPUP_ITEM, "c0.copy", N_("_Copy"), copy, NULL, "edit-copy", 0, EAB_POPUP_SELECT_ANY }, - { E_POPUP_ITEM, "d0.paste", N_("P_aste"), paste, NULL, "edit-paste", 0, EAB_POPUP_SELECT_EDITABLE }, - { E_POPUP_ITEM, "e0.delete", N_("_Delete"), delete, NULL, "edit-delete", 0, EAB_POPUP_SELECT_EDITABLE|EAB_POPUP_SELECT_ANY }, -}; - static void -get_card_1(gint model_row, void *data) -{ - ContactAndBook *contact_and_book = data; - EContact *contact; +addressbook_view_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_MODEL: + g_value_set_object ( + value, e_addressbook_view_get_model ( + E_ADDRESSBOOK_VIEW (object))); + return; + + case PROP_SHELL_VIEW: + g_value_set_object ( + value, e_addressbook_view_get_shell_view ( + E_ADDRESSBOOK_VIEW (object))); + return; + + case PROP_SOURCE: + g_value_set_object ( + value, e_addressbook_view_get_source ( + E_ADDRESSBOOK_VIEW (object))); + return; + } - contact = eab_model_get_contact(contact_and_book->view->model, model_row); - if (contact) - g_ptr_array_add((GPtrArray *)contact_and_book->closure, contact); + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } static void -eabv_popup_free(EPopup *ep, GSList *list, void *data) +addressbook_view_dispose (GObject *object) { - ContactAndBook *cab = data; - ESelectionModel *selection; + EAddressbookViewPrivate *priv; - /* NB: this looks strange to me */ - selection = contact_and_book_get_selection_model(cab); - if (selection) - e_selection_model_right_click_up(selection); + priv = E_ADDRESSBOOK_VIEW_GET_PRIVATE (object); - g_slist_free(list); - g_object_unref(cab->view); - g_free(cab); -} + if (priv->shell_view != NULL) { + g_object_remove_weak_pointer ( + G_OBJECT (priv->shell_view), + &priv->shell_view); + priv->shell_view = NULL; + } -static void -do_popup_menu(EABView *view, GdkEvent *event) -{ - EABPopup *ep; - EABPopupTargetSelect *t; - GSList *menus = NULL; - int i; - GtkMenu *menu; - GPtrArray *cards = g_ptr_array_new(); - ContactAndBook *contact_and_book; - ESelectionModel *selection_model; - - contact_and_book = g_new(ContactAndBook, 1); - contact_and_book->view = view; - g_object_ref(contact_and_book->view); - - selection_model = contact_and_book_get_selection_model(contact_and_book); - if (selection_model) { - contact_and_book->closure = cards; - e_selection_model_foreach(selection_model, get_card_1, contact_and_book); + if (priv->model != NULL) { + g_signal_handlers_disconnect_matched ( + priv->model, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, object); + g_object_unref (priv->model); + priv->model = NULL; } - /** @HookPoint-EABPopup:Addressbook view Context Menu - * @Id: org.gnome.evolution.addressbook.view.popup - * @Class: org.gnome.evolution.addresbook.popup:1.0 - * @Target: EABPopupTargetSelect - * - * The context menu on the contacts view. - */ + if (priv->activity != NULL) { + /* XXX Activity is not cancellable. */ + e_activity_complete (priv->activity); + g_object_unref (priv->activity); + priv->activity = NULL; + } - ep = eab_popup_new("org.gnome.evolution.addressbook.view.popup"); - t = eab_popup_target_new_select(ep, view->book, !eab_model_editable(view->model), cards); - t->target.widget = (GtkWidget *)view; + if (priv->invisible != NULL) { + gtk_widget_destroy (priv->invisible); + priv->invisible = NULL; + } - for (i=0;i<sizeof(eabv_popup_items)/sizeof(eabv_popup_items[0]);i++) - menus = g_slist_prepend(menus, &eabv_popup_items[i]); + if (priv->source != NULL) { + g_object_unref (priv->source); + priv->source = NULL; + } + + if (priv->view_instance != NULL) { + g_object_unref (priv->view_instance); + priv->view_instance = NULL; + } - e_popup_add_items((EPopup *)ep, menus, NULL, eabv_popup_free, contact_and_book); + g_list_foreach ( + priv->clipboard_contacts, + (GFunc) g_object_unref, NULL); + g_list_free (priv->clipboard_contacts); + priv->clipboard_contacts = NULL; - menu = e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0); - gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event?event->button.button:0, event?event->button.time:gtk_get_current_event_time()); + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); } static void -render_contact (int row, EABView *view) +addressbook_view_constructed (GObject *object) { - EContact *contact = eab_model_get_contact (view->model, row); + EAddressbookView *view = E_ADDRESSBOOK_VIEW (object); + GalViewInstance *view_instance; + EShellView *shell_view; + ESource *source; + gchar *uri; - view->displayed_contact = row; + shell_view = e_addressbook_view_get_shell_view (view); + source = e_addressbook_view_get_source (view); + uri = e_source_get_uri (source); - eab_contact_display_render (EAB_CONTACT_DISPLAY (view->contact_display), contact, - EAB_CONTACT_DISPLAY_RENDER_NORMAL); + view_instance = e_shell_view_new_view_instance (shell_view, uri); + g_signal_connect_swapped ( + view_instance, "display-view", + G_CALLBACK (addressbook_view_display_view_cb), view); + gal_view_instance_load (view_instance); + view->priv->view_instance = view_instance; + + g_free (uri); } static void -selection_changed (GObject *o, EABView *view) +addressbook_view_class_init (EAddressbookViewClass *class) { - ESelectionModel *selection_model; - - command_state_change (view); + GObjectClass *object_class; - selection_model = get_selection_model (view); + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EAddressbookViewPrivate)); - if (e_selection_model_selected_count (selection_model) == 1) - e_selection_model_foreach (selection_model, - (EForeachFunc)render_contact, view); - else { - view->displayed_contact = -1; - eab_contact_display_render (EAB_CONTACT_DISPLAY (view->contact_display), NULL, - EAB_CONTACT_DISPLAY_RENDER_NORMAL); - } + object_class = G_OBJECT_CLASS(class); + object_class->set_property = addressbook_view_set_property; + object_class->get_property = addressbook_view_get_property; + object_class->dispose = addressbook_view_dispose; + object_class->constructed = addressbook_view_constructed; + + g_object_class_install_property ( + object_class, + PROP_MODEL, + g_param_spec_object ( + "model", + _("Model"), + NULL, + E_TYPE_ADDRESSBOOK_MODEL, + G_PARAM_READABLE)); + + g_object_class_install_property ( + object_class, + PROP_SHELL_VIEW, + g_param_spec_object ( + "shell-view", + _("Shell View"), + NULL, + E_TYPE_SHELL_VIEW, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property ( + object_class, + PROP_SOURCE, + g_param_spec_object ( + "source", + _("Source"), + NULL, + E_TYPE_SOURCE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + + signals[OPEN_CONTACT] = g_signal_new ( + "open-contact", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EAddressbookViewClass, open_contact), + NULL, NULL, + e_marshal_VOID__OBJECT_BOOLEAN, + G_TYPE_NONE, 2, + E_TYPE_CONTACT, + G_TYPE_BOOLEAN); + + signals[POPUP_EVENT] = g_signal_new ( + "popup-event", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EAddressbookViewClass, popup_event), + NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, 1, + GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); + + signals[COMMAND_STATE_CHANGE] = g_signal_new ( + "command-state-change", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EAddressbookViewClass, command_state_change), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[SELECTION_CHANGE] = g_signal_new ( + "selection-change", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EAddressbookViewClass, selection_change), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + if (clipboard_atom == NULL) + clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); + /* init the accessibility support for e_addressbook_view */ + eab_view_a11y_init (); } static void -table_double_click(ETableScrolled *table, gint row, gint col, GdkEvent *event, EABView *view) +addressbook_view_init (EAddressbookView *view) { - if (E_IS_ADDRESSBOOK_TABLE_ADAPTER(view->object)) { - EABModel *model = view->model; - EContact *contact = eab_model_get_contact (model, row); - EBook *book; + view->priv = E_ADDRESSBOOK_VIEW_GET_PRIVATE (view); - g_object_get(model, - "book", &book, - NULL); + view->priv->model = e_addressbook_model_new (); - g_return_if_fail (E_IS_BOOK (book)); + view->priv->invisible = gtk_invisible_new (); - if (e_contact_get (contact, E_CONTACT_IS_LIST)) - eab_show_contact_list_editor (book, contact, FALSE, view->editable); - else - eab_show_contact_editor (book, contact, FALSE, view->editable); + gtk_selection_add_target ( + view->priv->invisible, clipboard_atom, + GDK_SELECTION_TYPE_STRING, 0); - g_object_unref (book); - g_object_unref (contact); - } + g_signal_connect_swapped ( + view->priv->invisible, "selection-get", + G_CALLBACK (addressbook_view_selection_get_cb), view); + g_signal_connect_swapped ( + view->priv->invisible, "selection-clear-event", + G_CALLBACK (addressbook_view_selection_clear_event_cb), view); + g_signal_connect_swapped ( + view->priv->invisible, "selection-received", + G_CALLBACK (addressbook_view_selection_received_cb), view); } -static gint -table_right_click(ETableScrolled *table, gint row, gint col, GdkEvent *event, EABView *view) +GType +e_addressbook_view_get_type (void) { - do_popup_menu(view, event); - return TRUE; -} + static GType type = 0; -static gint -table_white_space_event(ETableScrolled *table, GdkEvent *event, EABView *view) -{ - if (event->type == GDK_BUTTON_PRESS && ((GdkEventButton *)event)->button == 3) { - do_popup_menu(view, event); - return TRUE; - } else { - return FALSE; + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EAddressbookViewClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) addressbook_view_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EAddressbookView), + 0, /* n_preallocs */ + (GInstanceInitFunc) addressbook_view_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_VBOX, "EAddressbookView", &type_info, 0); } + + return type; } -static void -table_drag_data_get (ETable *table, - int row, - int col, - GdkDragContext *context, - GtkSelectionData *selection_data, - guint info, - guint time, - gpointer user_data) +GtkWidget * +e_addressbook_view_new (EShellView *shell_view, + ESource *source) { - EABView *view = user_data; - GList *contact_list; + GtkWidget *widget; + EAddressbookView *view; - if (!E_IS_ADDRESSBOOK_TABLE_ADAPTER(view->object)) - return; + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); - contact_list = get_selected_contacts (view); + widget = g_object_new ( + E_TYPE_ADDRESSBOOK_VIEW, "shell-view", + shell_view, "source", source, NULL); - switch (info) { - case DND_TARGET_TYPE_VCARD: { - char *value; + view = E_ADDRESSBOOK_VIEW (widget); - value = eab_contact_list_to_string (contact_list); + g_signal_connect_swapped ( + view->priv->model, "status_message", + G_CALLBACK (status_message), view); + g_signal_connect_swapped ( + view->priv->model, "search_result", + G_CALLBACK (search_result), view); + g_signal_connect_swapped ( + view->priv->model, "folder_bar_message", + G_CALLBACK (folder_bar_message), view); + g_signal_connect (view->priv->model, "stop_state_changed", + G_CALLBACK (stop_state_changed), view); + g_signal_connect_swapped ( + view->priv->model, "writable-status", + G_CALLBACK (command_state_change), view); + g_signal_connect_swapped ( + view->priv->model, "backend_died", + G_CALLBACK (backend_died), view); - gtk_selection_data_set (selection_data, - selection_data->target, - 8, - (guchar *)value, strlen (value)); - g_free (value); - break; - } - case DND_TARGET_TYPE_SOURCE_VCARD: { - char *value; - - value = eab_book_and_contact_list_to_string (view->book, contact_list); - - gtk_selection_data_set (selection_data, - selection_data->target, - 8, - (guchar *)value, strlen (value)); - g_free (value); - break; - } - } - - g_list_foreach (contact_list, (GFunc) g_object_unref, NULL); - g_list_free (contact_list); + return widget; } -static void -emit_status_message (EABView *eav, const gchar *status) +EAddressbookModel * +e_addressbook_view_get_model (EAddressbookView *view) { - g_signal_emit (eav, - eab_view_signals [STATUS_MESSAGE], 0, - status); -} + g_return_val_if_fail (E_IS_ADDRESSBOOK_VIEW (view), NULL); -static void -emit_search_result (EABView *eav, EBookViewStatus status) -{ - g_signal_emit (eav, - eab_view_signals [SEARCH_RESULT], 0, - status); + return view->priv->model; } -static void -emit_folder_bar_message (EABView *eav, const gchar *message) +GalViewInstance * +e_addressbook_view_get_view_instance (EAddressbookView *view) { - g_signal_emit (eav, - eab_view_signals [FOLDER_BAR_MESSAGE], 0, - message); -} + g_return_val_if_fail (E_IS_ADDRESSBOOK_VIEW (view), NULL); -static void -status_message (GtkObject *object, const gchar *status, EABView *eav) -{ - emit_status_message (eav, status); + return view->priv->view_instance; } -static void -search_result (GtkObject *object, EBookViewStatus status, EABView *eav) +GObject * +e_addressbook_view_get_view_object (EAddressbookView *view) { - emit_search_result (eav, status); -} + /* XXX Find a more descriptive name for this. */ -static void -folder_bar_message (GtkObject *object, const gchar *status, EABView *eav) -{ - emit_folder_bar_message (eav, status); -} + g_return_val_if_fail (E_IS_ADDRESSBOOK_VIEW (view), NULL); -static void -stop_state_changed (GtkObject *object, EABView *eav) -{ - command_state_change (eav); + return view->priv->object; } -static void -command_state_change (EABView *eav) +GtkWidget * +e_addressbook_view_get_view_widget (EAddressbookView *view) { - /* Reffing during emission is unnecessary. Gtk automatically refs during an emission. */ - g_signal_emit (eav, eab_view_signals [COMMAND_STATE_CHANGE], 0); -} + /* XXX Find a more descriptive name for this. */ -static void -backend_died (GtkObject *object, EABView *eav) -{ - e_error_run (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (eav))), - "addressbook:backend-died", e_book_get_uri (eav->book), NULL); + g_return_val_if_fail (E_IS_ADDRESSBOOK_VIEW (view), NULL); + + return view->priv->widget; } +/* Helper for e_addressbook_view_get_selected() */ static void -contact_changed (EABModel *model, gint index, EABView *eav) +add_to_list (gint model_row, gpointer closure) { - if (eav->displayed_contact == index) { - /* if the contact that's presently displayed is changed, re-render it */ - render_contact (index, eav); - } + GList **list = closure; + *list = g_list_prepend (*list, GINT_TO_POINTER (model_row)); } -static void -contacts_removed (EABModel *model, gpointer data, EABView *eav) +GList * +e_addressbook_view_get_selected (EAddressbookView *view) { - GArray *indices = (GArray *) data; - int count = indices->len; - gint i; - - for (i = 0; i < count; i ++) { + GList *list, *iter; + ESelectionModel *selection; + g_return_val_if_fail (E_IS_ADDRESSBOOK_VIEW (view), NULL); - if (eav->displayed_contact == g_array_index (indices, gint, i)) { + list = NULL; + selection = e_addressbook_view_get_selection_model (view); + e_selection_model_foreach (selection, add_to_list, &list); - /* if the contact that's presently displayed is changed, clear the display */ - eab_contact_display_render (EAB_CONTACT_DISPLAY (eav->contact_display), NULL, - EAB_CONTACT_DISPLAY_RENDER_NORMAL); - eav->displayed_contact = -1; - break; - } - } -} + for (iter = list; iter != NULL; iter = iter->next) + iter->data = e_addressbook_model_get_contact ( + view->priv->model, GPOINTER_TO_INT (iter->data)); + list = g_list_reverse (list); -static void -minicard_right_click (EMinicardView *minicard_view_item, GdkEvent *event, EABView *view) -{ - do_popup_menu(view, event); + return list; } -static void -create_minicard_view (EABView *view) +ESelectionModel * +e_addressbook_view_get_selection_model (EAddressbookView *view) { - GtkWidget *scrolled_window; - GtkWidget *minicard_view; - EAddressbookReflowAdapter *adapter; + GalView *gal_view; + GalViewInstance *view_instance; + ESelectionModel *model = NULL; - adapter = E_ADDRESSBOOK_REFLOW_ADAPTER(e_addressbook_reflow_adapter_new (view->model)); - minicard_view = e_minicard_view_widget_new(adapter); + g_return_val_if_fail (E_IS_ADDRESSBOOK_VIEW (view), NULL); - g_signal_connect(minicard_view, "selection_change", - G_CALLBACK(selection_changed), view); + view_instance = e_addressbook_view_get_view_instance (view); + gal_view = gal_view_instance_get_current_view (view_instance); - g_signal_connect(minicard_view, "right_click", - G_CALLBACK(minicard_right_click), view); + if (GAL_IS_VIEW_ETABLE (gal_view)) { + ETableScrolled *scrolled_table; + ETable *table; - scrolled_window = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); + scrolled_table = E_TABLE_SCROLLED (view->priv->widget); + table = e_table_scrolled_get_table (scrolled_table); - view->object = G_OBJECT(minicard_view); - view->widget = scrolled_window; + model = e_table_get_selection_model (table); - gtk_container_add (GTK_CONTAINER (scrolled_window), minicard_view); - gtk_widget_show (minicard_view); + } else if (GAL_IS_VIEW_MINICARD (gal_view)) { + EMinicardViewWidget *widget; - gtk_widget_show_all( GTK_WIDGET(scrolled_window) ); + widget = E_MINICARD_VIEW_WIDGET (view->priv->object); - gtk_paned_add1 (GTK_PANED (view->paned), scrolled_window); + model = e_minicard_view_widget_get_selection_model (widget); + } - e_reflow_model_changed (E_REFLOW_MODEL (adapter)); + return model; } -static void -create_table_view (EABView *view) +EShellView * +e_addressbook_view_get_shell_view (EAddressbookView *view) { - ETableModel *adapter; - GtkWidget *table; - char *etspecfile; - - adapter = eab_table_adapter_new(view->model); + g_return_val_if_fail (E_IS_ADDRESSBOOK_VIEW (view), NULL); - /* Here we create the table. We give it the three pieces of - the table we've created, the header, the model, and the - initial layout. It does the rest. */ - etspecfile = g_build_filename (EVOLUTION_ETSPECDIR, - "e-addressbook-view.etspec", - NULL); - table = e_table_scrolled_new_from_spec_file (adapter, NULL, etspecfile, NULL); - g_free (etspecfile); - - view->object = G_OBJECT(adapter); - view->widget = table; - - g_signal_connect(e_table_scrolled_get_table(E_TABLE_SCROLLED(table)), "double_click", - G_CALLBACK(table_double_click), view); - g_signal_connect(e_table_scrolled_get_table(E_TABLE_SCROLLED(table)), "right_click", - G_CALLBACK(table_right_click), view); - g_signal_connect(e_table_scrolled_get_table(E_TABLE_SCROLLED(table)), "white_space_event", - G_CALLBACK(table_white_space_event), view); - g_signal_connect(e_table_scrolled_get_table(E_TABLE_SCROLLED(table)), "selection_change", - G_CALLBACK(selection_changed), view); - - /* drag & drop signals */ - e_table_drag_source_set (E_TABLE(E_TABLE_SCROLLED(table)->table), GDK_BUTTON1_MASK, - drag_types, num_drag_types, GDK_ACTION_MOVE | GDK_ACTION_COPY); - - g_signal_connect (E_TABLE_SCROLLED(table)->table, - "table_drag_data_get", - G_CALLBACK (table_drag_data_get), - view); - - gtk_paned_add1 (GTK_PANED (view->paned), table); - - gtk_widget_show( GTK_WIDGET(table) ); + return view->priv->shell_view; } -static void -change_view_type (EABView *view, EABViewType view_type) +ESource * +e_addressbook_view_get_source (EAddressbookView *view) { - if (view_type == view->view_type) - return; - - if (view->widget) { - gtk_container_remove (GTK_CONTAINER (view->paned), view->widget); - view->widget = NULL; - } - view->object = NULL; - - switch (view_type) { - case EAB_VIEW_TABLE: - create_table_view (view); - break; - case EAB_VIEW_MINICARD: - create_minicard_view (view); - break; - default: - g_warning ("view_type not recognized."); - return; - } - - view->view_type = view_type; + g_return_val_if_fail (E_IS_ADDRESSBOOK_VIEW (view), NULL); - command_state_change (view); + return view->priv->source; } - - static void -search_activated (ESearchBar *esb, EABView *v) -{ - GList *master_list; - char *search_word, *search_query, *view_sexp; - const char *category_name; - int search_type, subid; - - g_object_get(esb, - "text", &search_word, - "item_id", &search_type, - NULL); - - if (search_type == E_FILTERBAR_ADVANCED_ID) { - /* rebuild view immediately */ - query_changed (esb, v); - } - else { - if ((search_word && strlen (search_word))) { - GString *s = g_string_new (""); - e_sexp_encode_string (s, search_word); - switch (search_type) { - case ESB_ANY: - search_query = g_strdup_printf ("(contains \"x-evolution-any-field\" %s)", - s->str); - break; - case ESB_FULL_NAME: - search_query = g_strdup_printf ("(contains \"full_name\" %s)", - s->str); - break; - case ESB_EMAIL: - search_query = g_strdup_printf ("(beginswith \"email\" %s)", - s->str); - break; - default: - search_query = g_strdup ("(contains \"x-evolution-any-field\" \"\")"); - break; - } - g_string_free (s, TRUE); - - } else - search_query = g_strdup ("(contains \"x-evolution-any-field\" \"\")"); - - /* Merge view and sexp */ - subid = e_search_bar_get_viewitem_id (esb); - - if (subid) { - master_list = get_master_list (FALSE); - if (subid < 3) { - view_sexp = g_strdup ("(not (and (exists \"CATEGORIES\") (not (is \"CATEGORIES\" \"\"))))"); - } else { - category_name = g_list_nth_data (master_list, subid-3); - view_sexp = g_strdup_printf ("(is \"category_list\" \"%s\")", category_name); - } - search_query = g_strconcat ("(and ", view_sexp, search_query, ")", NULL); - g_free (view_sexp); +status_message (EAddressbookView *view, + const gchar *status) +{ + EActivity *activity; + EShellView *shell_view; + EShellModule *shell_module; + + activity = view->priv->activity; + shell_view = e_addressbook_view_get_shell_view (view); + shell_module = e_shell_view_get_shell_module (shell_view); + + if (status == NULL || *status == '\0') { + if (activity != NULL) { + e_activity_complete (activity); + g_object_unref (activity); + view->priv->activity = NULL; } - if (search_query) - g_object_set (v, - "query", search_query, - NULL); - - g_free (search_query); - } + } else if (activity == NULL) { + activity = e_activity_new (status); + view->priv->activity = activity; + e_shell_module_add_activity (shell_module, activity); - g_free (search_word); - v->displayed_contact = -1; - eab_contact_display_render (EAB_CONTACT_DISPLAY (v->contact_display), NULL, - EAB_CONTACT_DISPLAY_RENDER_NORMAL); + } else + e_activity_set_primary_text (activity, status); } static void -search_menu_activated (ESearchBar *esb, int id, EABView *view) +search_result (EAddressbookView *view, + EBookViewStatus status) { - if (id == E_FILTERBAR_ADVANCED_ID) - e_search_bar_set_item_id (esb, id); -} + EShellView *shell_view; + EShellWindow *shell_window; -static void -query_changed (ESearchBar *esb, EABView *view) -{ - int search_type; - char *query; - - search_type = e_search_bar_get_item_id(esb); - if (search_type == E_FILTERBAR_ADVANCED_ID) { - g_object_get (esb, "query", &query, NULL); - g_object_set (view, "query", query, NULL); - g_free (query); - } + shell_view = e_addressbook_view_get_shell_view (view); + shell_window = e_shell_view_get_shell_window (shell_view); + eab_search_result_dialog (GTK_WIDGET (shell_window), status); } -static int -compare_subitems (const void *a, const void *b) -{ - const ESearchBarItem *subitem_a = a; - const ESearchBarItem *subitem_b = b; - char *collate_a, *collate_b; - int ret; - - collate_a = g_utf8_collate_key (subitem_a->text, -1); - collate_b = g_utf8_collate_key (subitem_b->text, -1); - - ret = strcmp (collate_a, collate_b); - - g_free (collate_a); - g_free (collate_b); - - return ret; -} - -static GtkWidget * -generate_viewoption_menu (EABSearchBarItem *subitems) +static void +folder_bar_message (EAddressbookView *view, + const gchar *message) { - GtkWidget *menu, *menu_item; - gint i = 0; - - menu = gtk_menu_new (); - - for (i = 0; subitems[i].search.id != -1; ++i) { - if (subitems[i].search.text) { - char *str = NULL; - str = e_str_without_underscores (subitems[i].search.text); - menu_item = gtk_image_menu_item_new_with_label (str); - if (subitems[i].image) { - GtkWidget *image; - - image = gtk_image_new_from_file ( - subitems[i].image); - gtk_image_menu_item_set_image ( - GTK_IMAGE_MENU_ITEM (menu_item), - image); - } - g_free (str); - } else { - menu_item = gtk_menu_item_new (); - gtk_widget_set_sensitive (menu_item, FALSE); - } + EShellView *shell_view; + EShellSidebar *shell_sidebar; + const gchar *name; - g_object_set_data (G_OBJECT (menu_item), "EsbItemId", - GINT_TO_POINTER (subitems[i].search.id)); + shell_view = e_addressbook_view_get_shell_view (view); + shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); - gtk_widget_show (menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); - } + if (view->priv->source == NULL) + return; - return menu; + name = e_source_peek_name (view->priv->source); + e_shell_sidebar_set_primary_text (shell_sidebar, name); + e_shell_sidebar_set_secondary_text (shell_sidebar, message); } static void -categories_changed_cb (gpointer object, gpointer user_data) +stop_state_changed (GtkObject *object, EAddressbookView *view) { - get_master_list (TRUE); - make_suboptions (user_data); + command_state_change (view); } static void -make_suboptions (EABView *view) +command_state_change (EAddressbookView *view) { - EABSearchBarItem *subitems, *s; - GList *master_list; - gint i, N; - GtkWidget *menu; - - master_list = get_master_list (FALSE); - N = g_list_length (master_list); - subitems = g_new (EABSearchBarItem, N+4); - - subitems[0].search.id = 0; - subitems[0].search.text = g_strdup (_("Any Category")); - subitems[0].image = NULL; - - subitems[1].search.text = g_strdup (_("Unmatched")); - subitems[1].search.id = 1; - subitems[1].image = NULL; - - subitems[2].search.text = NULL; - subitems[2].search.id = 0; - subitems[2].image = NULL; - - for (i=0; i<N; ++i) { - const char *category = g_list_nth_data (master_list, i); - subitems[i+3].search.id = i+3; - subitems[i+3].search.text = g_strdup (category); - subitems[i+3].image = (char *)e_categories_get_icon_file_for (category); - } - - subitems[N+3].search.id = -1; - subitems[N+3].search.text = NULL; - subitems[N+3].image = NULL; - - qsort (subitems + 3, N, sizeof (subitems[0]), compare_subitems); - menu = generate_viewoption_menu (subitems); - e_search_bar_set_viewoption_menu ((ESearchBar *)view->search, menu); - - for (s = subitems; ((ESearchBarItem *)s)->id != -1; s++) { - if (((ESearchBarItem *)s)->text) - g_free (((ESearchBarItem *)s)->text); - } - g_free (subitems); + g_signal_emit (view, signals[COMMAND_STATE_CHANGE], 0); } -static GList * -get_master_list (gboolean force_rebuild) +static void +backend_died (EAddressbookView *view) { - static GList *category_list = NULL; - - if (force_rebuild) { - g_list_free (category_list); - category_list = NULL; - } - - if (category_list == NULL) { - GList *l, *p = e_categories_get_list (); - - for (l = p; l; l = l->next) { - if (e_categories_is_searchable ((const char *) l->data)) - category_list = g_list_prepend (category_list, l->data); - } + EShellView *shell_view; + EShellWindow *shell_window; + EAddressbookModel *model; + EBook *book; - category_list = g_list_reverse (category_list); + shell_view = e_addressbook_view_get_shell_view (view); + shell_window = e_shell_view_get_shell_window (shell_view); - g_list_free (p); - } + model = e_addressbook_view_get_model (view); + book = e_addressbook_model_get_book (model); - return category_list; + e_error_run ( + GTK_WINDOW (shell_window), + "addressbook:backend-died", + e_book_get_uri (book), NULL); } static void @@ -1626,78 +1038,27 @@ e_contact_print_button (EPrintable *printable, GtkPrintOperationAction action) } void -eab_view_show_contact_preview (EABView *view, gboolean show) +e_addressbook_view_print (EAddressbookView *view, + GtkPrintOperationAction action) { - g_return_if_fail (view && E_IS_ADDRESSBOOK_VIEW (view)); + GalView *gal_view; + GalViewInstance *view_instance; - if (show) - gtk_widget_show (view->contact_display_window); - else - gtk_widget_hide (view->contact_display_window); -} - -void -eab_view_setup_menus (EABView *view, - BonoboUIComponent *uic) -{ - - g_return_if_fail (view != NULL); g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (view)); - g_return_if_fail (uic != NULL); - g_return_if_fail (BONOBO_IS_UI_COMPONENT (uic)); - - init_collection (); - view->uic = uic; + view_instance = e_addressbook_view_get_view_instance (view); + gal_view = gal_view_instance_get_current_view (view_instance); - setup_menus (view); - - /* XXX toshok - yeah this really doesn't belong here, but it - needs to happen at the same time and takes the uic */ - e_search_bar_set_ui_component ( (ESearchBar *)view->search, uic); -} - -/** - * eab_view_discard_menus: - * @view: An addressbook view. - * - * Makes an addressbook view discard its GAL view menus and its views instance - * objects. This should be called when the corresponding Bonobo component is - * deactivated. - **/ -void -eab_view_discard_menus (EABView *view) -{ - g_return_if_fail (view != NULL); - g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (view)); - - if (view->view_menus) { - gal_view_menus_unmerge (view->view_menus, NULL); - - g_object_unref (view->view_menus); - view->view_menus = NULL; - } - - if (view->view_instance) { - g_object_unref (view->view_instance); - view->view_instance = NULL; - } - - view->uic = NULL; -} - -void -eab_view_print (EABView *view, GtkPrintOperationAction action) -{ - if (view->view_type == EAB_VIEW_MINICARD) { + if (GAL_IS_VIEW_MINICARD (gal_view)) { + EAddressbookModel *model; EBook *book; EBookQuery *query; gchar *query_string; GList *contact_list; - g_object_get ( - view->model, "query", &query_string, - "book", &book, NULL); + model = e_addressbook_view_get_model (view); + book = e_addressbook_model_get_book (model); + query_string = e_addressbook_model_get_query (model); if (query_string != NULL) query = e_book_query_from_string (query_string); @@ -1705,7 +1066,7 @@ eab_view_print (EABView *view, GtkPrintOperationAction action) query = NULL; g_free (query_string); - contact_list = get_selected_contacts (view); + contact_list = e_addressbook_view_get_selected (view); e_contact_print (book, query, contact_list, action); g_list_foreach (contact_list, (GFunc) g_object_unref, NULL); g_list_free (contact_list); @@ -1713,11 +1074,11 @@ eab_view_print (EABView *view, GtkPrintOperationAction action) if (query != NULL) e_book_query_unref (query); - } else if (view->view_type == EAB_VIEW_TABLE) { + } else if (GAL_IS_VIEW_ETABLE (gal_view)) { EPrintable *printable; ETable *table; - g_object_get (view->widget, "table", &table, NULL); + g_object_get (view->priv->widget, "table", &table, NULL); printable = e_table_get_printable (table); g_object_ref_sink (printable); g_object_unref (table); @@ -1731,7 +1092,8 @@ eab_view_print (EABView *view, GtkPrintOperationAction action) /* callback function to handle removal of contacts for * which a user doesnt have write permission */ -static void delete_contacts_cb (EBook *book, EBookStatus status, gpointer closure) +static void +delete_contacts_cb (EBook *book, EBookStatus status, gpointer closure) { switch(status) { case E_BOOK_ERROR_OK : @@ -1747,19 +1109,85 @@ static void delete_contacts_cb (EBook *book, EBookStatus status, gpointer clos } } +static gboolean +addressbook_view_confirm_delete (GtkWindow *parent, + gboolean plural, + gboolean is_list, + const gchar *name) +{ + GtkWidget *dialog; + gchar *message; + gint response; + + if (is_list) { + if (plural) { + message = g_strdup ( + _("Are you sure you want to " + "delete these contact lists?")); + } else if (name == NULL) { + message = g_strdup ( + _("Are you sure you want to " + "delete this contact list?")); + } else { + message = g_strdup_printf ( + _("Are you sure you want to delete " + "this contact list (%s)?"), name); + } + } else { + if (plural) { + message = g_strdup ( + _("Are you sure you want to " + "delete these contacts?")); + } else if (name == NULL) { + message = g_strdup ( + _("Are you sure you want to " + "delete this contact?")); + } else { + message = g_strdup_printf ( + _("Are you sure you want to delete " + "this contact (%s)?"), name); + } + } + + dialog = gtk_message_dialog_new ( + parent, 0, GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, "%s", message); + gtk_dialog_add_buttons ( + GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT, + NULL); + response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + g_free (message); + + return (response == GTK_RESPONSE_ACCEPT); +} + void -eab_view_delete_selection(EABView *view, gboolean is_delete) +e_addressbook_view_delete_selection(EAddressbookView *view, gboolean is_delete) { GList *list, *l; gboolean plural = FALSE, is_list = FALSE; EContact *contact; ETable *etable = NULL; + EAddressbookModel *model; + EBook *book; EMinicardView *card_view; ESelectionModel *selection_model = NULL; + GalViewInstance *view_instance; + GalView *gal_view; char *name = NULL; gint row = 0, select; - list = get_selected_contacts (view); + model = e_addressbook_view_get_model (view); + book = e_addressbook_model_get_book (model); + + view_instance = e_addressbook_view_get_view_instance (view); + gal_view = gal_view_instance_get_current_view (view_instance); + + list = e_addressbook_view_get_selected (view); contact = list->data; if (g_list_next(list)) @@ -1770,28 +1198,29 @@ eab_view_delete_selection(EABView *view, gboolean is_delete) if (e_contact_get (contact, E_CONTACT_IS_LIST)) is_list = TRUE; - if (view->view_type == EAB_VIEW_MINICARD) { - card_view = e_minicard_view_widget_get_view (E_MINICARD_VIEW_WIDGET(view->object)); - selection_model = get_selection_model (view); + if (GAL_IS_VIEW_MINICARD (gal_view)) { + card_view = e_minicard_view_widget_get_view (E_MINICARD_VIEW_WIDGET(view->priv->object)); + selection_model = e_addressbook_view_get_selection_model (view); row = e_selection_model_cursor_row (selection_model); } - else if (view->view_type == EAB_VIEW_TABLE) { - etable = e_table_scrolled_get_table(E_TABLE_SCROLLED(view->widget)); + else if (GAL_IS_VIEW_ETABLE (gal_view)) { + etable = e_table_scrolled_get_table ( + E_TABLE_SCROLLED(view->priv->widget)); row = e_table_get_cursor_row (E_TABLE (etable)); } /* confirm delete */ - if (is_delete && - !eab_editor_confirm_delete(GTK_WINDOW(gtk_widget_get_toplevel(view->widget)), - plural, is_list, name)) { + if (is_delete && !addressbook_view_confirm_delete ( + GTK_WINDOW (gtk_widget_get_toplevel ( + view->priv->widget)), plural, is_list, name)) { g_free (name); g_list_foreach (list, (GFunc) g_object_unref, NULL); g_list_free (list); return; } - if (e_book_check_static_capability (view->book, "bulk-remove")) { + if (e_book_check_static_capability (book, "bulk-remove")) { GList *ids = NULL; for (l=list;l;l=g_list_next(l)) { @@ -1801,7 +1230,7 @@ eab_view_delete_selection(EABView *view, gboolean is_delete) } /* Remove the cards all at once. */ - e_book_async_remove_contacts (view->book, + e_book_async_remove_contacts (book, ids, delete_contacts_cb, NULL); @@ -1812,7 +1241,7 @@ eab_view_delete_selection(EABView *view, gboolean is_delete) for (l=list;l;l=g_list_next(l)) { contact = l->data; /* Remove the card. */ - e_book_async_remove_contact (view->book, + e_book_async_remove_contact (book, contact, delete_contacts_cb, NULL); @@ -1820,7 +1249,7 @@ eab_view_delete_selection(EABView *view, gboolean is_delete) } /* Sets the cursor, at the row after the deleted row */ - if (view->view_type == EAB_VIEW_MINICARD && row!=0) { + if (GAL_IS_VIEW_MINICARD (gal_view) && row != 0) { select = e_sorter_model_to_sorted (selection_model->sorter, row); /* Sets the cursor, before the deleted row if its the last row */ @@ -1834,7 +1263,7 @@ eab_view_delete_selection(EABView *view, gboolean is_delete) } /* Sets the cursor, at the row after the deleted row */ - else if (view->view_type == EAB_VIEW_TABLE && row!=0) { + else if (GAL_IS_VIEW_ETABLE (gal_view) && row != 0) { select = e_table_model_to_view_row (E_TABLE (etable), row); /* Sets the cursor, before the deleted row if its the last row */ @@ -1850,234 +1279,149 @@ eab_view_delete_selection(EABView *view, gboolean is_delete) g_list_free (list); } -static void -invisible_destroyed (gpointer data, GObject *where_object_was) -{ - EABView *view = data; - view->invisible = NULL; -} - -static void -selection_get (GtkWidget *invisible, - GtkSelectionData *selection_data, - guint info, - guint time_stamp, - EABView *view) -{ - char *value; - - value = eab_contact_list_to_string (view->clipboard_contacts); - - gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING, - 8, (guchar *)value, strlen (value)); - g_free (value); -} - -static void -selection_clear_event (GtkWidget *invisible, - GdkEventSelection *event, - EABView *view) +void +e_addressbook_view_save_as (EAddressbookView *view, + gboolean all) { - if (view->clipboard_contacts) { - g_list_foreach (view->clipboard_contacts, (GFunc)g_object_unref, NULL); - g_list_free (view->clipboard_contacts); - view->clipboard_contacts = NULL; - } -} + GList *list = NULL; + EBook *book; -static void -selection_received (GtkWidget *invisible, - GtkSelectionData *selection_data, - guint time, - EABView *view) -{ - if (selection_data->length <= 0 || selection_data->type != GDK_SELECTION_TYPE_STRING) { - return; - } else { - GList *contact_list; - GList *l; - char *str = NULL; + g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (view)); - if (selection_data->data [selection_data->length - 1] != 0) { - str = g_malloc0 (selection_data->length + 1); - memcpy (str, selection_data->data, selection_data->length); - contact_list = eab_contact_list_from_string (str); - } else - contact_list = eab_contact_list_from_string ((char *)selection_data->data); + book = e_addressbook_model_get_book (view->priv->model); - for (l = contact_list; l; l = l->next) { - EContact *contact = l->data; + if (all) { + EBookQuery *query; - /* XXX NULL for a callback /sigh */ - eab_merging_book_add_contact (view->book, contact, NULL /* XXX */, NULL); - } + query = e_book_query_any_field_contains (""); + e_book_get_contacts (book, query, &list, NULL); + e_book_query_unref (query); + } else + list = e_addressbook_view_get_selected (view); - g_list_foreach (contact_list, (GFunc)g_object_unref, NULL); - g_list_free (contact_list); - g_free (str); + if (list != NULL) { + eab_contact_list_save (_("Save as vCard..."), list, NULL); + g_list_foreach (list, (GFunc) g_object_unref, NULL); + g_list_free (list); } } -static void -add_to_list (int model_row, gpointer closure) -{ - GList **list = closure; - *list = g_list_prepend (*list, GINT_TO_POINTER (model_row)); -} - -static GList * -get_selected_contacts (EABView *view) -{ - GList *list; - GList *iterator; - ESelectionModel *selection = get_selection_model (view); - - list = NULL; - e_selection_model_foreach (selection, add_to_list, &list); - - for (iterator = list; iterator; iterator = iterator->next) { - iterator->data = eab_model_get_contact (view->model, GPOINTER_TO_INT (iterator->data)); - } - list = g_list_reverse (list); - return list; -} - void -eab_view_save_as (EABView *view, gboolean all) +e_addressbook_view_view (EAddressbookView *view) { - GList *list = NULL; - EBook *book ; + EAddressbookModel *model; + EBook *book; + GList *list, *iter; + gboolean editable; + gint response; + guint length; - g_object_get(view->model, - "book", &book, - NULL); + g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (view)); - if (all) { - EBookQuery *query = e_book_query_any_field_contains(""); - e_book_get_contacts(book, query, &list, NULL); - e_book_query_unref(query); - } - else { - list = get_selected_contacts(view); + model = e_addressbook_view_get_model (view); + book = e_addressbook_model_get_book (model); + editable = e_addressbook_model_get_editable (model); + + list = e_addressbook_view_get_selected (view); + length = g_list_length (list); + response = GTK_RESPONSE_YES; + + if (length > 5) { + GtkWidget *dialog; + + /* XXX Use e_error_new(). */ + /* XXX Provide a parent window. */ + dialog = gtk_message_dialog_new ( + NULL, 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, + _("Opening %d contacts will open %d new windows as " + "well.\nDo you really want to display all of these " + "contacts?"), length, length); + gtk_dialog_add_buttons ( + GTK_DIALOG (dialog), + _("_Don't Display"), GTK_RESPONSE_NO, + _("Display _All Contacts"), GTK_RESPONSE_YES, + NULL); + response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); } - if (list) - eab_contact_list_save (_("Save as vCard..."), list, NULL); - g_list_foreach (list, (GFunc) g_object_unref, NULL); - g_list_free (list); -} -void -eab_view_view (EABView *view) -{ - GList *list = get_selected_contacts (view); - eab_show_multiple_contacts (view->book, list, view->editable); - g_list_foreach (list, (GFunc) g_object_unref, NULL); - g_list_free (list); -} + if (response == GTK_RESPONSE_YES) + for (iter = list; iter != NULL; iter = iter->next) + addressbook_view_emit_open_contact ( + view, iter->data, FALSE); -void -eab_view_send (EABView *view) -{ - GList *list = get_selected_contacts (view); - if (list) - eab_send_contact_list (list, EAB_DISPOSITION_AS_ATTACHMENT); g_list_foreach (list, (GFunc) g_object_unref, NULL); g_list_free (list); } void -eab_view_send_to (EABView *view) +e_addressbook_view_cut (EAddressbookView *view) { - GList *list = get_selected_contacts (view); - if (list) - eab_send_contact_list (list, EAB_DISPOSITION_AS_TO); - g_list_foreach (list, (GFunc) g_object_unref, NULL); - g_list_free (list); -} + g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (view)); -void -eab_view_cut (EABView *view) -{ - eab_view_copy (view); - eab_view_delete_selection (view, FALSE); + e_addressbook_view_copy (view); + e_addressbook_view_delete_selection (view, FALSE); } -static gboolean -contact_display_has_selection (EABContactDisplay *display) +void +e_addressbook_view_copy (EAddressbookView *view) { - gchar *string; - gint selection_length; - gboolean has_selection; - - string = gtk_html_get_selection_html (GTK_HTML (display), &selection_length); - - has_selection = string ? TRUE : FALSE; + g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (view)); - if (string) - g_free (string); + view->priv->clipboard_contacts = e_addressbook_view_get_selected (view); - return has_selection; + gtk_selection_owner_set ( + view->priv->invisible, + clipboard_atom, GDK_CURRENT_TIME); } void -eab_view_copy (EABView *view) +e_addressbook_view_paste (EAddressbookView *view) { - if (GTK_WIDGET_HAS_FOCUS (view->contact_display) && - contact_display_has_selection (EAB_CONTACT_DISPLAY (view->contact_display))) - { - gtk_html_copy (GTK_HTML (view->contact_display)); - } - else - { - view->clipboard_contacts = get_selected_contacts (view); + g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (view)); - gtk_selection_owner_set (view->invisible, clipboard_atom, GDK_CURRENT_TIME); - } + gtk_selection_convert ( + view->priv->invisible, clipboard_atom, + GDK_SELECTION_TYPE_STRING, GDK_CURRENT_TIME); } void -eab_view_paste (EABView *view) +e_addressbook_view_select_all (EAddressbookView *view) { - gtk_selection_convert (view->invisible, clipboard_atom, - GDK_SELECTION_TYPE_STRING, - GDK_CURRENT_TIME); -} + ESelectionModel *model; -void -eab_view_select_all (EABView *view) -{ - ESelectionModel *model = get_selection_model (view); + g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (view)); + model = e_addressbook_view_get_selection_model (view); g_return_if_fail (model); e_selection_model_select_all (model); } void -eab_view_show_all(EABView *view) +e_addressbook_view_show_all (EAddressbookView *view) { - g_object_set(view, - "query", NULL, - NULL); + g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (view)); + + e_addressbook_model_set_query (view->priv->model, ""); } void -eab_view_stop(EABView *view) +e_addressbook_view_stop (EAddressbookView *view) { - if (view) - eab_model_stop (view->model); + g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (view)); + + e_addressbook_model_stop (view->priv->model); } static void -view_transfer_contacts (EABView *view, gboolean delete_from_source, gboolean all) +view_transfer_contacts (EAddressbookView *view, gboolean delete_from_source, gboolean all) { EBook *book; GList *contacts = NULL; GtkWindow *parent_window; - g_object_get(view->model, - "book", &book, - NULL); + book = e_addressbook_model_get_book (view->priv->model); if (all) { EBookQuery *query = e_book_query_any_field_contains(""); @@ -2085,7 +1429,7 @@ view_transfer_contacts (EABView *view, gboolean delete_from_source, gboolean all e_book_query_unref(query); } else { - contacts = get_selected_contacts (view); + contacts = e_addressbook_view_get_selected (view); } parent_window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))); @@ -2094,132 +1438,13 @@ view_transfer_contacts (EABView *view, gboolean delete_from_source, gboolean all } void -eab_view_copy_to_folder (EABView *view, gboolean all) +e_addressbook_view_copy_to_folder (EAddressbookView *view, gboolean all) { view_transfer_contacts (view, FALSE, all); } void -eab_view_move_to_folder (EABView *view, gboolean all) +e_addressbook_view_move_to_folder (EAddressbookView *view, gboolean all) { view_transfer_contacts (view, TRUE, all); } - - -static gboolean -eab_view_selection_nonempty (EABView *view) -{ - ESelectionModel *selection_model; - - selection_model = get_selection_model (view); - if (selection_model == NULL) - return FALSE; - - return e_selection_model_selected_count (selection_model) != 0; -} - -gboolean -eab_view_can_create (EABView *view) -{ - return view ? eab_model_editable (view->model) : FALSE; -} - -gboolean -eab_view_can_print (EABView *view) -{ - return view && view->model ? eab_model_contact_count (view->model) : FALSE; -} - -gboolean -eab_view_can_save_as (EABView *view) -{ - return view ? eab_view_selection_nonempty (view) : FALSE; -} - -gboolean -eab_view_can_view (EABView *view) -{ - return view ? eab_view_selection_nonempty (view) : FALSE; -} - -gboolean -eab_view_can_send (EABView *view) -{ - return view ? eab_view_selection_nonempty (view) : FALSE; -} - -gboolean -eab_view_can_send_to (EABView *view) -{ - return view ? eab_view_selection_nonempty (view) : FALSE; -} - -gboolean -eab_view_can_delete (EABView *view) -{ - return view ? eab_view_selection_nonempty (view) && eab_model_editable (view->model) : FALSE; -} - -gboolean -eab_view_can_cut (EABView *view) -{ - return view ? eab_view_selection_nonempty (view) && eab_model_editable (view->model) : FALSE; -} - -gboolean -eab_view_can_copy (EABView *view) -{ - return view ? eab_view_selection_nonempty (view) : FALSE; -} - -gboolean -eab_view_can_paste (EABView *view) -{ - return view ? eab_model_editable (view->model) : FALSE; -} - -gboolean -eab_view_can_select_all (EABView *view) -{ - return view ? eab_model_contact_count (view->model) != 0 : FALSE; -} - -gboolean -eab_view_can_stop (EABView *view) -{ - return view ? eab_model_can_stop (view->model) : FALSE; -} - -gboolean -eab_view_can_copy_to_folder (EABView *view) -{ - return view ? eab_view_selection_nonempty (view) : FALSE; -} - -gboolean -eab_view_can_move_to_folder (EABView *view) -{ - return view ? eab_view_selection_nonempty (view) && eab_model_editable (view->model) : FALSE; -} - -EABMenuTargetSelect * -eab_view_get_menu_target (EABView *view, EABMenu *menu) -{ - GPtrArray *cards = g_ptr_array_new(); - ESelectionModel *selection_model; - EABMenuTargetSelect *t; - - selection_model = get_selection_model (view); - if (selection_model) { - ContactAndBook cab; - - cab.view = view; - cab.closure = cards; - e_selection_model_foreach(selection_model, get_card_1, &cab); - } - - t = eab_menu_target_new_select(menu, view->book, !eab_model_editable(view->model), cards); - t->target.widget = (GtkWidget *)view; - - return t; -} diff --git a/addressbook/gui/widgets/e-addressbook-view.h b/addressbook/gui/widgets/e-addressbook-view.h index c9ac35d2fa..4e4e7c8178 100644 --- a/addressbook/gui/widgets/e-addressbook-view.h +++ b/addressbook/gui/widgets/e-addressbook-view.h @@ -20,145 +20,105 @@ * */ -#ifndef __EAB_VIEW_H__ -#define __EAB_VIEW_H__ +#ifndef E_ADDRESSBOOK_VIEW_H +#define E_ADDRESSBOOK_VIEW_H -#include <gtk/gtk.h> -#include <bonobo/bonobo-ui-component.h> -#include <widgets/menus/gal-view-instance.h> +#include <e-shell-view.h> #include <libebook/e-book.h> +#include <libebook/e-contact.h> +#include <widgets/menus/gal-view-instance.h> +#include <widgets/misc/e-selection-model.h> + #include "e-addressbook-model.h" #include "eab-contact-display.h" -#include "widgets/menus/gal-view-menus.h" -#include "misc/e-search-bar.h" -#include "misc/e-filter-bar.h" - -G_BEGIN_DECLS - -struct _EABMenu; -struct _EABMenuTargetSelect; - -/* EABView - A card displaying information about a contact. - * - * The following arguments are available: - * - * name type read/write description - * -------------------------------------------------------------------------------- - */ - -#define E_TYPE_AB_VIEW (eab_view_get_type ()) -#define EAB_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_AB_VIEW, EABView)) -#define EAB_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_AB_VIEW, EABViewClass)) -#define E_IS_ADDRESSBOOK_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_AB_VIEW)) -#define E_IS_ADDRESSBOOK_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_AB_VIEW)) -typedef enum { - EAB_VIEW_NONE, /* initialized to this */ - EAB_VIEW_MINICARD, - EAB_VIEW_TABLE, -} EABViewType; +/* Standard GObject macros */ +#define E_TYPE_ADDRESSBOOK_VIEW \ + (e_addressbook_view_get_type ()) +#define E_ADDRESSBOOK_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_ADDRESSBOOK_VIEW, EAddressbookView)) +#define E_ADDRESSBOOK_VIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_ADDRESSBOOK_VIEW, EAddressbookViewClass)) +#define E_IS_ADDRESSBOOK_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_ADDRESSBOOK_VIEW)) +#define E_IS_ADDRESSBOOK_VIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((obj), E_TYPE_ADDRESSBOOK_VIEW)) +#define E_ADDRESSBOOK_VIEW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_ADDRESSBOOK_VIEW, EAddressbookViewClass)) +G_BEGIN_DECLS -typedef struct _EABView EABView; -typedef struct _EABViewClass EABViewClass; +typedef struct _EAddressbookView EAddressbookView; +typedef struct _EAddressbookViewClass EAddressbookViewClass; +typedef struct _EAddressbookViewPrivate EAddressbookViewPrivate; -struct _EABView -{ +struct _EAddressbookView { GtkVBox parent; - - /* item specific fields */ - EABViewType view_type; - - EABModel *model; - - GtkWidget *invisible; - GList *clipboard_contacts; - - EBook *book; - ESource *source; - char *query; - guint editable : 1; - - gint displayed_contact; - - GObject *object; - GtkWidget *widget; - - GtkWidget *contact_display_window; - GtkWidget *contact_display; - GtkWidget *paned; - - /* Menus handler and the view instance */ - GalViewInstance *view_instance; - GalViewMenus *view_menus; - GalView *current_view; - BonoboUIComponent *uic; - - /* the search bar and related machinery */ - EFilterBar *search; - gint ecml_changed_id; - RuleContext *search_context; - FilterRule *search_rule; + EAddressbookViewPrivate *priv; }; -struct _EABViewClass -{ +struct _EAddressbookViewClass { GtkVBoxClass parent_class; - /* - * Signals - */ - void (*status_message) (EABView *view, const gchar *message); - void (*search_result) (EABView *view, EBookViewStatus status); - void (*folder_bar_message) (EABView *view, const gchar *message); - void (*command_state_change) (EABView *view); + /* Signals */ + void (*open_contact) (EAddressbookView *view, + EContact *contact, + gboolean is_new_contact); + void (*popup_event) (EAddressbookView *view, + GdkEvent *event); + void (*status_message) (EAddressbookView *view, + const gchar *message); + void (*command_state_change) (EAddressbookView *view); + void (*selection_change) (EAddressbookView *view); }; -GtkWidget *eab_view_new (void); -GType eab_view_get_type (void); - -void eab_view_show_contact_preview (EABView *view, gboolean show); - -void eab_view_setup_menus (EABView *view, - BonoboUIComponent *uic); -void eab_view_discard_menus (EABView *view); - -RuleContext *eab_view_peek_search_context (EABView *view); -FilterRule *eab_view_peek_search_rule (EABView *view); - -void eab_view_save_as (EABView *view, gboolean all); -void eab_view_view (EABView *view); -void eab_view_send (EABView *view); -void eab_view_send_to (EABView *view); -void eab_view_print (EABView *view, - GtkPrintOperationAction action); -void eab_view_delete_selection (EABView *view, gboolean is_delete); -void eab_view_cut (EABView *view); -void eab_view_copy (EABView *view); -void eab_view_paste (EABView *view); -void eab_view_select_all (EABView *view); -void eab_view_show_all (EABView *view); -void eab_view_stop (EABView *view); -void eab_view_copy_to_folder (EABView *view, gboolean all); -void eab_view_move_to_folder (EABView *view, gboolean all); - -gboolean eab_view_can_create (EABView *view); -gboolean eab_view_can_print (EABView *view); -gboolean eab_view_can_save_as (EABView *view); -gboolean eab_view_can_view (EABView *view); -gboolean eab_view_can_send (EABView *view); -gboolean eab_view_can_send_to (EABView *view); -gboolean eab_view_can_delete (EABView *view); -gboolean eab_view_can_cut (EABView *view); -gboolean eab_view_can_copy (EABView *view); -gboolean eab_view_can_paste (EABView *view); -gboolean eab_view_can_select_all (EABView *view); -gboolean eab_view_can_stop (EABView *view); -gboolean eab_view_can_copy_to_folder (EABView *view); -gboolean eab_view_can_move_to_folder (EABView *view); - -struct _EABMenuTargetSelect *eab_view_get_menu_target (EABView *view, struct _EABMenu *menu); +GType e_addressbook_view_get_type (void); +GtkWidget * e_addressbook_view_new (EShellView *shell_view, + ESource *source); +EAddressbookModel * + e_addressbook_view_get_model (EAddressbookView *view); +GalViewInstance * + e_addressbook_view_get_view_instance + (EAddressbookView *view); +GObject * e_addressbook_view_get_view_object + (EAddressbookView *view); +GtkWidget * e_addressbook_view_get_view_widget + (EAddressbookView *view); +GList * e_addressbook_view_get_selected (EAddressbookView *view); +ESelectionModel * + e_addressbook_view_get_selection_model + (EAddressbookView *view); +EShellView * e_addressbook_view_get_shell_view + (EAddressbookView *view); +ESource * e_addressbook_view_get_source (EAddressbookView *view); +void e_addressbook_view_save_as (EAddressbookView *view, + gboolean all); +void e_addressbook_view_view (EAddressbookView *view); +void e_addressbook_view_print (EAddressbookView *view, + GtkPrintOperationAction action); +void e_addressbook_view_delete_selection + (EAddressbookView *view, + gboolean is_delete); +void e_addressbook_view_cut (EAddressbookView *view); +void e_addressbook_view_copy (EAddressbookView *view); +void e_addressbook_view_paste (EAddressbookView *view); +void e_addressbook_view_select_all (EAddressbookView *view); +void e_addressbook_view_show_all (EAddressbookView *view); +void e_addressbook_view_stop (EAddressbookView *view); +void e_addressbook_view_copy_to_folder + (EAddressbookView *view, + gboolean all); +void e_addressbook_view_move_to_folder + (EAddressbookView *view, + gboolean all); + +gboolean e_addressbook_view_can_create (EAddressbookView *view); G_END_DECLS -#endif /* __EAB_VIEW_H__ */ +#endif /* E_ADDRESSBOOK_VIEW_H */ diff --git a/addressbook/gui/widgets/e-minicard-view-widget.c b/addressbook/gui/widgets/e-minicard-view-widget.c index 0f9ae7c143..3ad49cf2b3 100644 --- a/addressbook/gui/widgets/e-minicard-view-widget.c +++ b/addressbook/gui/widgets/e-minicard-view-widget.c @@ -53,6 +53,8 @@ enum { }; enum { + CREATE_CONTACT, + CREATE_CONTACT_LIST, SELECTION_CHANGE, COLUMN_WIDTH_CHANGED, RIGHT_CLICK, @@ -140,6 +142,24 @@ e_minicard_view_widget_class_init (EMinicardViewWidgetClass *class) 0.0, G_MAXDOUBLE, 150.0, G_PARAM_READWRITE)); + signals [CREATE_CONTACT] = + g_signal_new ("create-contact", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMinicardViewWidgetClass, create_contact), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals [CREATE_CONTACT_LIST] = + g_signal_new ("create-contact-list", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMinicardViewWidgetClass, create_contact_list), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals [SELECTION_CHANGE] = g_signal_new ("selection_change", G_OBJECT_CLASS_TYPE (object_class), @@ -315,6 +335,18 @@ column_width_changed (ESelectionModel *esm, double width, EMinicardViewWidget *w signals [COLUMN_WIDTH_CHANGED], 0, width); } +static void +create_contact (EMinicardView *view, EMinicardViewWidget *widget) +{ + g_signal_emit (widget, signals[CREATE_CONTACT], 0); +} + +static void +create_contact_list (EMinicardView *view, EMinicardViewWidget *widget) +{ + g_signal_emit (widget, signals[CREATE_CONTACT_LIST], 0); +} + static guint right_click (EMinicardView *view, GdkEvent *event, EMinicardViewWidget *widget) { @@ -370,6 +402,12 @@ e_minicard_view_widget_realize (GtkWidget *widget) "column_width_changed", G_CALLBACK (column_width_changed), view); g_signal_connect (view->emv, + "create-contact", + G_CALLBACK (create_contact), view); + g_signal_connect (view->emv, + "create-contact-list", + G_CALLBACK (create_contact_list), view); + g_signal_connect (view->emv, "right_click", G_CALLBACK (right_click), view); diff --git a/addressbook/gui/widgets/e-minicard-view-widget.h b/addressbook/gui/widgets/e-minicard-view-widget.h index 1c4323523f..917d1b588a 100644 --- a/addressbook/gui/widgets/e-minicard-view-widget.h +++ b/addressbook/gui/widgets/e-minicard-view-widget.h @@ -58,6 +58,8 @@ struct _EMinicardViewWidget struct _EMinicardViewWidgetClass { ECanvasClass parent_class; + void (*create_contact) (EMinicardViewWidget *emvw); + void (*create_contact_list) (EMinicardViewWidget *emvw); void (*selection_change) (EMinicardViewWidget *emvw); void (*column_width_changed) (EMinicardViewWidget *emvw, double width); guint (*right_click) (EMinicardViewWidget *emvw); diff --git a/addressbook/gui/widgets/e-minicard-view.c b/addressbook/gui/widgets/e-minicard-view.c index ccf3ecc6f9..32957fdf33 100644 --- a/addressbook/gui/widgets/e-minicard-view.c +++ b/addressbook/gui/widgets/e-minicard-view.c @@ -33,6 +33,7 @@ #include <misc/e-canvas.h> #include <glib/gi18n.h> #include <string.h> +#include "e-util/e-util.h" #include "a11y/addressbook/ea-addressbook.h" static void e_minicard_view_drag_data_get(GtkWidget *widget, @@ -56,6 +57,8 @@ enum { enum { + CREATE_CONTACT, + CREATE_CONTACT_LIST, RIGHT_CLICK, LAST_SIGNAL }; @@ -160,7 +163,7 @@ set_empty_message (EMinicardView *view) EBook *book; if (view->adapter) { - EABModel *model = NULL; + EAddressbookModel *model = NULL; g_object_get (view->adapter, "editable", &editable, @@ -171,7 +174,7 @@ set_empty_message (EMinicardView *view) if (!e_book_check_static_capability (book, "do-initial-query")) perform_initial_query = TRUE; - searching = model && eab_model_can_stop (model); + searching = model && e_addressbook_model_can_stop (model); } if (searching) { @@ -196,13 +199,13 @@ set_empty_message (EMinicardView *view) } static void -writable_status_change (EABModel *model, gboolean writable, EMinicardView *view) +writable_status_change (EAddressbookModel *model, gboolean writable, EMinicardView *view) { set_empty_message (view); } static void -stop_state_changed (EABModel *model, EMinicardView *view) +stop_state_changed (EAddressbookModel *model, EMinicardView *view) { set_empty_message (view); } @@ -230,7 +233,7 @@ e_minicard_view_set_property (GObject *object, case PROP_ADAPTER: if (view->adapter) { if (view->writable_status_id || view->stop_state_id) { - EABModel *model; + EAddressbookModel *model; g_object_get (view->adapter, "model", &model, NULL); @@ -253,7 +256,7 @@ e_minicard_view_set_property (GObject *object, "model", view->adapter, NULL); if (view->adapter) { - EABModel *model; + EAddressbookModel *model; g_object_get (view->adapter, "model", &model, NULL); @@ -338,7 +341,7 @@ e_minicard_view_dispose (GObject *object) if (view->adapter) { if (view->writable_status_id || view->stop_state_id) { - EABModel *model; + EAddressbookModel *model; g_object_get (view->adapter, "model", &model, NULL); @@ -383,13 +386,8 @@ e_minicard_view_event (GnomeCanvasItem *item, GdkEvent *event) g_object_get(view->adapter, "editable", &editable, NULL); - if (editable) { - EBook *book; - g_object_get(view, "book", &book, NULL); - - if (book && E_IS_BOOK (book)) - eab_show_contact_editor (book, e_contact_new(), TRUE, editable); - } + if (editable) + e_minicard_view_create_contact (view); return TRUE; } case GDK_BUTTON_PRESS: @@ -547,6 +545,22 @@ e_minicard_view_class_init (EMinicardViewClass *klass) FALSE, G_PARAM_READWRITE)); + signals [CREATE_CONTACT] = + g_signal_new ("create-contact", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals [CREATE_CONTACT_LIST] = + g_signal_new ("create-contact-list", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals [RIGHT_CLICK] = g_signal_new ("right_click", G_OBJECT_CLASS_TYPE (object_class), @@ -655,3 +669,19 @@ e_minicard_view_get_card_list (EMinicardView *view) mal.list = g_list_reverse (mal.list); return mal.list; } + +void +e_minicard_view_create_contact (EMinicardView *view) +{ + g_return_if_fail (E_IS_MINICARD_VIEW (view)); + + g_signal_emit (view, signals[CREATE_CONTACT], 0); +} + +void +e_minicard_view_create_contact_list (EMinicardView *view) +{ + g_return_if_fail (E_IS_MINICARD_VIEW (view)); + + g_signal_emit (view, signals[CREATE_CONTACT_LIST], 0); +} diff --git a/addressbook/gui/widgets/e-minicard-view.h b/addressbook/gui/widgets/e-minicard-view.h index 7d0a5b1842..4cdf9be7be 100644 --- a/addressbook/gui/widgets/e-minicard-view.h +++ b/addressbook/gui/widgets/e-minicard-view.h @@ -91,6 +91,8 @@ void e_minicard_view_remove_selection (EMinicardView *view, void e_minicard_view_jump_to_letter (EMinicardView *view, gunichar letter); GList *e_minicard_view_get_card_list (EMinicardView *view); +void e_minicard_view_create_contact (EMinicardView *view); +void e_minicard_view_create_contact_list (EMinicardView *view); G_END_DECLS diff --git a/addressbook/gui/widgets/e-minicard.c b/addressbook/gui/widgets/e-minicard.c index cbbcc80d5c..3e5e8ec3bf 100644 --- a/addressbook/gui/widgets/e-minicard.c +++ b/addressbook/gui/widgets/e-minicard.c @@ -35,7 +35,6 @@ #include "e-minicard.h" #include "e-minicard-label.h" #include "e-minicard-view.h" -#include "e-contact-editor.h" #include <e-util/e-html-utils.h> #include <e-util/e-icon-factory.h> #include <libebook/e-destination.h> @@ -86,6 +85,7 @@ enum { enum { SELECTED, DRAG_BEGIN, + OPEN_CONTACT, STYLE_SET, LAST_SIGNAL }; @@ -101,7 +101,7 @@ common_location [] = { "OTHER", N_ ("Other Email") } }; -static guint e_minicard_signals [LAST_SIGNAL] = {0, }; +static guint signals [LAST_SIGNAL] = {0, }; GType e_minicard_get_type (void) @@ -200,7 +200,7 @@ e_minicard_class_init (EMinicardClass *class) E_TYPE_CONTACT, G_PARAM_READWRITE)); - e_minicard_signals [SELECTED] = + signals [SELECTED] = g_signal_new ("selected", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, @@ -209,7 +209,7 @@ e_minicard_class_init (EMinicardClass *class) e_marshal_INT__POINTER, G_TYPE_INT, 1, G_TYPE_POINTER); - e_minicard_signals [DRAG_BEGIN] = + signals [DRAG_BEGIN] = g_signal_new ("drag_begin", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, @@ -218,7 +218,17 @@ e_minicard_class_init (EMinicardClass *class) e_marshal_INT__POINTER, G_TYPE_INT, 1, G_TYPE_POINTER); - e_minicard_signals [STYLE_SET] = + signals [OPEN_CONTACT] = + g_signal_new ("open-contact", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMinicardClass, open_contact), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + E_TYPE_CONTACT); + + signals [STYLE_SET] = g_signal_new ("style_set", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, @@ -249,8 +259,6 @@ e_minicard_init (EMinicard *minicard) minicard->list_icon_pixbuf = e_icon_factory_get_icon (LIST_ICON_NAME, E_ICON_SIZE_MENU); minicard->list_icon_size = gdk_pixbuf_get_height (minicard->list_icon_pixbuf); - minicard->editor = NULL; - minicard->changed = FALSE; e_canvas_item_set_reflow_callback(GNOME_CANVAS_ITEM(minicard), e_minicard_reflow); @@ -528,50 +536,12 @@ e_minicard_unrealize (GnomeCanvasItem *item) (* GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize) (item); } -/* Callback used when the contact editor is closed */ -static void -editor_closed_cb (GtkObject *editor, gpointer data) -{ - EMinicard *minicard = data; - g_object_unref (editor); - minicard->editor = NULL; -} - -gboolean -e_minicard_activate_editor(EMinicard *minicard) +void +e_minicard_activate_editor (EMinicard *minicard) { - GnomeCanvasItem *item = (GnomeCanvasItem *)minicard; - - if (minicard->editor) { - eab_editor_raise (minicard->editor); - } - else { - EBook *book = NULL; - if (E_IS_MINICARD_VIEW(item->parent)) { - g_object_get(item->parent, "book", &book, NULL); - } - - if (book != NULL) { - if (e_contact_get (minicard->contact, E_CONTACT_IS_LIST)) { - EContactListEditor *editor = eab_show_contact_list_editor (book, minicard->contact, - FALSE, e_book_is_writable (book)); - minicard->editor = EAB_EDITOR (editor); - } - else { - EContactEditor *editor = eab_show_contact_editor (book, minicard->contact, - FALSE, e_book_is_writable (book)); - minicard->editor = EAB_EDITOR (editor); - } - - g_object_ref (minicard->editor); - g_signal_connect (minicard->editor, "editor_closed", - G_CALLBACK (editor_closed_cb), minicard); - - g_object_unref (book); - } - } + g_return_if_fail (E_IS_MINICARD (minicard)); - return TRUE; + g_signal_emit (minicard, signals[OPEN_CONTACT], 0, minicard->contact); } static gboolean @@ -655,7 +625,8 @@ e_minicard_event (GnomeCanvasItem *item, GdkEvent *event) break; case GDK_2BUTTON_PRESS: if (event->button.button == 1 && E_IS_MINICARD_VIEW (item->parent)) { - return e_minicard_activate_editor (e_minicard); + e_minicard_activate_editor (e_minicard); + return TRUE; } break; case GDK_KEY_PRESS: @@ -725,7 +696,8 @@ e_minicard_event (GnomeCanvasItem *item, GdkEvent *event) } else if (event->key.keyval == GDK_Return || event->key.keyval == GDK_KP_Enter) { - return e_minicard_activate_editor (e_minicard); + e_minicard_activate_editor (e_minicard); + return TRUE; } break; default: @@ -1154,7 +1126,7 @@ e_minicard_drag_begin (EMinicard *minicard, GdkEvent *event) gint ret_val = 0; GnomeCanvasItem *parent; g_signal_emit (minicard, - e_minicard_signals[DRAG_BEGIN], 0, + signals[DRAG_BEGIN], 0, event, &ret_val); parent = GNOME_CANVAS_ITEM (minicard)->parent; diff --git a/addressbook/gui/widgets/e-minicard.h b/addressbook/gui/widgets/e-minicard.h index 71c976745f..98a4629ad9 100644 --- a/addressbook/gui/widgets/e-minicard.h +++ b/addressbook/gui/widgets/e-minicard.h @@ -24,7 +24,6 @@ #define __E_MINICARD_H__ #include <gtk/gtk.h> -#include "addressbook/gui/contact-editor/eab-editor.h" #include <libgnomecanvas/gnome-canvas.h> #include <libebook/e-contact.h> @@ -75,8 +74,6 @@ struct _EMinicard GdkPixbuf *list_icon_pixbuf; double list_icon_size; - EABEditor *editor; - GList *fields; /* Of type EMinicardField */ guint needs_remodeling : 1; @@ -105,6 +102,7 @@ struct _EMinicardClass gint (* selected) (EMinicard *minicard, GdkEvent *event); gint (* drag_begin) (EMinicard *minicard, GdkEvent *event); + void (* open_contact) (EMinicard *minicard, EContact *contact); void (* style_set) (EMinicard *minicard, GtkStyle *previous_style); }; @@ -125,7 +123,7 @@ int e_minicard_compare (EMinicard *minicard1, int e_minicard_selected (EMinicard *minicard, GdkEvent *event); -gboolean e_minicard_activate_editor (EMinicard *minicard); +void e_minicard_activate_editor (EMinicard *minicard); #ifdef __cplusplus } diff --git a/addressbook/gui/widgets/eab-contact-display.c b/addressbook/gui/widgets/eab-contact-display.c index 4e7418dc5c..42cc65294f 100644 --- a/addressbook/gui/widgets/eab-contact-display.c +++ b/addressbook/gui/widgets/eab-contact-display.c @@ -25,27 +25,46 @@ #endif #include "eab-contact-display.h" -#include "eab-popup.h" #include "eab-gui-util.h" #include "e-util/e-util.h" #include "e-util/e-html-utils.h" #include "e-util/e-icon-factory.h" +#include "e-util/e-plugin-ui.h" #include <string.h> #include <glib/gi18n.h> #include <gtkhtml/gtkhtml.h> #include <gtkhtml/gtkhtml-stream.h> -#define HANDLE_MAILTO_INTERNALLY 1 +#define EAB_CONTACT_DISPLAY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), EAB_TYPE_CONTACT_DISPLAY, EABContactDisplayPrivate)) -#define PARENT_TYPE (GTK_TYPE_HTML) +#define HANDLE_MAILTO_INTERNALLY 1 struct _EABContactDisplayPrivate { EContact *contact; + EABContactDisplayMode mode; + GtkUIManager *ui_manager; + GtkActionGroup *email_actions; + GtkActionGroup *uri_actions; GtkWidget *invisible; - char *selection_uri; + + gchar *selected_uri; + gchar *clipboard_uri; +}; + +enum { + PROP_0, + PROP_CONTACT, + PROP_MODE +}; + +enum { + SEND_MESSAGE, + LAST_SIGNAL }; static struct { @@ -77,151 +96,154 @@ common_location [] = #define MAX_COMPACT_IMAGE_DIMENSION 48 -static void -eab_uri_popup_link_open(EPopup *ep, EPopupItem *item, void *data) -{ - EABPopupTargetURI *t = (EABPopupTargetURI *)ep->target; - - /* FIXME Pass a parent window. */ - e_show_uri (NULL, t->uri); -} +static const gchar *ui = +"<ui>" +" <popup>" +" <menuitem action='open-link'/>" +" <menuitem action='copy-link'/>" +" <menuitem action='send-message'/>" +" <menuitem action='copy-address'/>" +" </popup>" +"</ui>"; -static void -eab_uri_popup_email_address_copy(EPopup *ep, EPopupItem *item, void *data) -{ - EABContactDisplay *display = data; - struct _EABContactDisplayPrivate *p = display->priv; - EABPopupTargetURI *t = (EABPopupTargetURI *)ep->target; - const char *url = t->uri; - char *html=NULL; - int i=0; - GList *email_list, *l; - int email_num = atoi (url + strlen ("internal-mailto:")); - - email_list = e_contact_get (p->contact, E_CONTACT_EMAIL); - for (l = email_list; l; l=l->next) { - if(i==email_num) - html = e_text_to_html (l->data, 0); - i++; - } - - g_free(p->selection_uri); - p->selection_uri = g_strdup(html); - g_free (html); - - gtk_selection_owner_set(p->invisible, GDK_SELECTION_PRIMARY, gtk_get_current_event_time()); - gtk_selection_owner_set(p->invisible, GDK_SELECTION_CLIPBOARD, gtk_get_current_event_time()); -} +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; static void -eab_uri_popup_link_copy(EPopup *ep, EPopupItem *pitem, void *data) +action_copy_address_cb (GtkAction *action, + EABContactDisplay *display) { - EABContactDisplay *display = data; - struct _EABContactDisplayPrivate *p = display->priv; - - g_free(p->selection_uri); - p->selection_uri = g_strdup(pitem->user_data); - - gtk_selection_owner_set(p->invisible, GDK_SELECTION_PRIMARY, gtk_get_current_event_time()); - gtk_selection_owner_set(p->invisible, GDK_SELECTION_CLIPBOARD, gtk_get_current_event_time()); + EContact *contact; + GList *list; + const gchar *uri; + gchar *html; + gint index; + + uri = display->priv->selected_uri; + index = atoi (uri + strlen ("internal-mailto:")); + contact = eab_contact_display_get_contact (display); + + list = e_contact_get (contact, E_CONTACT_EMAIL); + html = e_text_to_html (g_list_nth_data (list, index), 0); + g_list_foreach (list, (GFunc) g_free, NULL); + g_list_free (list); + + display->priv->clipboard_uri = html; + display->priv->selected_uri = NULL; + + gtk_selection_owner_set ( + display->priv->invisible, GDK_SELECTION_PRIMARY, + gtk_get_current_event_time ()); + gtk_selection_owner_set ( + display->priv->invisible, GDK_SELECTION_CLIPBOARD, + gtk_get_current_event_time ()); } static void -eab_uri_popup_address_send(EPopup *ep, EPopupItem *item, void *data) +action_copy_link_cb (GtkAction *action, + EABContactDisplay *display) { - EABPopupTargetURI *t = (EABPopupTargetURI *)ep->target; - const char *url = t->uri; - EABContactDisplay *display = data; - struct _EABContactDisplayPrivate *p = display->priv; - - int mail_num = atoi (url + strlen ("internal-mailto:")); - - if (mail_num == -1) - return; - - eab_send_contact (p->contact, mail_num, EAB_DISPOSITION_AS_TO); - + display->priv->clipboard_uri = display->priv->selected_uri; + display->priv->selected_uri = NULL; + + gtk_selection_owner_set ( + display->priv->invisible, GDK_SELECTION_PRIMARY, + gtk_get_current_event_time ()); + gtk_selection_owner_set ( + display->priv->invisible, GDK_SELECTION_CLIPBOARD, + gtk_get_current_event_time ()); } static void -eab_selection_get(GtkWidget *widget, GtkSelectionData *data, guint info, guint time_stamp, EABContactDisplay *display) +action_open_link_cb (GtkAction *action, + EABContactDisplay *display) { - struct _EABContactDisplayPrivate *p = display->priv; - - if (p->selection_uri == NULL) - return; - - gtk_selection_data_set(data, data->target, 8, (guchar *)p->selection_uri, strlen(p->selection_uri)); + /* XXX Pass a parent window. */ + e_show_uri (NULL, display->priv->selected_uri); } static void -eab_selection_clear_event(GtkWidget *widget, GdkEventSelection *event, EABContactDisplay *display) +action_send_message_cb (GtkAction *action, + EABContactDisplay *display) { -#if 0 - struct _EABContactDisplayPrivate *p = display->priv; - - g_free(p->selection_uri); - p->selection_uri = NULL; -#endif + EDestination *destination; + EContact *contact; + const gchar *uri; + gint row; + + uri = display->priv->selected_uri; + row = atoi (uri + strlen ("internal-mailto:")); + g_return_if_fail (row >= 0); + + destination = e_destination_new (); + contact = eab_contact_display_get_contact (display); + e_destination_set_contact (destination, contact, row); + g_signal_emit (display, signals[SEND_MESSAGE], 0, destination); + g_object_unref (destination); } -static EPopupItem eab_uri_popups[] = { - { E_POPUP_ITEM, "05.open", N_("_Open Link in Browser"), eab_uri_popup_link_open, NULL, NULL, EAB_POPUP_URI_NOT_MAILTO }, - { E_POPUP_ITEM, "10.copy", N_("_Copy Link Location"), eab_uri_popup_link_copy, NULL, "edit-copy", EAB_POPUP_URI_NOT_MAILTO }, - { E_POPUP_ITEM, "15.send", N_("_Send New Message To..."), eab_uri_popup_address_send, NULL, "mail-message-new", EAB_POPUP_URI_MAILTO}, - { E_POPUP_ITEM, "20.copy", N_("Copy _Email Address"), eab_uri_popup_email_address_copy, NULL, "edit-copy", EAB_POPUP_URI_MAILTO}, - }; +static GtkActionEntry email_entries[] = { + + { "copy-address", + NULL, + N_("Copy _Email Address"), + NULL, + NULL, + G_CALLBACK (action_copy_address_cb) }, + + { "send-message", + NULL, + N_("_Send New Message To..."), + NULL, + NULL, + G_CALLBACK (action_send_message_cb) } +}; +static GtkActionEntry uri_entries[] = { + + { "copy-link", + NULL, + N_("_Copy Link Location"), + NULL, + NULL, + G_CALLBACK (action_copy_link_cb) }, + + { "open-link", + NULL, + N_("_Open Link in Browser"), + NULL, + NULL, + G_CALLBACK (action_open_link_cb) } +}; static void -eab_uri_popup_free(EPopup *ep, GSList *list, void *data) +contact_display_selection_get (EABContactDisplay *display, + GtkSelectionData *data, + guint info, + guint time_stamp) { - while (list){ - GSList *n = list->next; - struct _EPopupItem *item = list->data; - - g_free(item->user_data); - item->user_data = NULL; - g_slist_free_1(list); + if (display->priv->clipboard_uri == NULL) + return; - list = n; - } + gtk_selection_data_set ( + data, data->target, 8, + (guchar *) display->priv->clipboard_uri, + strlen (display->priv->clipboard_uri)); } -static int -eab_uri_popup_event(EABContactDisplay *display, GdkEvent *event, const char *uri) +static void +contact_display_selection_clear_event (EABContactDisplay *display, + GdkEventSelection *event) { - EABPopup *emp; - EABPopupTargetURI *t ; - GtkMenu *menu; - GSList *menus = NULL; - int i; - - emp = eab_popup_new("org.gnome.evolution.addressbook.contactdisplay.popup"); - - t = eab_popup_target_new_uri(emp, uri); - t->target.widget = (GtkWidget *)display; - - for (i=0;i<sizeof(eab_uri_popups)/sizeof(eab_uri_popups[0]);i++) { - eab_uri_popups[i].user_data = g_strdup(t->uri); - menus = g_slist_prepend(menus, &eab_uri_popups[i]); - } - e_popup_add_items((EPopup *)emp, menus, NULL, eab_uri_popup_free, display); - - menu = e_popup_create_menu_once((EPopup *)emp,(EPopupTarget*)t, 0); - - if (event == NULL) { - gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time()); - } else { - gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button.button, event->button.time); - } - - return TRUE; + g_free (display->priv->clipboard_uri); + display->priv->clipboard_uri = NULL; } static void -on_url_requested (GtkHTML *html, const char *url, GtkHTMLStream *handle, - EABContactDisplay *display) +contact_display_on_url_requested (GtkHTML *html, + const gchar *url, + GtkHTMLStream *handle, + EABContactDisplay *display) { if (!strcmp (url, "internal-contact-photo:")) { EContactPhoto *photo; @@ -254,16 +276,25 @@ on_url_requested (GtkHTML *html, const char *url, GtkHTMLStream *handle, } static void -on_link_clicked (GtkHTML *html, const char *uri, EABContactDisplay *display) +contact_display_on_link_clicked (GtkHTML *html, + const gchar *uri, + EABContactDisplay *display) { #ifdef HANDLE_MAILTO_INTERNALLY if (!strncmp (uri, "internal-mailto:", strlen ("internal-mailto:"))) { - int mail_num = atoi (uri + strlen ("internal-mailto:")); + EDestination *destination; + EContact *contact; + gint email_num; - if (mail_num == -1) + email_num = atoi (uri + strlen ("internal-mailto:")); + if (email_num == -1) return; - eab_send_contact (display->priv->contact, mail_num, EAB_DISPOSITION_AS_TO); + destination = e_destination_new (); + contact = eab_contact_display_get_contact (display); + e_destination_set_contact (destination, contact, email_num); + g_signal_emit (display, signals[SEND_MESSAGE], 0, destination); + g_object_unref (destination); return; } @@ -273,44 +304,6 @@ on_link_clicked (GtkHTML *html, const char *uri, EABContactDisplay *display) e_show_uri (NULL, uri); } -#if 0 -static void -render_address (GtkHTMLStream *html_stream, EContact *contact, const char *html_label, EContactField adr_field, EContactField label_field) -{ - EContactAddress *adr; - const char *label; - - label = e_contact_get_const (contact, label_field); - if (label) { - char *html = e_text_to_html (label, E_TEXT_TO_HTML_CONVERT_NL); - - gtk_html_stream_printf (html_stream, "<tr><td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\"></td><td valign=\"top\" width=\"100\"><font color=" HEADER_COLOR ">%s:</font><br><a href=\"http://www.mapquest.com/\">%s</a></td><td valign=\"top\">%s</td></tr>", html_label, _("(map)"), html); - -This shoul g_free (html); - return; - } - - adr = e_contact_get (contact, adr_field); - if (adr && - (adr->po || adr->ext || adr->street || adr->locality || adr->region || adr->code || adr->country)) { - - gtk_html_stream_printf (html_stream, "<tr><td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\"></td><td valign=\"top\" width=\"100\"><font color=" HEADER_COLOR ">%s:</font><br><a href=\"http://www.mapquest.com/\">%s</a></td><td valign=\"top\">", html_label, _("map")); - - if (adr->po && *adr->po) gtk_html_stream_printf (html_stream, "%s<br>", adr->po); - if (adr->ext && *adr->ext) gtk_html_stream_printf (html_stream, "%s<br>", adr->ext); - if (adr->street && *adr->street) gtk_html_stream_printf (html_stream, "%s<br>", adr->street); - if (adr->locality && *adr->locality) gtk_html_stream_printf (html_stream, "%s<br>", adr->locality); - if (adr->region && *adr->region) gtk_html_stream_printf (html_stream, "%s<br>", adr->region); - if (adr->code && *adr->code) gtk_html_stream_printf (html_stream, "%s<br>", adr->code); - if (adr->country && *adr->country) gtk_html_stream_printf (html_stream, "%s<br>", adr->country); - - gtk_html_stream_printf (html_stream, "</td></tr>"); - } - if (adr) - e_contact_address_free (adr); -} -#endif - static void render_name_value (GtkHTMLStream *html_stream, const char *label, const char *str, const char *icon, unsigned int html_flags) { @@ -669,12 +662,6 @@ eab_contact_display_render_normal (EABContactDisplay *display, EContact *contact GtkHTMLStream *html_stream; gboolean is_rtl = (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL); - if (display->priv->contact) - g_object_unref (display->priv->contact); - display->priv->contact = contact; - if (display->priv->contact) - g_object_ref (display->priv->contact); - html_stream = gtk_html_begin (GTK_HTML (display)); gtk_html_stream_write (html_stream, HTML_HEADER, sizeof (HTML_HEADER) - 1); gtk_html_stream_printf (html_stream, "<body><table width=\"100%%\"><tr><td %s>\n", is_rtl ? " align=\"right\" " : ""); @@ -725,16 +712,11 @@ eab_contact_display_render_normal (EABContactDisplay *display, EContact *contact } static void -eab_contact_display_render_compact (EABContactDisplay *display, EContact *contact) +eab_contact_display_render_compact (EABContactDisplay *display, + EContact *contact) { GtkHTMLStream *html_stream; - if (display->priv->contact) - g_object_unref (display->priv->contact); - display->priv->contact = contact; - if (display->priv->contact) - g_object_ref (display->priv->contact); - html_stream = gtk_html_begin (GTK_HTML (display)); gtk_html_stream_write (html_stream, HTML_HEADER, sizeof (HTML_HEADER) - 1); gtk_html_stream_write (html_stream, "<body>\n", 7); @@ -908,98 +890,266 @@ eab_contact_display_render_compact (EABContactDisplay *display, EContact *contac gtk_html_end (GTK_HTML (display), html_stream, GTK_HTML_STREAM_OK); } -void -eab_contact_display_render (EABContactDisplay *display, EContact *contact, - EABContactDisplayRenderMode mode) +static int +contact_display_button_press_event (GtkWidget *widget, + GdkEvent *event, + EABContactDisplay *display) { - switch (mode) { - case EAB_CONTACT_DISPLAY_RENDER_NORMAL: - eab_contact_display_render_normal (display, contact); - break; - case EAB_CONTACT_DISPLAY_RENDER_COMPACT: - eab_contact_display_render_compact (display, contact); - break; + GtkUIManager *ui_manager; + GtkActionGroup *action_group; + GtkWidget *menu; + gboolean has_email; + gchar *uri; + + if (event->button.button != 3) + return FALSE; + + uri = gtk_html_get_url_at ( + GTK_HTML (widget), + event->button.x, event->button.y); + + if (uri == NULL) + return FALSE; + + g_free (display->priv->selected_uri); + display->priv->selected_uri = uri; + + ui_manager = display->priv->ui_manager; + menu = gtk_ui_manager_get_widget (ui_manager, "/popup"); + g_return_val_if_fail (GTK_IS_MENU (menu), FALSE); + + has_email = (g_ascii_strncasecmp (uri, "internal-mailto:", 16) == 0); + + /* Show the appropriate actions. */ + action_group = display->priv->email_actions; + gtk_action_group_set_visible (action_group, has_email); + action_group = display->priv->uri_actions; + gtk_action_group_set_visible (action_group, !has_email); + + if (event != NULL) + gtk_menu_popup ( + GTK_MENU (menu), NULL, NULL, NULL, NULL, + event->button.button, event->button.time); + else + gtk_menu_popup ( + GTK_MENU (menu), NULL, NULL, NULL, NULL, + 0, gtk_get_current_event_time ()); + + return TRUE; +} + +static void +contact_display_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CONTACT: + eab_contact_display_set_contact ( + EAB_CONTACT_DISPLAY (object), + g_value_get_object (value)); + return; + + case PROP_MODE: + eab_contact_display_set_mode ( + EAB_CONTACT_DISPLAY (object), + g_value_get_int (value)); + return; } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } -static int -eab_html_press_event (GtkWidget *widget, GdkEvent *event,EABContactDisplay *display) +static void +contact_display_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) { - char *uri; - gboolean res = FALSE; + switch (property_id) { + case PROP_CONTACT: + g_value_set_object ( + value, eab_contact_display_get_contact ( + EAB_CONTACT_DISPLAY (object))); + return; + case PROP_MODE: + g_value_set_int ( + value, eab_contact_display_get_mode ( + EAB_CONTACT_DISPLAY (object))); + return; + } - if (event->button.button!= 3 ) - return FALSE; + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +contact_display_dispose (GObject *object) +{ + EABContactDisplayPrivate *priv; + + priv = EAB_CONTACT_DISPLAY_GET_PRIVATE (object); + + if (priv->contact != NULL) { + g_object_unref (priv->contact); + priv->contact = NULL; + } + + if (priv->ui_manager != NULL) { + g_object_unref (priv->ui_manager); + priv->ui_manager = NULL; + } + + if (priv->email_actions != NULL) { + g_object_unref (priv->email_actions); + priv->email_actions = NULL; + } - uri = gtk_html_get_url_at (GTK_HTML (widget), event->button.x, event->button.y); - if (uri){ - eab_uri_popup_event(display,event,uri); - } + if (priv->uri_actions != NULL) { + g_object_unref (priv->uri_actions); + priv->uri_actions = NULL; + } - g_free(uri); + if (priv->invisible != NULL) { + g_object_unref (priv->invisible); + priv->invisible = NULL; + } - return res; + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); } -GtkWidget* -eab_contact_display_new (void) +static void +contact_display_finalize (GObject *object) { - EABContactDisplay *display; - - struct _EABContactDisplayPrivate *p; - - display = g_object_new (EAB_TYPE_CONTACT_DISPLAY, NULL); - p=display->priv = g_new0 (EABContactDisplayPrivate, 1); - - gtk_html_set_default_content_type (GTK_HTML (display), "text/html; charset=utf-8"); - - gtk_html_set_editable (GTK_HTML (display), FALSE); - - g_signal_connect (display, "url_requested", - G_CALLBACK (on_url_requested), - display); - g_signal_connect (display, "link_clicked", - G_CALLBACK (on_link_clicked), - display); - g_signal_connect(display, "button_press_event", - G_CALLBACK(eab_html_press_event), - display); - p->invisible = gtk_invisible_new(); - g_signal_connect(p->invisible, "selection_get", G_CALLBACK(eab_selection_get), display); - g_signal_connect(p->invisible, "selection_clear_event", G_CALLBACK(eab_selection_clear_event), display); - gtk_selection_add_target(p->invisible, GDK_SELECTION_PRIMARY, GDK_SELECTION_TYPE_STRING, 0); - gtk_selection_add_target(p->invisible, GDK_SELECTION_CLIPBOARD, GDK_SELECTION_TYPE_STRING, 1); - -#if 0 - g_signal_connect (display, "object_requested", - G_CALLBACK (on_object_requested), - mail_display); - g_signal_connect (display, "button_press_event", - G_CALLBACK (html_button_press_event), mail_display); - g_signal_connect (display, "motion_notify_event", - G_CALLBACK (html_motion_notify_event), mail_display); - g_signal_connect (display, "enter_notify_event", - G_CALLBACK (html_enter_notify_event), mail_display); - g_signal_connect (display, "iframe_created", - G_CALLBACK (html_iframe_created), mail_display); - g_signal_connect (display, "on_url", - G_CALLBACK (html_on_url), mail_display); -#endif + EABContactDisplayPrivate *priv; - return GTK_WIDGET (display); + priv = EAB_CONTACT_DISPLAY_GET_PRIVATE (object); + + g_free (priv->selected_uri); + g_free (priv->clipboard_uri); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); } static void -eab_contact_display_init (GObject *object) +eab_contact_display_class_init (EABContactDisplayClass *class) { - gtk_html_construct ((GtkHTML *)object); + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EABContactDisplayPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = contact_display_set_property; + object_class->get_property = contact_display_get_property; + object_class->dispose = contact_display_dispose; + object_class->finalize = contact_display_finalize; + + g_object_class_install_property ( + object_class, + PROP_CONTACT, + g_param_spec_object ( + "contact", + NULL, + NULL, + E_TYPE_CONTACT, + G_PARAM_READWRITE)); + + /* XXX Make this a real enum property. */ + g_object_class_install_property ( + object_class, + PROP_MODE, + g_param_spec_int ( + "mode", + NULL, + NULL, + EAB_CONTACT_DISPLAY_RENDER_NORMAL, + EAB_CONTACT_DISPLAY_RENDER_COMPACT, + EAB_CONTACT_DISPLAY_RENDER_NORMAL, + G_PARAM_READWRITE)); + + signals[SEND_MESSAGE] = g_signal_new ( + "send-message", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EABContactDisplayClass, send_message), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + E_TYPE_DESTINATION); } static void -eab_contact_display_class_init (GtkObjectClass *object_class) +eab_contact_display_init (EABContactDisplay *display) { - /* object_class->destroy = mail_display_destroy;*/ + GtkActionGroup *action_group; + GtkHTML *html; + const gchar *id; + + display->priv = EAB_CONTACT_DISPLAY_GET_PRIVATE (display); + display->priv->mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL; + display->priv->ui_manager = gtk_ui_manager_new (); + display->priv->invisible = gtk_invisible_new (); + + g_object_ref_sink (display->priv->invisible); + + action_group = gtk_action_group_new ("email"); + gtk_action_group_set_translation_domain ( + action_group, GETTEXT_PACKAGE); + gtk_action_group_add_actions ( + action_group, email_entries, + G_N_ELEMENTS (email_entries), display); + gtk_ui_manager_insert_action_group ( + display->priv->ui_manager, action_group, 0); + display->priv->email_actions = action_group; + + action_group = gtk_action_group_new ("uri"); + gtk_action_group_set_translation_domain ( + action_group, GETTEXT_PACKAGE); + gtk_action_group_add_actions ( + action_group, uri_entries, + G_N_ELEMENTS (uri_entries), display); + gtk_ui_manager_insert_action_group ( + display->priv->ui_manager, action_group, 0); + display->priv->uri_actions = action_group; + + gtk_ui_manager_add_ui_from_string ( + display->priv->ui_manager, ui, -1, NULL); + + html = GTK_HTML (display); + gtk_html_construct (html); + gtk_html_set_editable (html, FALSE); + gtk_html_set_default_content_type (html, "text/html; charset=utf-8"); + + g_signal_connect ( + display, "url-requested", + G_CALLBACK (contact_display_on_url_requested), display); + g_signal_connect ( + display, "link-clicked", + G_CALLBACK (contact_display_on_link_clicked), display); + g_signal_connect ( + display, "button-press-event", + G_CALLBACK (contact_display_button_press_event), display); + + g_signal_connect_swapped ( + display->priv->invisible, "selection-get", + G_CALLBACK (contact_display_selection_get), display); + g_signal_connect_swapped ( + display->priv->invisible, "selection-clear-event", + G_CALLBACK (contact_display_selection_clear_event), display); + gtk_selection_add_target ( + display->priv->invisible, + GDK_SELECTION_PRIMARY, GDK_SELECTION_TYPE_STRING, 0); + gtk_selection_add_target ( + display->priv->invisible, + GDK_SELECTION_CLIPBOARD, GDK_SELECTION_TYPE_STRING, 1); + + id = "org.gnome.evolution.contact-display"; + e_plugin_ui_register_manager (display->priv->ui_manager, id, display); + e_plugin_ui_enable_manager (display->priv->ui_manager, id); } GType @@ -1007,21 +1157,98 @@ eab_contact_display_get_type (void) { static GType type = 0; - if (!type) { - static const GTypeInfo info = { + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { sizeof (EABContactDisplayClass), - NULL, /* base_init */ - NULL, /* base_finalize */ + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, (GClassInitFunc) eab_contact_display_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ sizeof (EABContactDisplay), - 0, /* n_preallocs */ + 0, /* n_preallocs */ (GInstanceInitFunc) eab_contact_display_init, + NULL /* value_table */ }; - type = g_type_register_static (PARENT_TYPE, "EABContactDisplay", &info, 0); + type = g_type_register_static ( + GTK_TYPE_HTML, "EABContactDisplay", &type_info, 0); } return type; } + +GtkWidget * +eab_contact_display_new (void) +{ + return g_object_new (EAB_TYPE_CONTACT_DISPLAY, NULL); +} + +EContact * +eab_contact_display_get_contact (EABContactDisplay *display) +{ + g_return_val_if_fail (EAB_IS_CONTACT_DISPLAY (display), NULL); + + return display->priv->contact; +} + +void +eab_contact_display_set_contact (EABContactDisplay *display, + EContact *contact) +{ + EABContactDisplayMode mode; + + g_return_if_fail (EAB_IS_CONTACT_DISPLAY (display)); + + mode = eab_contact_display_get_mode (display); + + if (contact != NULL) + g_object_ref (contact); + if (display->priv->contact != NULL) + g_object_unref (display->priv->contact); + display->priv->contact = contact; + + switch (mode) { + case EAB_CONTACT_DISPLAY_RENDER_NORMAL: + eab_contact_display_render_normal (display, contact); + break; + + case EAB_CONTACT_DISPLAY_RENDER_COMPACT: + eab_contact_display_render_compact (display, contact); + break; + } + + g_object_notify (G_OBJECT (display), "contact"); +} + +EABContactDisplayMode +eab_contact_display_get_mode (EABContactDisplay *display) +{ + g_return_val_if_fail (EAB_IS_CONTACT_DISPLAY (display), 0); + + return display->priv->mode; +} + +void +eab_contact_display_set_mode (EABContactDisplay *display, + EABContactDisplayMode mode) +{ + EContact *contact; + + g_return_if_fail (EAB_IS_CONTACT_DISPLAY (display)); + + display->priv->mode = mode; + contact = eab_contact_display_get_contact (display); + + switch (mode) { + case EAB_CONTACT_DISPLAY_RENDER_NORMAL: + eab_contact_display_render_normal (display, contact); + break; + + case EAB_CONTACT_DISPLAY_RENDER_COMPACT: + eab_contact_display_render_compact (display, contact); + break; + } + + g_object_notify (G_OBJECT (display), "mode"); +} diff --git a/addressbook/gui/widgets/eab-contact-display.h b/addressbook/gui/widgets/eab-contact-display.h index c7b7f1a476..096a910f2f 100644 --- a/addressbook/gui/widgets/eab-contact-display.h +++ b/addressbook/gui/widgets/eab-contact-display.h @@ -20,41 +20,68 @@ * */ -#ifndef _EAB_CONTACT_DISPLAY_H_ -#define _EAB_CONTACT_DISPLAY_H_ +#ifndef EAB_CONTACT_DISPLAY_H +#define EAB_CONTACT_DISPLAY_H #include <gtkhtml/gtkhtml.h> #include <libebook/e-contact.h> +#include <libebook/e-destination.h> -#define EAB_TYPE_CONTACT_DISPLAY (eab_contact_display_get_type ()) -#define EAB_CONTACT_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EAB_TYPE_CONTACT_DISPLAY, EABContactDisplay)) -#define EAB_CONTACT_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EAB_TYPE_CONTACT_DISPLAY, EABContactDisplayClass)) -#define IS_EAB_CONTACT_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EAB_TYPE_CONTACT_DISPLAY)) -#define IS_EAB_CONTACT_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EAB_TYPE_CONTACT_DISPLAY)) +/* Standard GObject macros */ +#define EAB_TYPE_CONTACT_DISPLAY \ + (eab_contact_display_get_type ()) +#define EAB_CONTACT_DISPLAY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), EAB_TYPE_CONTACT_DISPLAY, EABContactDisplay)) +#define EAB_CONTACT_DISPLAY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), EAB_TYPE_CONTACT_DISPLAY, EABContactDisplayClass)) +#define EAB_IS_CONTACT_DISPLAY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), EAB_TYPE_CONTACT_DISPLAY)) +#define EAB_IS_CONTACT_DISPLAY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), EAB_TYPE_CONTACT_DISPLAY)) +#define EAB_CONTACT_DISPLAY_GET_CLASS(obj) \ + (G_TYPE_ISNTANCE_GET_CLASS \ + ((obj), EAB_TYPE_CONTACT_DISPLAY, EABContactDisplayClass)) + +G_BEGIN_DECLS typedef struct _EABContactDisplay EABContactDisplay; -typedef struct _EABContactDisplayPrivate EABContactDisplayPrivate; typedef struct _EABContactDisplayClass EABContactDisplayClass; +typedef struct _EABContactDisplayPrivate EABContactDisplayPrivate; typedef enum { EAB_CONTACT_DISPLAY_RENDER_NORMAL, /* for use in the preview pane */ EAB_CONTACT_DISPLAY_RENDER_COMPACT /* for use with embedded vcards (e.g, the EABVCardControl) */ -} EABContactDisplayRenderMode; +} EABContactDisplayMode; struct _EABContactDisplay { GtkHTML parent; - EABContactDisplayPrivate *priv; }; struct _EABContactDisplayClass { GtkHTMLClass parent_class; + + /* Signals */ + void (*send_message) (EABContactDisplay *display, + EDestination *destination); }; -GType eab_contact_display_get_type (void); -GtkWidget * eab_contact_display_new (void); +GType eab_contact_display_get_type (void); +GtkWidget * eab_contact_display_new (void); + +EContact * eab_contact_display_get_contact (EABContactDisplay *display); +void eab_contact_display_set_contact (EABContactDisplay *display, + EContact *contact); +EABContactDisplayMode + eab_contact_display_get_mode (EABContactDisplay *display); +void eab_contact_display_set_mode (EABContactDisplay *display, + EABContactDisplayMode mode); + -void eab_contact_display_render (EABContactDisplay *display, EContact *contact, - EABContactDisplayRenderMode render_mode); +G_END_DECLS -#endif /* _EAB_CONTACT_DISPLAY_H_ */ +#endif /* EAB_CONTACT_DISPLAY_H */ diff --git a/addressbook/gui/widgets/eab-gui-util.c b/addressbook/gui/widgets/eab-gui-util.c index 168c0bb7fa..9db9630b72 100644 --- a/addressbook/gui/widgets/eab-gui-util.c +++ b/addressbook/gui/widgets/eab-gui-util.c @@ -40,17 +40,11 @@ #include "misc/e-image-chooser.h" #include <e-util/e-icon-factory.h> #include "eab-contact-merging.h" -#include <composer/e-msg-composer.h> -#include <mail/em-composer-utils.h> /* we link to camel for decoding quoted printable email addresses */ #include <camel/camel-mime-utils.h> -#include "addressbook/gui/contact-editor/eab-editor.h" -#include "addressbook/gui/contact-editor/e-contact-editor.h" -#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h" -#include "addressbook/gui/component/addressbook-component.h" -#include "addressbook/gui/component/addressbook.h" +#include "addressbook/util/addressbook.h" /* the NULL's in this table correspond to the status codes that should *never* be generated by a backend */ @@ -201,140 +195,6 @@ eab_prompt_save_dialog (GtkWindow *parent) return e_error_run (parent, "addressbook:prompt-save", NULL); } -static void -added_cb (EBook* book, EBookStatus status, EContact *contact, - gpointer data) -{ - gboolean is_list = GPOINTER_TO_INT (data); - - if (status != E_BOOK_ERROR_OK && status != E_BOOK_ERROR_CANCELLED) { - eab_error_dialog (is_list ? _("Error adding list") : _("Error adding contact"), status); - } -} - -static void -modified_cb (EBook* book, EBookStatus status, EContact *contact, - gpointer data) -{ - gboolean is_list = GPOINTER_TO_INT (data); - - if (status != E_BOOK_ERROR_OK && status != E_BOOK_ERROR_CANCELLED) { - eab_error_dialog (is_list ? _("Error modifying list") : _("Error modifying contact"), - status); - } -} - -static void -deleted_cb (EBook* book, EBookStatus status, EContact *contact, - gpointer data) -{ - gboolean is_list = GPOINTER_TO_INT (data); - - if (status != E_BOOK_ERROR_OK) { - eab_error_dialog (is_list ? _("Error removing list") : _("Error removing contact"), - status); - } -} - -static void -editor_closed_cb (GtkObject *editor, gpointer data) -{ - g_object_unref (editor); -} - -EContactEditor * -eab_show_contact_editor (EBook *book, EContact *contact, - gboolean is_new_contact, - gboolean editable) -{ - EContactEditor *ce; - - ce = e_contact_editor_new (book, contact, is_new_contact, editable); - - g_signal_connect (ce, "contact_added", - G_CALLBACK (added_cb), GINT_TO_POINTER (FALSE)); - g_signal_connect (ce, "contact_modified", - G_CALLBACK (modified_cb), GINT_TO_POINTER (FALSE)); - g_signal_connect (ce, "contact_deleted", - G_CALLBACK (deleted_cb), GINT_TO_POINTER (FALSE)); - g_signal_connect (ce, "editor_closed", - G_CALLBACK (editor_closed_cb), NULL); - - return ce; -} - -EContactListEditor * -eab_show_contact_list_editor (EBook *book, EContact *contact, - gboolean is_new_contact, - gboolean editable) -{ - EContactListEditor *ce; - - ce = e_contact_list_editor_new (book, contact, is_new_contact, editable); - - g_signal_connect (ce, "contact_added", - G_CALLBACK (added_cb), GINT_TO_POINTER (TRUE)); - g_signal_connect (ce, "contact_modified", - G_CALLBACK (modified_cb), GINT_TO_POINTER (TRUE)); - g_signal_connect (ce, "contact_deleted", - G_CALLBACK (deleted_cb), GINT_TO_POINTER (TRUE)); - g_signal_connect (ce, "editor_closed", - G_CALLBACK (editor_closed_cb), GINT_TO_POINTER (TRUE)); - - eab_editor_show (EAB_EDITOR (ce)); - - return ce; -} - -static void -view_contacts (EBook *book, GList *list, gboolean editable) -{ - for (; list; list = list->next) { - EContact *contact = list->data; - if (e_contact_get (contact, E_CONTACT_IS_LIST)) - eab_show_contact_list_editor (book, contact, FALSE, editable); - else - eab_show_contact_editor (book, contact, FALSE, editable); - } -} - -void -eab_show_multiple_contacts (EBook *book, - GList *list, - gboolean editable) -{ - if (list) { - int length = g_list_length (list); - if (length > 5) { - GtkWidget *dialog; - gint response; - - dialog = gtk_message_dialog_new (NULL, - 0, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_NONE, - ngettext("Opening %d contact will open %d new window as well.\n" - "Do you really want to display this contact?", - "Opening %d contacts will open %d new windows as well.\n" - "Do you really want to display all of these contacts?", - length), - length, - length); - gtk_dialog_add_buttons (GTK_DIALOG (dialog), - _("_Don't Display"), GTK_RESPONSE_NO, - _("Display _All Contacts"), GTK_RESPONSE_YES, - NULL); - response = gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - if (response == GTK_RESPONSE_YES) - view_contacts (book, list, editable); - } else { - view_contacts (book, list, editable); - } - } -} - - static gint file_exists(GtkWindow *window, const char *filename) { @@ -629,16 +489,6 @@ struct ContactCopyProcess_ { ContactCopyDone done_cb; }; -#if 0 -static void -contact_deleted_cb (EBook* book, EBookStatus status, gpointer user_data) -{ - if (status != E_BOOK_ERROR_OK) { - eab_error_dialog (_("Error removing contact"), status); - } -} -#endif - static void do_delete (gpointer data, gpointer user_data) { @@ -783,232 +633,6 @@ eab_transfer_contacts (EBook *source, GList *contacts /* adopted */, gboolean de addressbook_load (dest, got_book_cb, process); } -typedef struct { - EContact *contact; - int email_num; /* if the contact is a person (not a list), the email address to use */ -} ContactAndEmailNum; - -static void -eab_send_to_contact_and_email_num_list (GList *contact_list) -{ - EMsgComposer *composer; - EComposerHeaderTable *table; - GPtrArray *to_array; - GPtrArray *bcc_array; - - union { - gpointer *pdata; - EDestination **destinations; - } convert; - - if (contact_list == NULL) - return; - - composer = e_msg_composer_new (); - table = e_msg_composer_get_header_table (composer); - em_composer_utils_setup_default_callbacks (composer); - - to_array = g_ptr_array_new (); - bcc_array = g_ptr_array_new (); - - /* Sort contacts into "To" and "Bcc" destinations. */ - while (contact_list != NULL) { - ContactAndEmailNum *ce = contact_list->data; - EContact *contact = ce->contact; - EDestination *destination; - - destination = e_destination_new (); - e_destination_set_contact (destination, contact, 0); - - if (e_destination_is_evolution_list (destination)) { - if (e_destination_list_show_addresses (destination)) - g_ptr_array_add (to_array, destination); - else - g_ptr_array_add (bcc_array, destination); - } else - g_ptr_array_add (to_array, destination); - - contact_list = g_list_next (contact_list); - } - - /* Add sentinels to each array. */ - g_ptr_array_add (to_array, NULL); - g_ptr_array_add (bcc_array, NULL); - - /* XXX Acrobatics like this make me question whether NULL-terminated - * arrays are really the best argument type for passing a list of - * destinations to the header table. */ - - /* Add "To" destinations. */ - convert.pdata = to_array->pdata; - e_composer_header_table_set_destinations_to ( - table, convert.destinations); - g_ptr_array_free (to_array, FALSE); - e_destination_freev (convert.destinations); - - /* Add "Bcc" destinations. */ - convert.pdata = bcc_array->pdata; - e_composer_header_table_set_destinations_bcc ( - table, convert.destinations); - g_ptr_array_free (bcc_array, FALSE); - e_destination_freev (convert.destinations); - - gtk_widget_show (GTK_WIDGET (composer)); -} - -static const char * -get_email (EContact *contact, EContactField field_id, gchar **to_free) -{ - char *name = NULL, *mail = NULL; - const char *value = e_contact_get_const (contact, field_id); - - *to_free = NULL; - - if (eab_parse_qp_email (value, &name, &mail)) { - *to_free = g_strdup_printf ("%s <%s>", name, mail); - value = *to_free; - } - - g_free (name); - g_free (mail); - - return value; -} - -static void -eab_send_contact_list_as_attachment (GList *contacts) -{ - EMsgComposer *composer; - EComposerHeaderTable *table; - CamelMimePart *attachment; - gchar *data; - - if (contacts == NULL) - return; - - composer = e_msg_composer_new (); - table = e_msg_composer_get_header_table (composer); - em_composer_utils_setup_default_callbacks (composer); - - attachment = camel_mime_part_new (); - data = eab_contact_list_to_string (contacts); - - camel_mime_part_set_content ( - attachment, data, strlen (data), "text/x-vcard"); - - if (contacts->next != NULL) - camel_mime_part_set_description ( - attachment, _("Multiple vCards")); - else { - EContact *contact = contacts->data; - const gchar *file_as; - gchar *description; - - file_as = e_contact_get_const (contact, E_CONTACT_FILE_AS); - description = g_strdup_printf (_("vCard for %s"), file_as); - camel_mime_part_set_description (attachment, description); - g_free (description); - } - - camel_mime_part_set_disposition (attachment, "attachment"); - - e_msg_composer_attach (composer, attachment); - camel_object_unref (attachment); - - if (contacts->next != NULL) - e_composer_header_table_set_subject ( - table, _("Contact information")); - else { - EContact *contact = contacts->data; - gchar *tempstr; - const gchar *tempstr2; - gchar *tempfree = NULL; - - tempstr2 = e_contact_get_const (contact, E_CONTACT_FILE_AS); - if (!tempstr2 || !*tempstr2) - tempstr2 = e_contact_get_const (contact, E_CONTACT_FULL_NAME); - if (!tempstr2 || !*tempstr2) - tempstr2 = e_contact_get_const (contact, E_CONTACT_ORG); - if (!tempstr2 || !*tempstr2) { - g_free (tempfree); - tempstr2 = get_email (contact, E_CONTACT_EMAIL_1, &tempfree); - } - if (!tempstr2 || !*tempstr2) { - g_free (tempfree); - tempstr2 = get_email (contact, E_CONTACT_EMAIL_2, &tempfree); - } - if (!tempstr2 || !*tempstr2) { - g_free (tempfree); - tempstr2 = get_email (contact, E_CONTACT_EMAIL_3, &tempfree); - } - - if (!tempstr2 || !*tempstr2) - tempstr = g_strdup_printf (_("Contact information")); - else - tempstr = g_strdup_printf (_("Contact information for %s"), tempstr2); - - e_composer_header_table_set_subject (table, tempstr); - - g_free (tempstr); - g_free (tempfree); - } - - gtk_widget_show (GTK_WIDGET (composer)); -} - -void -eab_send_contact_list (GList *contacts, EABDisposition disposition) -{ - switch (disposition) { - case EAB_DISPOSITION_AS_TO: { - GList *list = NULL, *l; - - for (l = contacts; l; l = l->next) { - ContactAndEmailNum *ce = g_new (ContactAndEmailNum, 1); - ce->contact = l->data; - ce->email_num = 0; /* hardcode this */ - - list = g_list_append (list, ce); - } - - eab_send_to_contact_and_email_num_list (list); - - g_list_foreach (list, (GFunc)g_free, NULL); - g_list_free (list); - break; - } - case EAB_DISPOSITION_AS_ATTACHMENT: - eab_send_contact_list_as_attachment (contacts); - break; - } -} - -void -eab_send_contact (EContact *contact, int email_num, EABDisposition disposition) -{ - GList *list = NULL; - - switch (disposition) { - case EAB_DISPOSITION_AS_TO: { - ContactAndEmailNum ce; - - ce.contact = contact; - ce.email_num = email_num; - - list = g_list_prepend (NULL, &ce); - eab_send_to_contact_and_email_num_list (list); - break; - } - case EAB_DISPOSITION_AS_ATTACHMENT: { - list = g_list_prepend (NULL, contact); - eab_send_contact_list_as_attachment (list); - break; - } - } - - g_list_free (list); -} - GtkWidget * eab_create_image_chooser_widget(gchar *name, gchar *string1, gchar *string2, diff --git a/addressbook/gui/widgets/eab-gui-util.h b/addressbook/gui/widgets/eab-gui-util.h index 79dbe5493a..8d878cff14 100644 --- a/addressbook/gui/widgets/eab-gui-util.h +++ b/addressbook/gui/widgets/eab-gui-util.h @@ -26,8 +26,6 @@ #include <gtk/gtk.h> #include <libebook/e-book.h> -#include "addressbook/gui/contact-editor/e-contact-editor.h" -#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h" G_BEGIN_DECLS @@ -40,17 +38,6 @@ void eab_search_result_dialog (GtkWidget *parent, EBookViewStatus status); gint eab_prompt_save_dialog (GtkWindow *parent); -EContactEditor *eab_show_contact_editor (EBook *book, - EContact *contact, - gboolean is_new_contact, - gboolean editable); -EContactListEditor *eab_show_contact_list_editor (EBook *book, - EContact *contact, - gboolean is_new_contact, - gboolean editable); -void eab_show_multiple_contacts (EBook *book, - GList *list, - gboolean editable); void eab_transfer_contacts (EBook *source, GList *contacts, /* adopted */ gboolean delete_from_source, @@ -64,26 +51,17 @@ void eab_contact_list_save (char *title, GList *list, GtkWindow *parent_window); -typedef enum { - EAB_DISPOSITION_AS_ATTACHMENT, - EAB_DISPOSITION_AS_TO, -} EABDisposition; - -void eab_send_contact (EContact *contact, - int email_num, - EABDisposition disposition); -void eab_send_contact_list (GList *contacts, - EABDisposition disposition); - GtkWidget *eab_create_image_chooser_widget (gchar *name, gchar *string1, gchar *string2, gint int1, gint int2); ESource *eab_select_source (const gchar *title, const gchar *message, const gchar *select_uid, GtkWindow *parent); -/* To parse quoted printable address & return email & name fields */ -gboolean eab_parse_qp_email (const gchar *string, gchar **name, gchar **email); -char *eab_parse_qp_email_to_html (const gchar *string); +/* To parse quoted printable address & return email & name fields */ +gboolean eab_parse_qp_email (const gchar *string, + gchar **name, + gchar **email); +gchar * eab_parse_qp_email_to_html (const gchar *string); G_END_DECLS diff --git a/addressbook/gui/widgets/eab-menu.c b/addressbook/gui/widgets/eab-menu.c deleted file mode 100644 index 603e93893c..0000000000 --- a/addressbook/gui/widgets/eab-menu.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * 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: - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <stdlib.h> - -#include <glib.h> - -#include <libebook/e-contact.h> - -#include "eab-menu.h" - -static void eabm_standard_menu_factory(EMenu *emp, void *data); - -static GObjectClass *eabm_parent; - -static void -eabm_init(GObject *o) -{ - /*EABMenu *emp = (EABMenu *)o; */ -} - -static void -eabm_finalise(GObject *o) -{ - ((GObjectClass *)eabm_parent)->finalize(o); -} - -static void -eabm_target_free(EMenu *ep, EMenuTarget *t) -{ - switch (t->type) { - case EAB_MENU_TARGET_SELECT: { - EABMenuTargetSelect *s = (EABMenuTargetSelect *)t; - int i; - - for (i=0;i<s->cards->len;i++) - g_object_unref(s->cards->pdata[i]); - g_ptr_array_free(s->cards, TRUE); - if (s->book) - g_object_unref(s->book); - break; } - } - - ((EMenuClass *)eabm_parent)->target_free(ep, t); -} - -static void -eabm_class_init(GObjectClass *klass) -{ - klass->finalize = eabm_finalise; - ((EMenuClass *)klass)->target_free = eabm_target_free; - - e_menu_class_add_factory((EMenuClass *)klass, NULL, (EMenuFactoryFunc)eabm_standard_menu_factory, NULL); -} - -GType -eab_menu_get_type(void) -{ - static GType type = 0; - - if (type == 0) { - static const GTypeInfo info = { - sizeof(EABMenuClass), - NULL, NULL, - (GClassInitFunc)eabm_class_init, - NULL, NULL, - sizeof(EABMenu), 0, - (GInstanceInitFunc)eabm_init - }; - eabm_parent = g_type_class_ref(e_menu_get_type()); - type = g_type_register_static(e_menu_get_type(), "EABMenu", &info, 0); - } - - return type; -} - -EABMenu *eab_menu_new(const char *menuid) -{ - EABMenu *emp = g_object_new(eab_menu_get_type(), NULL); - - e_menu_construct(&emp->menu, menuid); - - return emp; -} - -/** - * eab_menu_target_new_select - create a menu target of the current selection. - * @eabp: Address book menu. - * @book: Book the cards belong to. May be NULL in which case cards must be an empty GPtrArray. - * @readonly: Book is read-only mode. FIXME: Why can't we just get this off the book? - * @cards: Cards selected. This will be freed on completion and the array indices unreferenced. - * - * Create a new selection menu target. - * - * Return value: - **/ -EABMenuTargetSelect * -eab_menu_target_new_select(EABMenu *eabp, struct _EBook *book, int readonly, GPtrArray *cards) -{ - EABMenuTargetSelect *t = e_menu_target_new(&eabp->menu, EAB_MENU_TARGET_SELECT, sizeof(*t)); - guint32 mask = ~0; - int has_email = FALSE, i; - - /* FIXME: duplicated in eab-popup.c */ - - t->book = book; - if (book) - g_object_ref(book); - t->cards = cards; - - for (i=0;i<cards->len && !has_email;i++) { - EContact *contact = cards->pdata[i]; - GList *email; - - email = e_contact_get(E_CONTACT(contact), E_CONTACT_EMAIL); - if (email) { - has_email = TRUE; - - g_list_foreach(email, (GFunc)g_free, NULL); - g_list_free(email); - } - } - - if (has_email) - mask &= ~EAB_MENU_SELECT_EMAIL; - - if (!readonly) - mask &= ~EAB_MENU_SELECT_EDITABLE; - - if (cards->len == 1) - mask &= ~EAB_MENU_SELECT_ONE; - - if (cards->len > 1) - mask &= ~EAB_MENU_SELECT_MANY; - - if (cards->len >= 1) - mask &= ~EAB_MENU_SELECT_ANY; - - t->target.mask = mask; - - return t; -} - -static void -eabm_standard_menu_factory(EMenu *emp, void *data) -{ - /* noop */ -} - -/* ********************************************************************** */ - -/* menu plugin handler */ - -/* -<e-plugin - class="org.gnome.mail.plugin.popup:1.0" - id="org.gnome.mail.plugin.popup.item:1.0" - type="shlib" - location="/opt/gnome2/lib/camel/1.0/libcamelimap.so" - name="imap" - description="IMAP4 and IMAP4v1 mail store"> - <hook class="org.gnome.mail.popupMenu:1.0" - handler="HandlePopup"> - <menu id="any" target="select"> - <item - type="item|toggle|radio|image|submenu|bar" - active - path="foo/bar" - label="label" - icon="foo" - mask="select_one" - activate="eabm_view_emacs"/> - </menu> - </extension> - -*/ - -static void *eabmph_parent_class; -#define eabmph ((EABMenuHook *)eph) - -static const EMenuHookTargetMask eabmph_select_masks[] = { - { "one", EAB_MENU_SELECT_ONE }, - { "many", EAB_MENU_SELECT_MANY }, - { "any", EAB_MENU_SELECT_ANY }, - { "editable", EAB_MENU_SELECT_EDITABLE }, - { "email", EAB_MENU_SELECT_EMAIL }, - { NULL } -}; - -static const EMenuHookTargetMap eabmph_targets[] = { - { "select", EAB_MENU_TARGET_SELECT, eabmph_select_masks }, - { NULL } -}; - -static void -eabmph_finalise(GObject *o) -{ - /*EPluginHook *eph = (EPluginHook *)o;*/ - - ((GObjectClass *)eabmph_parent_class)->finalize(o); -} - -static void -eabmph_class_init(EPluginHookClass *klass) -{ - int i; - - ((GObjectClass *)klass)->finalize = eabmph_finalise; - ((EPluginHookClass *)klass)->id = "org.gnome.evolution.addressbook.bonobomenu:1.0"; - - for (i=0;eabmph_targets[i].type;i++) - e_menu_hook_class_add_target_map((EMenuHookClass *)klass, &eabmph_targets[i]); - - /* FIXME: leaks parent set class? */ - ((EMenuHookClass *)klass)->menu_class = g_type_class_ref(eab_menu_get_type()); -} - -GType -eab_menu_hook_get_type(void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof(EABMenuHookClass), NULL, NULL, (GClassInitFunc) eabmph_class_init, NULL, NULL, - sizeof(EABMenuHook), 0, (GInstanceInitFunc) NULL, - }; - - eabmph_parent_class = g_type_class_ref(e_menu_hook_get_type()); - type = g_type_register_static(e_menu_hook_get_type(), "EABMenuHook", &info, 0); - } - - return type; -} diff --git a/addressbook/gui/widgets/eab-menu.h b/addressbook/gui/widgets/eab-menu.h deleted file mode 100644 index 7da05c133b..0000000000 --- a/addressbook/gui/widgets/eab-menu.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * - * 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: - * Michel Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef __EAB_MENU_H__ -#define __EAB_MENU_H__ - -#include <glib-object.h> - -#include "e-util/e-menu.h" - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -struct _EBook; - -typedef struct _EABMenu EABMenu; -typedef struct _EABMenuClass EABMenuClass; - -/* Current target description */ -enum _eab_menu_target_t { - EAB_MENU_TARGET_SELECT, -}; - -/** - * enum _eab_menu_target_select_t - EABMenuTargetSelect qualifiers. - * - * @EAB_MENU_SELECT_ONE: Only one item is selected. - * @EAB_MENU_SELECT_MANY: More than one item selected. - * @EAB_MENU_SELECT_ANY: One or more items selected. - * @EAB_MENU_SELECT_EDITABLE: Editable addressbook. - * @EAB_MENU_SELECT_EMAIL: Has an email address. - **/ -enum _eab_menu_target_select_t { - EAB_MENU_SELECT_ONE = 1<<0, - EAB_MENU_SELECT_MANY = 1<<1, - EAB_MENU_SELECT_ANY = 1<<2, - EAB_MENU_SELECT_EDITABLE = 1<<3, - EAB_MENU_SELECT_EMAIL = 1<<4, -}; - -typedef struct _EABMenuTargetSelect EABMenuTargetSelect; - -struct _EABMenuTargetSelect { - EMenuTarget target; - - struct _EBook *book; - GPtrArray *cards; -}; - -typedef struct _EMenuItem EABMenuItem; - -/* The object */ -struct _EABMenu { - EMenu menu; - - struct _EABMenuPrivate *priv; -}; - -struct _EABMenuClass { - EMenuClass menu_class; -}; - -GType eab_menu_get_type(void); - -EABMenu *eab_menu_new(const char *menuid); - -EABMenuTargetSelect *eab_menu_target_new_select(EABMenu *eabp, struct _EBook *book, int readonly, GPtrArray *cards); - -/* ********************************************************************** */ - -typedef struct _EABMenuHook EABMenuHook; -typedef struct _EABMenuHookClass EABMenuHookClass; - -struct _EABMenuHook { - EMenuHook hook; -}; - -struct _EABMenuHookClass { - EMenuHookClass hook_class; -}; - -GType eab_menu_hook_get_type(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __EAB_MENU_H__ */ diff --git a/addressbook/gui/widgets/eab-popup-control.c b/addressbook/gui/widgets/eab-popup-control.c deleted file mode 100644 index 6a702f3941..0000000000 --- a/addressbook/gui/widgets/eab-popup-control.c +++ /dev/null @@ -1,464 +0,0 @@ -/* - * This file is too big and this widget is too complicated. Forgive me. - * - * 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: - * Jon Trowbridge <trow@ximian.com> - * Chris Toshok <toshok@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - */ - -#include <config.h> -#include <string.h> -#include "addressbook.h" -#include "eab-popup-control.h" -#include <bonobo/bonobo-control.h> -#include <bonobo/bonobo-property-bag.h> -#include <bonobo/bonobo-generic-factory.h> -#include <addressbook/util/eab-book-util.h> -#include <addressbook/gui/contact-editor/e-contact-editor.h> -#include <addressbook/gui/contact-editor/e-contact-quick-add.h> -#include <addressbook/gui/widgets/eab-contact-display.h> -#include <addressbook/gui/widgets/eab-gui-util.h> - -static void eab_popup_control_set_name (EABPopupControl *pop, const gchar *name); -static void eab_popup_control_set_email (EABPopupControl *pop, const gchar *email); -static void eab_popup_control_set_vcard (EABPopupControl *pop, const gchar *vcard); - -static GtkObjectClass *parent_class; - -static void eab_popup_control_dispose (GObject *); -static void eab_popup_control_query (EABPopupControl *); - - -static void -eab_popup_control_class_init (EABPopupControlClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - object_class->dispose = eab_popup_control_dispose; -} - -static void -eab_popup_control_init (EABPopupControl *pop) -{ - pop->transitory = TRUE; -} - -static void -eab_popup_control_cleanup (EABPopupControl *pop) -{ - if (pop->contact) { - g_object_unref (pop->contact); - pop->contact = NULL; - } - - if (pop->scheduled_refresh) { - g_source_remove (pop->scheduled_refresh); - pop->scheduled_refresh = 0; - } - - if (pop->query_tag) { -#ifdef notyet - e_book_simple_query_cancel (pop->book, pop->query_tag); -#endif - pop->query_tag = 0; - } - - if (pop->book) { - g_object_unref (pop->book); - pop->book = NULL; - } - - g_free (pop->name); - pop->name = NULL; - - g_free (pop->email); - pop->email = NULL; - - g_free (pop->vcard); - pop->vcard = NULL; -} - -static void -eab_popup_control_dispose (GObject *obj) -{ - EABPopupControl *pop = EAB_POPUP_CONTROL (obj); - - eab_popup_control_cleanup (pop); - - if (G_OBJECT_CLASS (parent_class)->dispose) - G_OBJECT_CLASS (parent_class)->dispose (obj); -} - -GType -eab_popup_control_get_type (void) -{ - static GType pop_type = 0; - - if (!pop_type) { - static const GTypeInfo pop_info = { - sizeof (EABPopupControlClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) eab_popup_control_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (EABPopupControl), - 0, /* n_preallocs */ - (GInstanceInitFunc) eab_popup_control_init, - }; - - pop_type = g_type_register_static (gtk_event_box_get_type (), "EABPopupControl", &pop_info, 0); - } - - return pop_type; -} - -static void -eab_popup_control_refresh_names (EABPopupControl *pop) -{ - if (pop->name_widget) { - if (pop->name && *pop->name) { - gtk_label_set_text (GTK_LABEL (pop->name_widget), pop->name); - gtk_widget_show (pop->name_widget); - } else { - gtk_widget_hide (pop->name_widget); - } - } - - if (pop->email_widget) { - if (pop->email && *pop->email) { - gtk_label_set_text (GTK_LABEL (pop->email_widget), pop->email); - gtk_widget_show (pop->email_widget); - } else { - gtk_widget_hide (pop->email_widget); - } - } - - eab_popup_control_query (pop); -} - -static gint -refresh_timeout_cb (gpointer ptr) -{ - EABPopupControl *pop = EAB_POPUP_CONTROL (ptr); - eab_popup_control_refresh_names (pop); - pop->scheduled_refresh = 0; - return 0; -} - -static void -eab_popup_control_schedule_refresh (EABPopupControl *pop) -{ - if (pop->scheduled_refresh == 0) - pop->scheduled_refresh = g_timeout_add (20, refresh_timeout_cb, pop); -} - -/* If we are handed something of the form "Foo <bar@bar.com>", - do the right thing. */ -static gboolean -eab_popup_control_set_free_form (EABPopupControl *pop, const gchar *txt) -{ - gchar *lt, *gt = NULL; - - g_return_val_if_fail (pop && EAB_IS_POPUP_CONTROL (pop), FALSE); - - if (txt == NULL) - return FALSE; - - lt = strchr (txt, '<'); - if (lt) - gt = strchr (txt, '>'); - - if (lt && gt && lt+1 < gt) { - gchar *name = g_strndup (txt, lt-txt); - gchar *email = g_strndup (lt+1, gt-lt-1); - eab_popup_control_set_name (pop, name); - eab_popup_control_set_email (pop, email); - g_free(name); - g_free(email); - - return TRUE; - } - - return FALSE; -} - -static void -eab_popup_control_set_name (EABPopupControl *pop, const gchar *name) -{ - g_return_if_fail (pop && EAB_IS_POPUP_CONTROL (pop)); - - /* We only allow the name to be set once. */ - if (pop->name) - return; - - if (!eab_popup_control_set_free_form (pop, name)) { - pop->name = g_strdup (name); - if (pop->name) - g_strstrip (pop->name); - } - - eab_popup_control_schedule_refresh (pop); -} - -static void -eab_popup_control_set_email (EABPopupControl *pop, const gchar *email) -{ - g_return_if_fail (pop && EAB_IS_POPUP_CONTROL (pop)); - - /* We only allow the e-mail to be set once. */ - if (pop->email) - return; - - if (!eab_popup_control_set_free_form (pop, email)) { - pop->email = g_strdup (email); - if (pop->email) - g_strstrip (pop->email); - } - - eab_popup_control_schedule_refresh (pop); -} - -static void -eab_popup_control_set_vcard (EABPopupControl *pop, const gchar *vcard) -{ - g_return_if_fail (pop && EAB_IS_POPUP_CONTROL (pop)); - - /* We only allow the vcard to be set once. */ - if (pop->vcard) - return; - - g_free (pop->name); - g_free (pop->email); - - pop->name = NULL; - pop->email = NULL; - - pop->vcard = g_strdup (vcard); - - eab_popup_control_schedule_refresh (pop); -} - -void -eab_popup_control_construct (EABPopupControl *pop) -{ - GtkWidget *vbox, *name_holder; - GdkColor color = { 0x0, 0xffff, 0xffff, 0xffff }; - - g_return_if_fail (pop && EAB_IS_POPUP_CONTROL (pop)); - - pop->main_vbox = gtk_vbox_new (FALSE, 0); - - /* Build Generic View */ - - name_holder = gtk_event_box_new (); - vbox = gtk_vbox_new (FALSE, 2); - pop->name_widget = gtk_label_new (""); - pop->email_widget = gtk_label_new (""); - - gtk_box_pack_start (GTK_BOX (vbox), pop->name_widget, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (vbox), pop->email_widget, TRUE, TRUE, 2); - gtk_container_add (GTK_CONTAINER (name_holder), GTK_WIDGET (vbox)); - - if (gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (name_holder)), &color, FALSE, TRUE)) { - GtkStyle *style = gtk_style_copy (gtk_widget_get_style (GTK_WIDGET (name_holder))); - style->bg[0] = color; - gtk_widget_set_style (GTK_WIDGET (name_holder), style); - g_object_unref (style); - } - - pop->generic_view = gtk_frame_new (NULL); - gtk_container_add (GTK_CONTAINER (pop->generic_view), name_holder); - gtk_box_pack_start (GTK_BOX (pop->main_vbox), pop->generic_view, TRUE, TRUE, 0); - gtk_widget_show_all (pop->generic_view); - - pop->query_msg = gtk_label_new (_("Querying Address Book...")); - gtk_box_pack_start (GTK_BOX (pop->main_vbox), pop->query_msg, TRUE, TRUE, 0); - gtk_widget_show (pop->query_msg); - - /* Build ContactDisplay */ - pop->contact_display = eab_contact_display_new (); - gtk_box_pack_start (GTK_BOX (pop->main_vbox), pop->contact_display, TRUE, TRUE, 0); - - - /* Final assembly */ - - gtk_container_add (GTK_CONTAINER (pop), pop->main_vbox); - gtk_widget_show (pop->main_vbox); - - gtk_container_set_border_width (GTK_CONTAINER (vbox), 3); - gtk_container_set_border_width (GTK_CONTAINER (pop), 2); -} - -static GtkWidget * -eab_popup_new (void) -{ - EABPopupControl *pop = g_object_new (EAB_TYPE_POPUP_CONTROL, NULL); - eab_popup_control_construct (pop); - return GTK_WIDGET (pop); -} - -static void -emit_event (EABPopupControl *pop, const char *event) -{ - if (pop->es) { - BonoboArg *arg; - - arg = bonobo_arg_new (BONOBO_ARG_BOOLEAN); - BONOBO_ARG_SET_BOOLEAN (arg, TRUE); - bonobo_event_source_notify_listeners_full (pop->es, - "GNOME/Evolution/Addressbook/AddressPopup", - "Event", - event, - arg, NULL); - bonobo_arg_release (arg); - } -} - -static void -eab_popup_control_no_matches (EABPopupControl *pop) -{ - if (pop->vcard && *pop->vcard) - e_contact_quick_add_vcard (pop->vcard, NULL, NULL); - else if (pop->email && *pop->email) { - if (pop->name && *pop->name) - e_contact_quick_add (pop->name, pop->email, NULL, NULL); - else - e_contact_quick_add_free_form (pop->email, NULL, NULL); - - } - eab_popup_control_cleanup (pop); - emit_event (pop, "Destroy"); -} - -static void -eab_popup_control_query (EABPopupControl *pop) -{ - g_return_if_fail (pop && EAB_IS_POPUP_CONTROL (pop)); - - g_object_ref (pop); - - eab_popup_control_no_matches (pop) ; - - g_object_unref (pop); - -} - -/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/ - -enum { - PROPERTY_NAME, - PROPERTY_EMAIL, - PROPERTY_TRANSITORY, - PROPERTY_VCARD -}; - -static void -set_prop (BonoboPropertyBag *bag, const BonoboArg *arg, guint arg_id, CORBA_Environment *ev, gpointer user_data) -{ - EABPopupControl *pop = EAB_POPUP_CONTROL (user_data); - - switch (arg_id) { - - case PROPERTY_NAME: - eab_popup_control_set_name (pop, BONOBO_ARG_GET_STRING (arg)); - break; - - case PROPERTY_EMAIL: - eab_popup_control_set_email (pop, BONOBO_ARG_GET_STRING (arg)); - break; - - case PROPERTY_VCARD: - eab_popup_control_set_vcard (pop, BONOBO_ARG_GET_STRING (arg)); - break; - - default: - g_return_if_reached (); - } -} - -static void -get_prop (BonoboPropertyBag *bag, BonoboArg *arg, guint arg_id, CORBA_Environment *ev, gpointer user_data) -{ - EABPopupControl *pop = EAB_POPUP_CONTROL (user_data); - - switch (arg_id) { - - case PROPERTY_NAME: - BONOBO_ARG_SET_STRING (arg, pop->name); - break; - - case PROPERTY_EMAIL: - BONOBO_ARG_SET_STRING (arg, pop->email); - break; - - case PROPERTY_TRANSITORY: - BONOBO_ARG_SET_BOOLEAN (arg, pop->transitory); - break; - - case PROPERTY_VCARD: - BONOBO_ARG_SET_STRING (arg, pop->vcard); - break; - - default: - g_return_if_reached (); - } -} - -BonoboControl * -eab_popup_control_new (void) -{ - BonoboControl *control; - BonoboPropertyBag *bag; - EABPopupControl *addy; - GtkWidget *w; - - w = eab_popup_new (); - addy = EAB_POPUP_CONTROL (w); - - control = bonobo_control_new (w); - gtk_widget_show (w); - - bag = bonobo_property_bag_new (get_prop, set_prop, w); - bonobo_property_bag_add (bag, "name", PROPERTY_NAME, - BONOBO_ARG_STRING, NULL, NULL, - BONOBO_PROPERTY_WRITEABLE | BONOBO_PROPERTY_READABLE); - - bonobo_property_bag_add (bag, "email", PROPERTY_EMAIL, - BONOBO_ARG_STRING, NULL, NULL, - BONOBO_PROPERTY_WRITEABLE | BONOBO_PROPERTY_READABLE); - - bonobo_property_bag_add (bag, "transitory", PROPERTY_TRANSITORY, - BONOBO_ARG_BOOLEAN, NULL, NULL, - BONOBO_PROPERTY_READABLE); - - bonobo_property_bag_add (bag, "vcard", PROPERTY_VCARD, - BONOBO_ARG_STRING, NULL, NULL, - BONOBO_PROPERTY_WRITEABLE | BONOBO_PROPERTY_READABLE); - - bonobo_control_set_properties (control, bonobo_object_corba_objref (BONOBO_OBJECT (bag)), NULL); - bonobo_object_unref (BONOBO_OBJECT (bag)); - - addy->es = bonobo_event_source_new (); - bonobo_object_add_interface (BONOBO_OBJECT (control), - BONOBO_OBJECT (addy->es)); - - return control; -} diff --git a/addressbook/gui/widgets/eab-popup-control.h b/addressbook/gui/widgets/eab-popup-control.h deleted file mode 100644 index e8031a7fec..0000000000 --- a/addressbook/gui/widgets/eab-popup-control.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * 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: - * Jon Trowbridge <trow@ximian.com> - * Chris Toshok <toshok@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef __EAB_POPUP_CONTROL_H__ -#define __EAB_POPUP_CONTROL_H__ - -#include <bonobo/bonobo-event-source.h> -#include <libebook/e-book.h> -#include <libebook/e-contact.h> - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define EAB_TYPE_POPUP_CONTROL (eab_popup_control_get_type ()) -#define EAB_POPUP_CONTROL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EAB_TYPE_POPUP_CONTROL, EABPopupControl)) -#define EAB_POPUP_CONTROL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EAB_TYPE_POPUP_CONTROL, EABPopupControlClass)) -#define EAB_IS_POPUP_CONTROL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EAB_TYPE_POPUP_CONTROL)) -#define EAB_IS_POPUP_CONTROL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EAB_TYPE_POPUP_CONTROL)) - -typedef struct _EABPopupControl EABPopupControl; -typedef struct _EABPopupControlClass EABPopupControlClass; - -struct _EABPopupControl { - GtkEventBox parent; - - gchar *name; - gchar *email; - gchar *vcard; - - GtkWidget *name_widget; - GtkWidget *email_widget; - GtkWidget *query_msg; - - GtkWidget *main_vbox; - GtkWidget *generic_view; - GtkWidget *contact_display; - - gboolean transitory; - - guint scheduled_refresh; - EBook *book; - guint query_tag; - gboolean multiple_matches; - EContact *contact; - - BonoboEventSource *es; -}; - -struct _EABPopupControlClass { - GtkEventBoxClass parent_class; -}; - -GType eab_popup_control_get_type (void); - -void eab_popup_control_construct (EABPopupControl *); - -BonoboControl *eab_popup_control_new (void); - -G_END_DECLS - -#endif /* __EAB_POPUP_CONTROL_H__ */ - diff --git a/addressbook/gui/widgets/eab-popup.c b/addressbook/gui/widgets/eab-popup.c deleted file mode 100644 index 17f979734b..0000000000 --- a/addressbook/gui/widgets/eab-popup.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * 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: - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <stdlib.h> - -#include <glib.h> - -#include "eab-popup.h" -#include <libedataserverui/e-source-selector.h> -#include <libebook/e-contact.h> - -static GObjectClass *eabp_parent; - -static void -eabp_init(GObject *o) -{ - /*EABPopup *eabp = (EABPopup *)o; */ -} - -static void -eabp_finalise(GObject *o) -{ - ((GObjectClass *)eabp_parent)->finalize(o); -} - -static void -eabp_target_free(EPopup *ep, EPopupTarget *t) -{ - switch (t->type) { - case EAB_POPUP_TARGET_SELECT: { - EABPopupTargetSelect *s = (EABPopupTargetSelect *)t; - int i; - - for (i=0;i<s->cards->len;i++) - g_object_unref(s->cards->pdata[i]); - g_ptr_array_free(s->cards, TRUE); - g_object_unref(s->book); - - break; } - case EAB_POPUP_TARGET_URI: { - EABPopupTargetURI *s = (EABPopupTargetURI *)t; - - g_free(s->uri); - break; } - case EAB_POPUP_TARGET_SOURCE: { - EABPopupTargetSource *s = (EABPopupTargetSource *)t; - - g_object_unref(s->selector); - break; } - -#ifdef ADAPTED_TO_E_NAME_SELECTOR - - case EAB_POPUP_TARGET_SELECT_NAMES: { - EABPopupTargetSelectNames *s = (EABPopupTargetSelectNames *)t; - - g_object_unref(s->model); - break; } - -#endif - - } - - ((EPopupClass *)eabp_parent)->target_free(ep, t); -} - -static void -eabp_class_init(GObjectClass *klass) -{ - klass->finalize = eabp_finalise; - ((EPopupClass *)klass)->target_free = eabp_target_free; -} - -GType -eab_popup_get_type(void) -{ - static GType type = 0; - - if (type == 0) { - static const GTypeInfo info = { - sizeof(EABPopupClass), - NULL, NULL, - (GClassInitFunc)eabp_class_init, - NULL, NULL, - sizeof(EABPopup), 0, - (GInstanceInitFunc)eabp_init - }; - eabp_parent = g_type_class_ref(e_popup_get_type()); - type = g_type_register_static(e_popup_get_type(), "EABPopup", &info, 0); - } - - return type; -} - -EABPopup *eab_popup_new(const char *menuid) -{ - EABPopup *eabp = g_object_new(eab_popup_get_type(), NULL); - - e_popup_construct(&eabp->popup, menuid); - - return eabp; -} - -/** - * eab_popup_target_new_select: - * @eabp: Address book popup. - * @book: Book the cards belong to. - * @readonly: Book is read-only mode. FIXME: Why can't we just get this off the book? - * @cards: Cards selected. This will be freed on completion. - * - * Create a new selection popup target. - * - * Return value: - **/ - - -EABPopupTargetURI * -eab_popup_target_new_uri(EABPopup *emp, const char *uri) -{ - EABPopupTargetURI *t = e_popup_target_new(&emp->popup, EAB_POPUP_TARGET_URI, sizeof(*t)); - guint32 mask = ~0; - - t->uri = g_strdup(uri); - - if (g_ascii_strncasecmp(uri, "http:", 5) == 0 - || g_ascii_strncasecmp(uri, "https:", 6) == 0) - mask &= ~EAB_POPUP_URI_HTTP; - if (g_ascii_strncasecmp(uri, "internal-mailto:", 16) == 0) - mask &= ~EAB_POPUP_URI_MAILTO; - else - mask &= ~EAB_POPUP_URI_NOT_MAILTO; - - t->target.mask = mask; - - return t; -} - - - - -EABPopupTargetSelect * -eab_popup_target_new_select(EABPopup *eabp, struct _EBook *book, int readonly, GPtrArray *cards) -{ - EABPopupTargetSelect *t = e_popup_target_new(&eabp->popup, EAB_POPUP_TARGET_SELECT, sizeof(*t)); - guint32 mask = ~0; - int has_email = FALSE, i; - - /* FIXME: duplicated in eab-menu.c */ - - t->book = book; - g_object_ref(book); - t->cards = cards; - - for (i=0;i<cards->len && !has_email;i++) { - EContact *contact = cards->pdata[i]; - GList *email; - - email = e_contact_get(E_CONTACT(contact), E_CONTACT_EMAIL); - if (email) { - has_email = TRUE; - - g_list_foreach(email, (GFunc)g_free, NULL); - g_list_free(email); - } - } - - if (cards->len == 1) { - if (e_contact_get (E_CONTACT(cards->pdata[0]), E_CONTACT_IS_LIST)) - mask &= ~EAB_POPUP_LIST; - else - mask &= ~EAB_POPUP_CONTACT; - } - - if (has_email) - mask &= ~EAB_POPUP_SELECT_EMAIL; - - if (!readonly) - mask &= ~EAB_POPUP_SELECT_EDITABLE; - - if (cards->len == 1) - mask &= ~EAB_POPUP_SELECT_ONE; - - if (cards->len > 1) - mask &= ~EAB_POPUP_SELECT_MANY; - - if (cards->len >= 1) - mask &= ~EAB_POPUP_SELECT_ANY; - - t->target.mask = mask; - - return t; -} - -EABPopupTargetSource * -eab_popup_target_new_source(EABPopup *eabp, ESourceSelector *selector) -{ - EABPopupTargetSource *t = e_popup_target_new(&eabp->popup, EAB_POPUP_TARGET_SOURCE, sizeof(*t)); - guint32 mask = ~0; - const char *source_uri; - ESource *source; - - /* TODO: this is duplicated for calendar and tasks too */ - - t->selector = selector; - g_object_ref(selector); - - /* TODO: perhaps we need to copy this so it doesn't change during the lifecycle */ - source = e_source_selector_peek_primary_selection(selector); - if (source) - mask &= ~EAB_POPUP_SOURCE_PRIMARY; - - /* FIXME Gross hack, should have a property or something */ - source_uri = e_source_peek_relative_uri(source); - if (source_uri && !strcmp("system", source_uri)) - mask &= ~EAB_POPUP_SOURCE_SYSTEM; - else - mask &= ~EAB_POPUP_SOURCE_USER; - - t->target.mask = mask; - - return t; -} - -#ifdef ADAPTED_TO_E_NAME_SELECTOR - -EABPopupTargetSelectNames * -eab_popup_target_new_select_names(EABPopup *eabp, struct _ESelectNamesModel *model, int row) -{ - EABPopupTargetSelectNames *t = e_popup_target_new(&eabp->popup, EAB_POPUP_TARGET_SELECT_NAMES, sizeof(*t)); - - /* TODO: this is sort of not very useful, maybe the popup which uses it doesn't - need to be pluggable */ - - t->model = model; - g_object_ref(model); - t->row = row; - - return t; -} - -#endif - -/* ********************************************************************** */ -/* Popup menu plugin handler */ - -/* -<e-plugin - class="org.gnome.mail.plugin.popup:1.0" - id="org.gnome.mail.plugin.popup.iteab:1.0" - type="shlib" - location="/opt/gnome2/lib/camel/1.0/libcamelimap.so" - name="imap" - description="IMAP4 and IMAP4v1 mail store"> - <hook class="org.gnome.mail.popupMenu:1.0" - handler="HandlePopup"> - <menu id="any" target="select"> - <iteab - type="iteab|toggle|radio|image|submenu|bar" - active - path="foo/bar" - label="label" - icon="foo" - mask="select_one" - activate="eabp_view_eabacs"/> - </menu> - </extension> - -*/ - -static void *eabph_parent_class; -#define eabph ((EABPopupHook *)eph) - -static const EPopupHookTargetMask eabph_select_masks[] = { - { "one", EAB_POPUP_SELECT_ONE }, - { "many", EAB_POPUP_SELECT_MANY }, - { "any", EAB_POPUP_SELECT_ANY }, - { "editable", EAB_POPUP_SELECT_EDITABLE }, - { "email", EAB_POPUP_SELECT_EMAIL }, - { NULL } -}; - -static const EPopupHookTargetMask eabph_source_masks[] = { - { "primary", EAB_POPUP_SOURCE_PRIMARY }, - { "system", EAB_POPUP_SOURCE_SYSTEM }, - { NULL } -}; - -static const EPopupHookTargetMask eabph_uri_masks[] = { - { "http", EAB_POPUP_URI_HTTP }, - { "internal-mailto", EAB_POPUP_URI_MAILTO }, - { "notmailto", EAB_POPUP_URI_NOT_MAILTO }, - { NULL } -}; - -static const EPopupHookTargetMask eabph_select_names_masks[] = { - { NULL } -}; - -static const EPopupHookTargetMap eabph_targets[] = { - { "select", EAB_POPUP_TARGET_SELECT, eabph_select_masks }, - { "uri", EAB_POPUP_TARGET_URI, eabph_uri_masks }, - { "source", EAB_POPUP_TARGET_SOURCE, eabph_source_masks }, - { "select-names", EAB_POPUP_TARGET_SELECT_NAMES, eabph_select_names_masks }, - { NULL } -}; - -static void -eabph_finalise(GObject *o) -{ - /*EPluginHook *eph = (EPluginHook *)o;*/ - - ((GObjectClass *)eabph_parent_class)->finalize(o); -} - -static void -eabph_class_init(EPluginHookClass *klass) -{ - int i; - - ((GObjectClass *)klass)->finalize = eabph_finalise; - ((EPluginHookClass *)klass)->id = "org.gnome.evolution.addressbook.popup:1.0"; - - for (i=0;eabph_targets[i].type;i++) - e_popup_hook_class_add_target_map((EPopupHookClass *)klass, &eabph_targets[i]); - - ((EPopupHookClass *)klass)->popup_class = g_type_class_ref(eab_popup_get_type()); -} - -GType -eab_popup_hook_get_type(void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof(EABPopupHookClass), NULL, NULL, (GClassInitFunc) eabph_class_init, NULL, NULL, - sizeof(EABPopupHook), 0, (GInstanceInitFunc) NULL, - }; - - eabph_parent_class = g_type_class_ref(e_popup_hook_get_type()); - type = g_type_register_static(e_popup_hook_get_type(), "EABPopupHook", &info, 0); - } - - return type; -} diff --git a/addressbook/gui/widgets/eab-popup.h b/addressbook/gui/widgets/eab-popup.h deleted file mode 100644 index 933c815af8..0000000000 --- a/addressbook/gui/widgets/eab-popup.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * - * 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: - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef __EAB_POPUP_H__ -#define __EAB_POPUP_H__ - -#include <glib-object.h> - -#include "e-util/e-popup.h" - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -#define ADAPTED_TO_E_NAME_SELECTOR 1 - -typedef struct _EABPopup EABPopup; -typedef struct _EABPopupClass EABPopupClass; - -/** - * enum _eab_popup_target_t - A list of mail popup target types. - * - * @EAB_POPUP_TARGET_SELECT: A selection of cards - * @EAB_POPUP_TARGET_SOURCE: A source selection. - * - * Defines the value of the targetid for all EABPopup target types. - **/ -enum _eab_popup_target_t { - EAB_POPUP_TARGET_SELECT, - EAB_POPUP_TARGET_URI, - EAB_POPUP_TARGET_SOURCE, - EAB_POPUP_TARGET_SELECT_NAMES, -}; - -/** - * enum _eab_popup_target_select_t - EABPopupTargetSelect qualifiers. - * - * @EAB_POPUP_SELECT_ONE: Only one item is selected. - * @EAB_POPUP_SELECT_MANY: Two or more items are selected. - * @EAB_POPUP_SELECT_ANY: One or more items are selected. - * @EAB_POPUP_SELECT_EDITABLE: Read/writable source. - * @EAB_POPUP_SELECT_EMAIL: Has an email address. - **/ -enum _eab_popup_target_select_t { - EAB_POPUP_SELECT_ONE = 1<<0, - EAB_POPUP_SELECT_MANY = 1<<1, - EAB_POPUP_SELECT_ANY = 1<<2, - EAB_POPUP_SELECT_EDITABLE = 1<<3, - EAB_POPUP_SELECT_EMAIL = 1<<4, - EAB_POPUP_LIST = 1<<5, - EAB_POPUP_CONTACT = 1<<6, -}; - -enum _eab_popup_target_uri_t { - EAB_POPUP_URI_HTTP = 1<<0, - EAB_POPUP_URI_MAILTO = 1<<1, - EAB_POPUP_URI_NOT_MAILTO = 1<<2, -}; -/** - * enum _eab_popup_target_source_t - EABPopupTargetSource qualifiers. - * - * @EAB_POPUP_SOURCE_PRIMARY: Has a primary selection. - * @EAB_POPUP_SOURCE_SYSTEM: Is a 'system' folder. - * - **/ -enum _eab_popup_target_source_t { - EAB_POPUP_SOURCE_PRIMARY = 1<<0, - EAB_POPUP_SOURCE_SYSTEM = 1<<1, /* system folder */ - EAB_POPUP_SOURCE_USER = 1<<2, /* user folder (!system) */ -}; - -typedef struct _EABPopupTargetSelect EABPopupTargetSelect; -typedef struct _EABPopupTargetSource EABPopupTargetSource; -typedef struct _EABPopupTargetSelectNames EABPopupTargetSelectNames; -typedef struct _EABPopupTargetURI EABPopupTargetURI; -/** - * struct _EABPopupTargetSelect - A list of address cards. - * - * @target: Superclass. - * @book: Book the cards belong to. - * @cards: All selected cards. - * - * Used to represent a selection of cards as context for a popup - * menu. - **/ -struct _EABPopupTargetSelect { - EPopupTarget target; - - struct _EBook *book; - GPtrArray *cards; -}; - - -struct _EABPopupTargetURI { - EPopupTarget target; - char *uri; -}; - -/** - * struct _EABPopupTargetSource - A source target. - * - * @target: Superclass. - * @selector: Selector holding the source selection. - * - * This target is used to represent a source selection. - **/ -struct _EABPopupTargetSource { - EPopupTarget target; - - struct _ESourceSelector *selector; -}; - -#ifdef ADAPTED_TO_E_NAME_SELECTOR - -/** - * struct _EABPopupTargetSelectNames - A select names target. - * - * @target: Superclass. - * @model: Select names model. - * @row: Row of item selected. - * - * This target is used to represent an item selected in an - * ESelectNames model. - **/ -struct _EABPopupTargetSelectNames { - EPopupTarget target; - - struct _ESelectNamesModel *model; - int row; -}; - -#endif - -typedef struct _EPopupItem EABPopupItem; - -/* The object */ -struct _EABPopup { - EPopup popup; - - struct _EABPopupPrivate *priv; -}; - -struct _EABPopupClass { - EPopupClass popup_class; -}; - -GType eab_popup_get_type(void); - -EABPopup *eab_popup_new(const char *menuid); - -EABPopupTargetSelect *eab_popup_target_new_select(EABPopup *eabp, struct _EBook *book, int readonly, GPtrArray *cards); -EABPopupTargetURI *eab_popup_target_new_uri(EABPopup *emp, const char *uri); -EABPopupTargetSource *eab_popup_target_new_source(EABPopup *eabp, struct _ESourceSelector *selector); - -#ifdef ADAPTED_TO_E_NAME_SELECTOR - -EABPopupTargetSelectNames *eab_popup_target_new_select_names(EABPopup *eabp, struct _ESelectNamesModel *model, int row); - -#endif - -/* ********************************************************************** */ - -typedef struct _EABPopupHook EABPopupHook; -typedef struct _EABPopupHookClass EABPopupHookClass; - -struct _EABPopupHook { - EPopupHook hook; -}; - -struct _EABPopupHookClass { - EPopupHookClass hook_class; -}; - -GType eab_popup_hook_get_type(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __EAB_POPUP_H__ */ diff --git a/addressbook/gui/widgets/eab-vcard-control.c b/addressbook/gui/widgets/eab-vcard-control.c deleted file mode 100644 index 1e890167f6..0000000000 --- a/addressbook/gui/widgets/eab-vcard-control.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * 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> - * Chris Toshok <toshok@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#include <config.h> -#include <string.h> - -#include <gtk/gtk.h> -#include <bonobo/bonobo-generic-factory.h> -#include <bonobo/bonobo-persist.h> -#include <bonobo/bonobo-persist-stream.h> -#include <bonobo/bonobo-stream-client.h> -#include <e-util/e-util.h> - -#include <libebook/e-book.h> -#include <libebook/e-contact.h> -#include <addressbook/gui/component/addressbook.h> -#include <addressbook/gui/widgets/eab-contact-display.h> -#include <addressbook/util/eab-book-util.h> - -#include "eab-vcard-control.h" -#include "eab-contact-merging.h" - -typedef struct { - EABContactDisplay *display; - GList *card_list; - GtkWidget *label; - EABContactDisplayRenderMode render_mode; -} EABVCardControl; - -#define VCARD_CONTROL_ID "OAFIID:GNOME_Evolution_Addressbook_VCard_Control:" BASE_VERSION - -/* - * Bonobo::PersistStream - * - * These two functions implement the Bonobo::PersistStream load and - * save methods which allow data to be loaded into and out of the - * BonoboObject. - */ -static char * -stream_read (Bonobo_Stream stream) -{ - Bonobo_Stream_iobuf *buffer; - CORBA_Environment ev; - char *data = NULL; - gint length = 0; - - CORBA_exception_init (&ev); - do { -#define READ_CHUNK_SIZE 65536 - Bonobo_Stream_read (stream, READ_CHUNK_SIZE, - &buffer, &ev); - - if (ev._major != CORBA_NO_EXCEPTION) { - CORBA_exception_free (&ev); - return NULL; - } - - if (buffer->_length <= 0) - break; - - data = g_realloc (data, length + buffer->_length + 1); - - memcpy (data + length, buffer->_buffer, buffer->_length); - - length += buffer->_length; - - CORBA_free (buffer); - } while (1); - - CORBA_free (buffer); - CORBA_exception_free (&ev); - - if (data) - data[length] = '\0'; - else - data = g_strdup(""); - - return data; -} /* stream_read */ - -/* - * This function implements the Bonobo::PersistStream:load method. - */ -static void -pstream_load (BonoboPersistStream *ps, const Bonobo_Stream stream, - Bonobo_Persist_ContentType type, void *data, - CORBA_Environment *ev) -{ - GList *list; - char *vcard; - EABVCardControl *vcard_control = data; - - if (type && g_ascii_strcasecmp (type, "text/vCard") != 0 && - g_ascii_strcasecmp (type, "text/x-vCard") != 0) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_Bonobo_Persist_WrongDataType, NULL); - return; - } - - if ((vcard = stream_read (stream)) == NULL) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_Bonobo_Persist_FileNotFound, NULL); - return; - } - - g_list_foreach ( - vcard_control->card_list, - (GFunc) g_object_unref, NULL); - g_list_free (vcard_control->card_list); - - list = eab_contact_list_from_string (vcard); - g_free(vcard); - vcard_control->card_list = list; - if (list) { - eab_contact_display_render (vcard_control->display, E_CONTACT (list->data), - vcard_control->render_mode); - } - if (list && list->next) { - char *message; - int length = g_list_length (list) - 1; - message = g_strdup_printf (ngettext("There is one other contact.", - "There are %d other contacts.", length), - length); - gtk_label_set_text (GTK_LABEL (vcard_control->label), message); - g_free (message); - gtk_widget_show (vcard_control->label); - } else { - gtk_widget_hide (vcard_control->label); - } -} /* pstream_load */ - -/* - * This function implements the Bonobo::PersistStream:save method. - */ -static void -pstream_save (BonoboPersistStream *ps, const Bonobo_Stream stream, - Bonobo_Persist_ContentType type, void *data, - CORBA_Environment *ev) -{ - EABVCardControl *vcard_control = data; - char *vcard; - int length; - - if (type && g_ascii_strcasecmp (type, "text/vCard") != 0 && - g_ascii_strcasecmp (type, "text/x-vCard") != 0) { - CORBA_exception_set (ev, CORBA_USER_EXCEPTION, - ex_Bonobo_Persist_WrongDataType, NULL); - return; - } - - vcard = eab_contact_list_to_string (vcard_control->card_list); - length = strlen (vcard); - bonobo_stream_client_write (stream, vcard, length, ev); - g_free (vcard); -} /* pstream_save */ - -static Bonobo_Persist_ContentTypeList * -pstream_get_content_types (BonoboPersistStream *ps, void *closure, - CORBA_Environment *ev) -{ - return bonobo_persist_generate_content_types (2, "text/vCard", "text/x-vCard"); -} - -static void -book_open_cb (EBook *book, EBookStatus status, gpointer closure) -{ - GList *list = closure; - if (status == E_BOOK_ERROR_OK) { - GList *p; - for (p = list; p; p = p->next) { - /* XXX argh, more passing of NULL's for callbacks */ - eab_merging_book_add_contact (book, E_CONTACT (p->data), NULL, NULL); - } - } - if (book) - g_object_unref (book); - g_list_foreach (list, (GFunc) g_object_unref, NULL); - g_list_free (list); -} - -static void -save_in_addressbook(GtkWidget *button, gpointer data) -{ - EABVCardControl *vcard_control = data; - GList *list, *p; - - list = g_list_copy (vcard_control->card_list); - - for (p = list; p; p = p->next) - g_object_ref (p->data); - - addressbook_load_default_book (book_open_cb, list); -} - -static void -toggle_full_vcard(GtkWidget *button, gpointer data) -{ - EABVCardControl *vcard_control = data; - char *label; - - if (!vcard_control->card_list) - return; - - if (vcard_control->render_mode == EAB_CONTACT_DISPLAY_RENDER_NORMAL) { - vcard_control->render_mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT; - label = _("Show Full vCard"); - } - else { - vcard_control->render_mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL; - label = _("Show Compact vCard"); - } - - gtk_button_set_label (GTK_BUTTON (button), label); - eab_contact_display_render (vcard_control->display, E_CONTACT (vcard_control->card_list->data), - vcard_control->render_mode); -} - -static void -free_struct (gpointer data, GObject *where_object_was) -{ - EABVCardControl *vcard_control = data; - - g_list_foreach ( - vcard_control->card_list, - (GFunc) g_object_unref, NULL); - g_list_free (vcard_control->card_list); - g_free (vcard_control); -} - -BonoboControl * -eab_vcard_control_new (void) -{ - BonoboControl *control; - BonoboPersistStream *stream; - GtkWidget *display; - GtkWidget *button1, *button2; - GtkWidget *bbox; - GtkWidget *vbox; - - EABVCardControl *vcard_control = g_new (EABVCardControl, 1); - - vcard_control->card_list = NULL; - vcard_control->display = NULL; - vcard_control->label = NULL; - - vcard_control->render_mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT; - - /* Create the control. */ - - display = eab_contact_display_new (); - vcard_control->display = EAB_CONTACT_DISPLAY (display); - - bbox = gtk_hbutton_box_new (); - gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_START); - gtk_box_set_spacing (GTK_BOX (bbox), 12); - - button1 = gtk_button_new_with_label(_("Show Full vCard")); - g_signal_connect (button1, "clicked", - G_CALLBACK (toggle_full_vcard), vcard_control); - gtk_box_pack_start (GTK_BOX (bbox), button1, FALSE, FALSE, 0); - - button2 = gtk_button_new_with_label(_("Save in address book")); - g_signal_connect (button2, "clicked", - G_CALLBACK (save_in_addressbook), vcard_control); - gtk_box_pack_start (GTK_BOX (bbox), button2, FALSE, FALSE, 0); - - /* This is intentionally not shown. */ - vcard_control->label = gtk_label_new (""); - - vbox = gtk_vbox_new (FALSE, 0); - gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (vbox), display, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (vbox), vcard_control->label, TRUE, TRUE, 0); - gtk_widget_show_all (bbox); - gtk_widget_show (display); - gtk_widget_show (vbox); - - control = bonobo_control_new (vbox); - - g_object_weak_ref (G_OBJECT (control), free_struct, vcard_control); - - stream = bonobo_persist_stream_new (pstream_load, pstream_save, - pstream_get_content_types, - VCARD_CONTROL_ID, - vcard_control); - - if (stream == NULL) { - bonobo_object_unref (BONOBO_OBJECT (control)); - return NULL; - } - - bonobo_object_add_interface (BONOBO_OBJECT (control), - BONOBO_OBJECT (stream)); - - return control; -} diff --git a/addressbook/gui/widgets/gal-view-minicard.c b/addressbook/gui/widgets/gal-view-minicard.c index 4645517bfc..cb2f52f4ff 100644 --- a/addressbook/gui/widgets/gal-view-minicard.c +++ b/addressbook/gui/widgets/gal-view-minicard.c @@ -26,115 +26,172 @@ #include <config.h> #include <libxml/parser.h> - -#include <libedataserver/e-xml-utils.h> - #include <e-util/e-xml-utils.h> +#include <libedataserver/e-xml-utils.h> #include "gal-view-minicard.h" -#define PARENT_TYPE gal_view_get_type () -#define d(x) +static gpointer parent_class; + +static void +view_minicard_column_width_changed (EAddressbookView *address_view, + gdouble width) +{ + GalView *view; + GalViewInstance *view_instance; + GalViewMinicard *view_minicard; + GtkScrolledWindow *scrolled_window; + GtkAdjustment *adjustment; + GtkWidget *widget; + gdouble value, lower, upper; + gdouble page_increment, page_size; + + view_instance = e_addressbook_view_get_view_instance (address_view); + view = gal_view_instance_get_current_view (view_instance); + view_minicard = GAL_VIEW_MINICARD (view); + + if (view_minicard->column_width != width) { + view_minicard->column_width = width; + gal_view_changed (view); + } + + widget = e_addressbook_view_get_view_widget (address_view); + scrolled_window = GTK_SCROLLED_WINDOW (widget); + adjustment = gtk_scrolled_window_get_hadjustment (scrolled_window); + + value = gtk_adjustment_get_value (adjustment); + lower = gtk_adjustment_get_lower (adjustment); + upper = gtk_adjustment_get_upper (adjustment); + page_increment = gtk_adjustment_get_page_increment (adjustment); + page_size = gtk_adjustment_get_page_size (adjustment); + + adjustment = GTK_ADJUSTMENT (gtk_adjustment_new ( + value, lower, upper, page_size, page_increment, page_size)); + gtk_scrolled_window_set_hadjustment (scrolled_window, adjustment); +} + +static void +view_minicard_finalize (GObject *object) +{ + GalViewMinicard *view = GAL_VIEW_MINICARD (object); + + if (view->title != NULL) { + gal_view_minicard_detach (view); + g_free (view->title); + view->title = NULL; + } -static GalViewClass *gal_view_minicard_parent_class; + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} static void -gal_view_minicard_load (GalView *view, - const char *filename) +view_minicard_load (GalView *view, + const gchar *filename) { + GalViewMinicard *view_minicard; xmlDoc *doc; + xmlNode *root; + + view_minicard = GAL_VIEW_MINICARD (view); doc = e_xml_parse_file (filename); - if (doc) { - xmlNode *root = xmlDocGetRootElement(doc); - GAL_VIEW_MINICARD (view)->column_width = e_xml_get_double_prop_by_name_with_default (root, (const unsigned char *)"column_width", 150); - xmlFreeDoc(doc); - } + g_return_if_fail (doc != NULL); + + root = xmlDocGetRootElement (doc); + view_minicard->column_width = + e_xml_get_double_prop_by_name_with_default ( + root, (guchar *) "column_width", 150); + xmlFreeDoc (doc); } static void -gal_view_minicard_save (GalView *view, - const char *filename) +view_minicard_save (GalView *view, + const gchar *filename) { + GalViewMinicard *view_minicard; xmlDoc *doc; xmlNode *root; - doc = xmlNewDoc((const unsigned char *)"1.0"); - root = xmlNewNode (NULL, (const unsigned char *)"EMinicardViewState"); - e_xml_set_double_prop_by_name (root, (const unsigned char *)"column_width", GAL_VIEW_MINICARD (view)->column_width); - xmlDocSetRootElement(doc, root); + view_minicard = GAL_VIEW_MINICARD (view); + + doc = xmlNewDoc ((guchar *) "1.0"); + root = xmlNewNode (NULL, (guchar *) "EMinicardViewState"); + e_xml_set_double_prop_by_name ( + root, (guchar *) "column_width", + view_minicard->column_width); + xmlDocSetRootElement (doc, root); e_xml_save_file (filename, doc); - xmlFreeDoc(doc); + xmlFreeDoc (doc); } -static const char * -gal_view_minicard_get_title (GalView *view) +static const gchar * +view_minicard_get_title (GalView *view) { - return GAL_VIEW_MINICARD(view)->title; + GalViewMinicard *view_minicard; + + view_minicard = GAL_VIEW_MINICARD (view); + + return view_minicard->title; } static void -gal_view_minicard_set_title (GalView *view, - const char *title) +view_minicard_set_title (GalView *view, + const char *title) { - g_free(GAL_VIEW_MINICARD(view)->title); - GAL_VIEW_MINICARD(view)->title = g_strdup(title); + GalViewMinicard *view_minicard; + + view_minicard = GAL_VIEW_MINICARD (view); + + g_free (view_minicard->title); + view_minicard->title = g_strdup (title); } -static const char * -gal_view_minicard_get_type_code (GalView *view) +static const gchar * +view_minicard_get_type_code (GalView *view) { return "minicard"; } static GalView * -gal_view_minicard_clone (GalView *view) +view_minicard_clone (GalView *view) { - GalViewMinicard *gvm, *new; + GalViewMinicard *view_minicard; + GalViewMinicard *clone; - gvm = GAL_VIEW_MINICARD(view); + view_minicard = GAL_VIEW_MINICARD(view); - new = g_object_new (GAL_TYPE_VIEW_MINICARD, NULL); - new->title = g_strdup (gvm->title); - new->column_width = gvm->column_width; + clone = g_object_new (GAL_TYPE_VIEW_MINICARD, NULL); + clone->column_width = view_minicard->column_width; + clone->title = g_strdup (view_minicard->title); - return GAL_VIEW(new); + return GAL_VIEW (clone); } static void -gal_view_minicard_dispose (GObject *object) +gal_view_minicard_class_init (GalViewMinicardClass *class) { - GalViewMinicard *view = GAL_VIEW_MINICARD(object); + GObjectClass *object_class; + GalViewClass *gal_view_class; - if (view->title != NULL) { - gal_view_minicard_detach (view); - g_free(view->title); - view->title = NULL; - } + parent_class = g_type_class_peek_parent (class); - if (G_OBJECT_CLASS (gal_view_minicard_parent_class)->dispose) - (* G_OBJECT_CLASS (gal_view_minicard_parent_class)->dispose) (object); -} + object_class = G_OBJECT_CLASS (class); + object_class->dispose = view_minicard_finalize; + + gal_view_class = GAL_VIEW_CLASS (class); + gal_view_class->edit = NULL; + gal_view_class->load = view_minicard_load; + gal_view_class->save = view_minicard_save; + gal_view_class->get_title = view_minicard_get_title; + gal_view_class->set_title = view_minicard_set_title; + gal_view_class->get_type_code = view_minicard_get_type_code; + gal_view_class->clone = view_minicard_clone; -static void -gal_view_minicard_class_init (GObjectClass *object_class) -{ - GalViewClass *gal_view_class = GAL_VIEW_CLASS(object_class); - gal_view_minicard_parent_class = g_type_class_ref (PARENT_TYPE); - - gal_view_class->edit = NULL ; - gal_view_class->load = gal_view_minicard_load ; - gal_view_class->save = gal_view_minicard_save ; - gal_view_class->get_title = gal_view_minicard_get_title ; - gal_view_class->set_title = gal_view_minicard_set_title ; - gal_view_class->get_type_code = gal_view_minicard_get_type_code; - gal_view_class->clone = gal_view_minicard_clone ; - - object_class->dispose = gal_view_minicard_dispose ; } static void -gal_view_minicard_init (GalViewMinicard *gvm) +gal_view_minicard_init (GalViewMinicard *gvm) { gvm->title = NULL; gvm->column_width = 150.0; @@ -143,6 +200,32 @@ gal_view_minicard_init (GalViewMinicard *gvm) gvm->emvw_column_width_changed_id = 0; } +GType +gal_view_minicard_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (GalViewMinicardClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gal_view_minicard_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalViewMinicard), + 0, /* n_preallocs */ + (GInstanceInitFunc) gal_view_minicard_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GAL_VIEW_TYPE, "GalViewMinicard", &type_info, 0); + } + + return type; +} + /** * gal_view_minicard_new * @title: The name of the new view. @@ -155,7 +238,8 @@ gal_view_minicard_init (GalViewMinicard *gvm) GalView * gal_view_minicard_new (const gchar *title) { - return gal_view_minicard_construct (g_object_new (GAL_TYPE_VIEW_MINICARD, NULL), title); + return gal_view_minicard_construct ( + g_object_new (GAL_TYPE_VIEW_MINICARD, NULL), title); } /** @@ -163,7 +247,7 @@ gal_view_minicard_new (const gchar *title) * @view: The view to construct. * @title: The name of the new view. * - * constructs the GalViewMinicard. To be used by subclasses and + * Constructs the GalViewMinicard. To be used by subclasses and * language bindings. * * Returns: The GalViewMinicard. @@ -172,85 +256,49 @@ GalView * gal_view_minicard_construct (GalViewMinicard *view, const gchar *title) { - view->title = g_strdup(title); - return GAL_VIEW(view); -} - -GType -gal_view_minicard_get_type (void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof (GalViewMinicardClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gal_view_minicard_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GalViewMinicard), - 0, /* n_preallocs */ - (GInstanceInitFunc) gal_view_minicard_init, - }; + view->title = g_strdup (title); - type = g_type_register_static (PARENT_TYPE, "GalViewMinicard", &info, 0); - } - - return type; + return GAL_VIEW (view); } -static void -column_width_changed (EMinicardViewWidget *w, double width, EABView *address_view) +void +gal_view_minicard_attach (GalViewMinicard *view, + EAddressbookView *address_view) { - GalViewMinicard *view = GAL_VIEW_MINICARD (gal_view_instance_get_current_view (address_view->view_instance)); - GtkScrolledWindow *scrolled_window; - GtkAdjustment *adj; - GtkAdjustment *adj_new; + GObject *object; - d(g_print("%s: Old width = %f, New width = %f\n", G_STRFUNC, view->column_width, width)); - if (view->column_width != width) { - view->column_width = width; - gal_view_changed(GAL_VIEW(view)); - } + g_return_if_fail (GAL_IS_VIEW_MINICARD (view)); + g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (address_view)); - scrolled_window = GTK_SCROLLED_WINDOW (address_view->widget); - adj = gtk_scrolled_window_get_hadjustment (scrolled_window); - adj_new = GTK_ADJUSTMENT (gtk_adjustment_new (adj->value, adj->lower, adj->upper, - adj->page_size, adj->page_increment, - adj->page_size)); - gtk_scrolled_window_set_hadjustment (scrolled_window, adj_new); -} + object = e_addressbook_view_get_view_object (address_view); + g_return_if_fail (E_IS_MINICARD_VIEW_WIDGET (object)); -void -gal_view_minicard_attach (GalViewMinicard *view, EABView *address_view) -{ - EMinicardViewWidget *emvw = E_MINICARD_VIEW_WIDGET (address_view->object); gal_view_minicard_detach (view); + view->emvw = g_object_ref (object); - view->emvw = emvw; - - g_object_ref (view->emvw); - - g_object_set (view->emvw, - "column_width", view->column_width, - NULL); + g_object_set (view->emvw, "column-width", view->column_width, NULL); view->emvw_column_width_changed_id = - g_signal_connect(view->emvw, "column_width_changed", - G_CALLBACK (column_width_changed), address_view); + g_signal_connect_swapped ( + view->emvw, "column-width-changed", + G_CALLBACK (view_minicard_column_width_changed), + address_view); } void gal_view_minicard_detach (GalViewMinicard *view) { + g_return_if_fail (GAL_IS_VIEW_MINICARD (view)); + if (view->emvw == NULL) return; - if (view->emvw_column_width_changed_id) { - g_signal_handler_disconnect (view->emvw, - view->emvw_column_width_changed_id); + + if (view->emvw_column_width_changed_id > 0) { + g_signal_handler_disconnect ( + view->emvw, view->emvw_column_width_changed_id); view->emvw_column_width_changed_id = 0; } + g_object_unref (view->emvw); view->emvw = NULL; } diff --git a/addressbook/gui/widgets/gal-view-minicard.h b/addressbook/gui/widgets/gal-view-minicard.h index bb22cf8a57..6e1a0ca68e 100644 --- a/addressbook/gui/widgets/gal-view-minicard.h +++ b/addressbook/gui/widgets/gal-view-minicard.h @@ -22,40 +22,59 @@ * */ -#ifndef _GAL_VIEW_MINICARD_H_ -#define _GAL_VIEW_MINICARD_H_ +#ifndef GAL_VIEW_MINICARD_H +#define GAL_VIEW_MINICARD_H #include <widgets/menus/gal-view.h> #include <e-minicard-view-widget.h> #include "e-addressbook-view.h" -#define GAL_TYPE_VIEW_MINICARD (gal_view_minicard_get_type ()) -#define GAL_VIEW_MINICARD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GAL_TYPE_VIEW_MINICARD, GalViewMinicard)) -#define GAL_VIEW_MINICARD_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GAL_TYPE_VIEW_MINICARD, GalViewMinicardClass)) -#define GAL_IS_VIEW_MINICARD(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GAL_TYPE_VIEW_MINICARD)) -#define GAL_IS_VIEW_MINICARD_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GAL_TYPE_VIEW_MINICARD)) +/* Standard GObject macros */ +#define GAL_TYPE_VIEW_MINICARD \ + (gal_view_minicard_get_type ()) +#define GAL_VIEW_MINICARD(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), GAL_TYPE_VIEW_MINICARD, GalViewMinicard)) +#define GAL_VIEW_MINICARD_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), GAL_TYPE_VIEW_MINICARD, GalViewMinicardClass)) +#define GAL_IS_VIEW_MINICARD(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), GAL_TYPE_VIEW_MINICARD)) +#define GAL_IS_VIEW_MINICARD_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), GAL_TYPE_VIEW_MINICARD)) +#define GAL_VIEW_MINICARD_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), GAL_TYPE_VIEW_MINICARD, GalViewMinicardClass)) -typedef struct { - GalView base; +G_BEGIN_DECLS + +typedef struct _GalViewMinicard GalViewMinicard; +typedef struct _GalViewMinicardClass GalViewMinicardClass; + +struct _GalViewMinicard { + GalView parent; char *title; double column_width; EMinicardViewWidget *emvw; guint emvw_column_width_changed_id; -} GalViewMinicard; +}; -typedef struct { +struct _GalViewMinicardClass { GalViewClass parent_class; -} GalViewMinicardClass; - -/* Standard functions */ -GType gal_view_minicard_get_type (void); -GalView *gal_view_minicard_new (const gchar *title); -GalView *gal_view_minicard_construct (GalViewMinicard *view, - const gchar *title); -void gal_view_minicard_attach (GalViewMinicard *view, - EABView *address_view); -void gal_view_minicard_detach (GalViewMinicard *view); - -#endif /* _GAL_VIEW_MINICARD_H_ */ +}; + +GType gal_view_minicard_get_type (void); +GalView * gal_view_minicard_new (const gchar *title); +GalView * gal_view_minicard_construct (GalViewMinicard *view, + const gchar *title); +void gal_view_minicard_attach (GalViewMinicard *view, + EAddressbookView *address_view); +void gal_view_minicard_detach (GalViewMinicard *view); + +G_END_DECLS + +#endif /* GAL_VIEW_MINICARD_H */ |