diff options
Diffstat (limited to 'widgets')
156 files changed, 18588 insertions, 11759 deletions
diff --git a/widgets/Makefile.am b/widgets/Makefile.am index 347c0f7c66..99305b844e 100644 --- a/widgets/Makefile.am +++ b/widgets/Makefile.am @@ -1,9 +1,9 @@ SUBDIRS = \ - table \ - text \ misc \ + text \ e-timezone-dialog \ + table \ menus EXTRA_DIST = \ diff --git a/widgets/e-timezone-dialog/e-timezone-dialog.c b/widgets/e-timezone-dialog/e-timezone-dialog.c index 22eaabfc3a..8f22695916 100644 --- a/widgets/e-timezone-dialog/e-timezone-dialog.c +++ b/widgets/e-timezone-dialog/e-timezone-dialog.c @@ -349,7 +349,7 @@ get_local_timezone(void) location = e_cal_system_timezone_get_location (); if (location) - zone = icaltimezone_get_builtin_timezone (location); + zone = icaltimezone_get_builtin_timezone (location); g_free (location); diff --git a/widgets/menus/Makefile.am b/widgets/menus/Makefile.am index f67a07370c..f07ae41d14 100644 --- a/widgets/menus/Makefile.am +++ b/widgets/menus/Makefile.am @@ -8,7 +8,6 @@ AM_CPPFLAGS = \ $(E_UTIL_CFLAGS) libmenus_la_SOURCES = \ - gal-view-menus.c \ gal-define-views-dialog.c \ gal-define-views-model.c \ gal-view-collection.c \ @@ -18,8 +17,7 @@ libmenus_la_SOURCES = \ gal-view-instance-save-as-dialog.c \ gal-view-instance.c \ gal-view-new-dialog.c \ - gal-view.c \ - gal-view-menus.h + gal-view.c glade_DATA = \ gal-define-views.glade \ diff --git a/widgets/menus/gal-view-collection.c b/widgets/menus/gal-view-collection.c index 801a941ba4..5719e17f6b 100644 --- a/widgets/menus/gal-view-collection.c +++ b/widgets/menus/gal-view-collection.c @@ -33,7 +33,7 @@ #include <glib/gi18n.h> #include "e-util/e-util.h" #include "e-util/e-xml-utils.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include "gal-view-collection.h" diff --git a/widgets/menus/gal-view-instance.c b/widgets/menus/gal-view-instance.c index b539965abc..bd93b64034 100644 --- a/widgets/menus/gal-view-instance.c +++ b/widgets/menus/gal-view-instance.c @@ -38,7 +38,7 @@ #include <glib/gi18n.h> #include "e-util/e-util.h" #include "e-util/e-xml-utils.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include "gal-define-views-dialog.h" #include "gal-view-instance.h" @@ -46,9 +46,6 @@ G_DEFINE_TYPE (GalViewInstance, gal_view_instance, G_TYPE_OBJECT) -static const EPopupMenu separator = E_POPUP_SEPARATOR; -static const EPopupMenu terminator = E_POPUP_TERMINATOR; - #define d(x) enum { @@ -466,140 +463,3 @@ gal_view_instance_exists (GalViewInstance *instance) return FALSE; } - -typedef struct { - GalViewInstance *instance; - gchar *id; -} ListenerClosure; - -static void -view_item_cb (GtkWidget *widget, - gpointer user_data) -{ - ListenerClosure *closure = user_data; - - if (GTK_CHECK_MENU_ITEM (widget)->active) { - gal_view_instance_set_current_view_id (closure->instance, closure->id); - } -} - -static void -add_popup_radio_item (EPopupMenu *menu_item, - const gchar *title, - GCallback fn, - gpointer closure, - gboolean value) -{ - EPopupMenu menu_item_struct = - E_POPUP_RADIO_ITEM_CC (title, - fn, - closure, - 0, - 0); - menu_item_struct.is_active = value; - - e_popup_menu_copy_1 (menu_item, &menu_item_struct); -} - -static void -add_popup_menu_item (EPopupMenu *menu_item, - const gchar *title, - GCallback fn, - gpointer closure) -{ - EPopupMenu menu_item_struct = - E_POPUP_ITEM_CC (title, - fn, - closure, - 0); - - e_popup_menu_copy_1 (menu_item, &menu_item_struct); -} - -static void -define_views_dialog_response(GtkWidget *dialog, gint id, GalViewInstance *instance) -{ - if (id == GTK_RESPONSE_OK) { - gal_view_collection_save(instance->collection); - } - gtk_widget_destroy (dialog); -} - -static void -define_views_cb(GtkWidget *widget, - GalViewInstance *instance) -{ - GtkWidget *dialog = gal_define_views_dialog_new(instance->collection); - g_signal_connect(dialog, "response", - G_CALLBACK(define_views_dialog_response), instance); - gtk_widget_show(dialog); -} - -static void -save_current_view_cb(GtkWidget *widget, - GalViewInstance *instance) -{ - gal_view_instance_save_as (instance); -} - -EPopupMenu * -gal_view_instance_get_popup_menu (GalViewInstance *instance) -{ - EPopupMenu *ret_val; - gint length; - gint i; - gboolean found = FALSE; - gchar *id; - - length = gal_view_collection_get_count(instance->collection); - id = gal_view_instance_get_current_view_id (instance); - - ret_val = g_new (EPopupMenu, length + 6); - - for (i = 0; i < length; i++) { - gboolean value = FALSE; - GalViewCollectionItem *item = gal_view_collection_get_view_item(instance->collection, i); - ListenerClosure *closure; - - closure = g_new (ListenerClosure, 1); - closure->instance = instance; - closure->id = item->id; - g_object_ref (closure->instance); - - if (!found && id && !strcmp (id, item->id)) { - found = TRUE; - value = TRUE; - } - - add_popup_radio_item (ret_val + i, item->title, G_CALLBACK (view_item_cb), closure, value); - } - - if (!found) { - e_popup_menu_copy_1 (ret_val + i++, &separator); - - add_popup_radio_item (ret_val + i++, N_("Custom View"), NULL, NULL, TRUE); - add_popup_menu_item (ret_val + i++, N_("Save Custom View"), G_CALLBACK (save_current_view_cb), instance); - } - - e_popup_menu_copy_1 (ret_val + i++, &separator); - add_popup_menu_item (ret_val + i++, N_("Define Views..."), G_CALLBACK (define_views_cb), instance); - e_popup_menu_copy_1 (ret_val + i++, &terminator); - - if (id) - g_free (id); - - return ret_val; -} - -void -gal_view_instance_free_popup_menu (GalViewInstance *instance, EPopupMenu *menu) -{ - gint i; - /* This depends on the first non-custom closure to be a separator or a terminator. */ - for (i = 0; menu[i].name && *(menu[i].name); i++) { - g_object_unref (((ListenerClosure *)(menu[i].closure))->instance); - g_free (menu[i].closure); - } - - e_popup_menu_free (menu); -} diff --git a/widgets/menus/gal-view-instance.h b/widgets/menus/gal-view-instance.h index 65aea4b0fd..00f5065d35 100644 --- a/widgets/menus/gal-view-instance.h +++ b/widgets/menus/gal-view-instance.h @@ -26,7 +26,6 @@ #include <glib-object.h> #include <widgets/menus/gal-view-collection.h> -#include <misc/e-popup-menu.h> G_BEGIN_DECLS @@ -106,10 +105,6 @@ const gchar *gal_view_instance_get_default_view (GalViewInstance *ins void gal_view_instance_set_default_view (GalViewInstance *instance, const gchar *id); -EPopupMenu *gal_view_instance_get_popup_menu (GalViewInstance *instance); -void gal_view_instance_free_popup_menu (GalViewInstance *instance, - EPopupMenu *menu); - G_END_DECLS #endif /* _GAL_VIEW_INSTANCE_H_ */ diff --git a/widgets/menus/gal-view-menus.c b/widgets/menus/gal-view-menus.c deleted file mode 100644 index de51da49c1..0000000000 --- a/widgets/menus/gal-view-menus.c +++ /dev/null @@ -1,541 +0,0 @@ -/* - * gal-view-menus.c: Deploy a GalViewCollection in the menus. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Authors: - * Chris Lahey <clahey@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "gal-view-menus.h" - -#include <stdlib.h> -#include <string.h> -#include <gtk/gtk.h> -#include <libxml/parser.h> -#include <libxml/xmlmemory.h> -#include <glib/gi18n.h> -#include <bonobo/bonobo-ui-util.h> -#include <e-util/e-util.h> -#include <e-util/e-xml-utils.h> -#include <widgets/menus/gal-define-views-dialog.h> -#include <bonobo/bonobo-ui-util.h> -#include <libedataserver/e-list.h> - -struct _GalViewMenusPrivate { - GalViewInstance *instance; - gint collection_changed_id; - gint instance_changed_id; - BonoboUIComponent *component; - EList *listenerClosures; - GtkWidget *define_views_dialog; - - guint show_define_views : 1; -}; - -typedef struct { - GalViewInstance *instance; - gchar *id; - gint ref_count; -} ListenerClosure; - -static void collection_changed (GalViewCollection *collection, - GalViewMenus *gvm); -static void instance_changed (GalViewInstance *instance, - GalViewMenus *gvm); - -#define d(x) -#define CURRENT_VIEW_PATH "/menu/View/ViewBegin/CurrentView" - -G_DEFINE_TYPE(GalViewMenus, gal_view_menus, G_TYPE_OBJECT) - -static void -closure_free (gpointer data, gpointer user_data) -{ - ListenerClosure *closure = data; - GalViewMenus *gvm = user_data; - - closure->ref_count --; - if (closure->ref_count == 0) { - g_object_unref (closure->instance); - - bonobo_ui_component_remove_listener (gvm->priv->component, closure->id); - g_free (closure); - } -} - -static gpointer -closure_copy (gconstpointer data, gpointer user_data) -{ - ListenerClosure *closure = (gpointer) data; - - closure->ref_count ++; - return closure; -} - -static void -remove_listeners (GalViewMenus *gvm) -{ - if (gvm->priv->listenerClosures) - g_object_unref (gvm->priv->listenerClosures); - - gvm->priv->listenerClosures = NULL; -} - -static void -remove_xml (GalViewMenus *gvm) -{ -} - -static void -remove_instance (GalViewMenus *gvm) -{ - if (gvm->priv->instance) { - if (gvm->priv->instance_changed_id != 0) - g_signal_handler_disconnect (gvm->priv->instance, gvm->priv->instance_changed_id); - - if (gvm->priv->instance->collection && gvm->priv->collection_changed_id != 0) - g_signal_handler_disconnect (gvm->priv->instance->collection, gvm->priv->collection_changed_id); - } - - gvm->priv->instance_changed_id = 0; - gvm->priv->collection_changed_id = 0; - - if (gvm->priv->instance) { - g_object_unref (gvm->priv->instance); - gvm->priv->instance = NULL; - } - - remove_listeners(gvm); - remove_xml(gvm); -} - -static void -add_instance (GalViewMenus *gvm, - GalViewInstance *instance) -{ - g_object_ref (instance); - - if (gvm->priv->instance != NULL) - remove_instance (gvm); - - gvm->priv->instance = instance; - - gal_view_instance_load (gvm->priv->instance); - - gvm->priv->instance_changed_id = g_signal_connect (instance, "changed", - G_CALLBACK (instance_changed), gvm); - gvm->priv->collection_changed_id = g_signal_connect (instance->collection, "changed", - G_CALLBACK (collection_changed), gvm); -} - -static void -clear_define_views_dialog (gpointer data, - GObject *where_the_object_was) -{ - GalViewMenus *gvm = GAL_VIEW_MENUS (data); - gvm->priv->define_views_dialog = NULL; -} - -static void -gal_view_menus_finalize (GObject *object) -{ - GalViewMenus *gvm = GAL_VIEW_MENUS (object); - - remove_instance (gvm); - - gal_view_menus_unmerge (gvm, NULL); - - if (gvm->priv->component) - bonobo_object_unref (gvm->priv->component); - - if (gvm->priv->define_views_dialog) - g_object_weak_unref (G_OBJECT (gvm->priv->define_views_dialog), clear_define_views_dialog, gvm); - - g_free(gvm->priv); - - (* G_OBJECT_CLASS (gal_view_menus_parent_class)->finalize) (object); -} - -static void -gal_view_menus_class_init (GalViewMenusClass *gvm_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (gvm_class); - - object_class->finalize = gal_view_menus_finalize; -} - -static void -gal_view_menus_init (GalViewMenus *gvm) -{ - gvm->priv = g_new(GalViewMenusPrivate, 1); - gvm->priv->instance = NULL; - gvm->priv->collection_changed_id = 0; - gvm->priv->instance_changed_id = 0; - gvm->priv->component = NULL; - gvm->priv->listenerClosures = NULL; - gvm->priv->define_views_dialog = NULL; - gvm->priv->show_define_views = TRUE; -} - -GalViewMenus * -gal_view_menus_new (GalViewInstance *instance) -{ - GalViewMenus *gvm; - - g_return_val_if_fail (instance != NULL, NULL); - g_return_val_if_fail (GAL_IS_VIEW_INSTANCE (instance), NULL); - - gvm = g_object_new (GAL_VIEW_MENUS_TYPE, NULL); - gal_view_menus_construct(gvm, instance); - - return gvm; -} - -GalViewMenus * -gal_view_menus_construct (GalViewMenus *gvm, - GalViewInstance *instance) -{ - g_return_val_if_fail (gvm != NULL, NULL); - g_return_val_if_fail (GAL_IS_VIEW_MENUS (gvm), NULL); - g_return_val_if_fail (instance != NULL, NULL); - g_return_val_if_fail (GAL_IS_VIEW_INSTANCE (instance), NULL); - - add_instance (gvm, instance); - - return gvm; -} - -static void -dialog_response(GtkWidget *dialog, gint id, GalViewMenus *menus) -{ - if (id == GTK_RESPONSE_OK) { - gal_view_collection_save(menus->priv->instance->collection); - } - gtk_widget_destroy(dialog); -} - -static void -define_views(BonoboUIComponent *component, - GalViewMenus *menus, - gchar *cname) -{ - if (menus->priv->define_views_dialog) { - gdk_window_raise (menus->priv->define_views_dialog->window); - } else { - GtkWidget *dialog = gal_define_views_dialog_new(menus->priv->instance->collection); - - g_signal_connect (dialog, "response", G_CALLBACK (dialog_response), menus); - menus->priv->define_views_dialog = dialog; - g_object_weak_ref (G_OBJECT (dialog), clear_define_views_dialog, menus); - gtk_widget_show(dialog); - } -} - -static void -save_current_view(BonoboUIComponent *component, - GalViewMenus *menus, - gchar *cname) -{ - gal_view_instance_save_as (menus->priv->instance); -} - -static void -toggled_cb (BonoboUIComponent *component, - const gchar *path, - Bonobo_UIComponent_EventType type, - const gchar *state, - gpointer user_data) -{ - ListenerClosure *closure = user_data; - - /* do nothing on state change to untoggled */ - if (!strcmp (state, "0")) - return; - - g_print ("%s\n", path); - - gal_view_instance_set_current_view_id (closure->instance, closure->id); -} - -static gchar * -build_menus(GalViewMenus *menus) -{ - BonoboUINode *root, *menu, *submenu, *place, *menuitem, *commands, *command; - gchar *xml; - gint length; - gint i; - GalViewInstance *instance = menus->priv->instance; - GalViewCollection *collection = instance->collection; - gchar *id; - gboolean found = FALSE; - - root = bonobo_ui_node_new("Root"); - menu = bonobo_ui_node_new_child(root, "menu"); - commands = bonobo_ui_node_new_child (root, "commands"); - - submenu = bonobo_ui_node_new_child(menu, "submenu"); - bonobo_ui_node_set_attr(submenu, "name", "View"); - - place = bonobo_ui_node_new_child(submenu, "placeholder"); - bonobo_ui_node_set_attr(place, "name", "ViewBegin"); - - submenu = bonobo_ui_node_new_child(place, "submenu"); - bonobo_ui_node_set_attr(submenu, "name", "CurrentView"); - bonobo_ui_node_set_attr(submenu, "_label", N_("C_urrent View")); - - id = gal_view_instance_get_current_view_id (instance); - - length = gal_view_collection_get_count(collection); - - menus->priv->listenerClosures = e_list_new (closure_copy, closure_free, menus); - - for (i = 0; i < length; i++) { - GalViewCollectionItem *item = gal_view_collection_get_view_item(collection, i); - ListenerClosure *closure; - gchar *label; - gchar *tip; - - menuitem = bonobo_ui_node_new_child(submenu, "menuitem"); - bonobo_ui_node_set_attr(menuitem, "name", item->id); - bonobo_ui_node_set_attr(menuitem, "id", item->id); - bonobo_ui_node_set_attr(menuitem, "group", "GalViewMenus"); - bonobo_ui_node_set_attr(menuitem, "type", "radio"); - - command = bonobo_ui_node_new_child (commands, "cmd"); - bonobo_ui_node_set_attr(command, "name", item->id); - bonobo_ui_node_set_attr(command, "group", "GalViewMenus"); - tip = g_strdup_printf (_("Select View: %s"), item->id); - bonobo_ui_node_set_attr(command, "_tip", tip); - g_free (tip); - - label = bonobo_ui_util_encode_str (item->title); - bonobo_ui_node_set_attr(menuitem, "label", label); - g_free (label); - - closure = g_new (ListenerClosure, 1); - closure->instance = instance; - closure->id = item->id; - closure->ref_count = 1; - - if (!found && id && !strcmp (item->id, id)) { - found = TRUE; - } - - g_object_ref (closure->instance); - - bonobo_ui_component_add_listener (menus->priv->component, item->id, toggled_cb, closure); - e_list_append (menus->priv->listenerClosures, closure); - - closure_free (closure, menus); - } - - if (menus->priv->show_define_views) { - if (!found) { - - menuitem = bonobo_ui_node_new_child(submenu, "separator"); - bonobo_ui_node_set_attr(menuitem, "name", "GalView:first_sep"); - bonobo_ui_node_set_attr(menuitem, "f", ""); - - menuitem = bonobo_ui_node_new_child(submenu, "menuitem"); - bonobo_ui_node_set_attr(menuitem, "name", "custom_view"); - bonobo_ui_node_set_attr(menuitem, "id", "custom_view"); - bonobo_ui_node_set_attr(menuitem, "group", "GalViewMenus"); - bonobo_ui_node_set_attr(menuitem, "type", "radio"); - /* bonobo displays this string so it must be in locale */ - bonobo_ui_node_set_attr(menuitem, "_label", N_("Custom View")); - - command = bonobo_ui_node_new_child (commands, "cmd"); - bonobo_ui_node_set_attr(command, "name", "custom_view"); - bonobo_ui_node_set_attr(command, "group", "GalViewMenus"); - bonobo_ui_node_set_attr(command, "_tip", N_("Current view is a customized view")); - - menuitem = bonobo_ui_node_new_child(submenu, "menuitem"); - bonobo_ui_node_set_attr(menuitem, "name", "SaveCurrentView"); - bonobo_ui_node_set_attr(menuitem, "_label", N_("Save Custom View...")); - bonobo_ui_node_set_attr(menuitem, "verb", ""); - - command = bonobo_ui_node_new_child(commands, "cmd"); - bonobo_ui_node_set_attr(command, "name", "SaveCurrentView"); - bonobo_ui_node_set_attr(command, "_tip", N_("Save current custom view")); - } - - menuitem = bonobo_ui_node_new_child(submenu, "separator"); - bonobo_ui_node_set_attr(menuitem, "name", "GalView:second_sep"); - bonobo_ui_node_set_attr(menuitem, "f", ""); - - menuitem = bonobo_ui_node_new_child(submenu, "menuitem"); - bonobo_ui_node_set_attr(menuitem, "name", "DefineViews"); - bonobo_ui_node_set_attr(menuitem, "_label", N_("Define Views...")); - bonobo_ui_node_set_attr(menuitem, "verb", ""); - - command = bonobo_ui_node_new_child(commands, "cmd"); - bonobo_ui_node_set_attr(command, "name", "DefineViews"); - bonobo_ui_node_set_attr(command, "_tip", N_("Create or edit views")); - } - - xml = bonobo_ui_node_to_string(root, TRUE); - - bonobo_ui_node_free(root); - - g_free (id); - - /* d(g_print (xml));*/ - - return xml; -} - -static BonoboUIVerb verbs [] = { - BONOBO_UI_UNSAFE_VERB ("DefineViews", define_views), - BONOBO_UI_UNSAFE_VERB ("SaveCurrentView", save_current_view), - BONOBO_UI_VERB_END -}; - -static void -set_state (GalViewMenus *gvm, const gchar *path, CORBA_Environment *ev) -{ - gchar *full_path = g_strdup_printf ("/commands/%s", path); - - bonobo_ui_component_set_prop (gvm->priv->component, full_path, "state", "1", ev); - g_free (full_path); -} - -static void -set_radio (GalViewMenus *gvm, - CORBA_Environment *ev) -{ - gchar *id; - - id = gal_view_instance_get_current_view_id (gvm->priv->instance); - - if (id) { - set_state (gvm, id, ev); - } else { - set_state (gvm, "custom_view", ev); - } - g_free (id); -} - -static void -build_stuff (GalViewMenus *gvm, - CORBA_Environment *ev) -{ - gchar *xml; - - g_object_ref (gvm); - - gal_view_menus_unmerge (gvm, ev); - - remove_listeners(gvm); - remove_xml(gvm); - xml = build_menus(gvm); - bonobo_ui_component_set_translate(gvm->priv->component, "/", xml, ev); - g_free(xml); - - bonobo_ui_component_add_verb_list_with_data(gvm->priv->component, verbs, gvm); - - set_radio (gvm, ev); - - g_object_unref (gvm); -} - -void -gal_view_menus_set_show_define_views (GalViewMenus *gvm, - gboolean show_define_views) -{ - if (gvm->priv->show_define_views == show_define_views) - return; - - gvm->priv->show_define_views = show_define_views; - - if (gvm->priv->component) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - build_stuff(gvm, &ev); - CORBA_exception_free (&ev); - } -} - -void -gal_view_menus_apply (GalViewMenus *gvm, - BonoboUIComponent *component, - CORBA_Environment *opt_ev) -{ - if (gvm->priv == NULL) - return; - - if (component != gvm->priv->component) { - if (component) - bonobo_object_ref (BONOBO_OBJECT (component)); - - if (gvm->priv->component) - bonobo_object_unref (BONOBO_OBJECT (gvm->priv->component)); - } - - gvm->priv->component = component; - - build_stuff (gvm, opt_ev); -} - -void -gal_view_menus_unmerge (GalViewMenus *gvm, - CORBA_Environment *opt_ev) -{ - d(g_print ("%s:\n", G_STRFUNC)); - if (bonobo_ui_component_get_container (gvm->priv->component) != NULL - && bonobo_ui_component_path_exists (gvm->priv->component, CURRENT_VIEW_PATH, opt_ev)) { - d(g_print ("%s: Removing path\n", G_STRFUNC)); - bonobo_ui_component_rm (gvm->priv->component, CURRENT_VIEW_PATH, opt_ev); - } -} - -static void -collection_changed (GalViewCollection *collection, - GalViewMenus *gvm) -{ - CORBA_Environment ev; - - CORBA_exception_init (&ev); - build_stuff(gvm, &ev); - CORBA_exception_free (&ev); -} - -static void -instance_changed (GalViewInstance *instance, - GalViewMenus *gvm) -{ - CORBA_Environment ev; - - CORBA_exception_init (&ev); - build_stuff(gvm, &ev); - CORBA_exception_free (&ev); -} - -void -gal_view_menus_set_instance (GalViewMenus *gvm, - GalViewInstance *instance) -{ - remove_instance (gvm); - add_instance (gvm, instance); - instance_changed (instance, gvm); -} diff --git a/widgets/menus/gal-view-menus.h b/widgets/menus/gal-view-menus.h deleted file mode 100644 index f565d07613..0000000000 --- a/widgets/menus/gal-view-menus.h +++ /dev/null @@ -1,63 +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/> - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef _GAL_VIEW_MENUS_H_ -#define _GAL_VIEW_MENUS_H_ - -#include <libxml/tree.h> -#include <bonobo/bonobo-ui-component.h> -#include <widgets/menus/gal-view-instance.h> - -#include <glib-object.h> - -#define GAL_VIEW_MENUS_TYPE (gal_view_menus_get_type ()) -#define GAL_VIEW_MENUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GAL_VIEW_MENUS_TYPE, GalViewMenus)) -#define GAL_VIEW_MENUS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GAL_VIEW_MENUS_TYPE, GalViewMenusClass)) -#define GAL_IS_VIEW_MENUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GAL_VIEW_MENUS_TYPE)) -#define GAL_IS_VIEW_MENUS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GAL_VIEW_MENUS_TYPE)) - -typedef struct _GalViewMenusPrivate GalViewMenusPrivate; - -typedef struct { - GObject base; - GalViewMenusPrivate *priv; -} GalViewMenus; - -typedef struct { - GObjectClass parent_class; -} GalViewMenusClass; - -GType gal_view_menus_get_type (void); -GalViewMenus *gal_view_menus_new (GalViewInstance *instance); -GalViewMenus *gal_view_menus_construct (GalViewMenus *menus, - GalViewInstance *instance); - -void gal_view_menus_set_show_define_views (GalViewMenus *menus, - gboolean show_define_views); - -void gal_view_menus_apply (GalViewMenus *menus, - BonoboUIComponent *component, - CORBA_Environment *opt_ev); -void gal_view_menus_unmerge (GalViewMenus *gvm, - CORBA_Environment *opt_ev); -void gal_view_menus_set_instance (GalViewMenus *gvm, - GalViewInstance *instance); - -#endif /* _GAL_VIEW_MENUS_H_ */ diff --git a/widgets/menus/gal-view-new-dialog.c b/widgets/menus/gal-view-new-dialog.c index e2f62c7e99..da90fb024d 100644 --- a/widgets/menus/gal-view-new-dialog.c +++ b/widgets/menus/gal-view-new-dialog.c @@ -27,7 +27,7 @@ #include <glib/gi18n.h> #include "e-util/e-util.h" #include "e-util/e-util-private.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include "gal-define-views-model.h" #include "gal-view-new-dialog.h" diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am index d6689ef73f..ebd5562c30 100644 --- a/widgets/misc/Makefile.am +++ b/widgets/misc/Makefile.am @@ -4,7 +4,7 @@ endif AM_CPPFLAGS = \ -I$(top_srcdir) \ - -I$(top_srcdir)/a11y/widgets \ + -I$(top_srcdir)/filter \ -I$(top_srcdir)/widgets \ -DEVOLUTION_IMAGES=\""$(imagesdir)"\" \ -DEVOLUTION_GLADEDIR=\""$(gladedir)"\" \ @@ -13,8 +13,7 @@ AM_CPPFLAGS = \ $(GNOME_PLATFORM_CFLAGS) privsolib_LTLIBRARIES = \ - libemiscwidgets.la \ - libefilterbar.la + libemiscwidgets.la widgetsincludedir = $(privincludedir)/misc filterbarincludedir = $(privincludedir)/misc @@ -32,7 +31,12 @@ glade_DATA = e-send-options.glade widgetsinclude_HEADERS = \ $(pilot_headers) \ e-account-combo-box.h \ - e-activity-handler.h \ + e-account-manager.h \ + e-account-tree-view.h \ + e-action-combo-box.h \ + e-activity.h \ + e-activity-proxy.h \ + e-alert-activity.h \ e-attachment.h \ e-attachment-button.h \ e-attachment-dialog.h \ @@ -44,54 +48,58 @@ widgetsinclude_HEADERS = \ e-attachment-store.h \ e-attachment-tree-view.h \ e-attachment-view.h \ - e-spinner.c \ - e-spinner.h \ e-calendar.h \ e-calendar-item.h \ - e-cell-date-edit.h \ - e-cell-percent.h \ - e-cell-renderer-combo.h \ - e-charset-picker.h \ - e-combo-cell-editable.h \ - e-config-page.h \ - e-combo-button.h \ - e-dateedit.h \ - e-dropdown-button.h \ - e-icon-entry.h \ - e-image-chooser.h \ - e-info-label.h \ - e-map.h \ - e-multi-config-dialog.h \ - e-online-button.h \ - e-search-bar.h \ - e-task-bar.h \ - e-task-widget.h \ - e-send-options.h \ - e-url-entry.h \ + e-canvas.h \ e-canvas-background.h \ e-canvas-utils.h \ e-canvas-vbox.h \ - e-canvas.h \ + e-cell-renderer-combo.h \ + e-charset-combo-box.h \ + e-colors.h \ + e-combo-cell-editable.h \ e-cursors.h \ + e-dateedit.h \ e-gui-utils.h \ + e-hinted-entry.h \ e-hsv-utils.h \ + e-image-chooser.h \ + e-map.h \ + e-menu-tool-button.h \ + e-online-button.h \ + e-popup-action.h \ e-popup-menu.h \ + e-preferences-window.h \ e-printable.h \ - e-reflow-model.h \ - e-reflow.h \ + e-selection-model.h \ e-selection-model-array.h \ e-selection-model-simple.h \ - e-selection-model.h \ + e-send-options.h \ e-signature-combo-box.h \ - e-unicode.h \ - e-colors.h + e-signature-editor.h \ + e-signature-manager.h \ + e-signature-preview.h \ + e-signature-script-dialog.h \ + e-signature-tree-view.h \ + e-spinner.c \ + e-spinner.h \ + e-timeout-activity.h \ + e-url-entry.h \ + ea-calendar-cell.h \ + ea-calendar-item.h \ + ea-cell-table.h \ + ea-widgets.h libemiscwidgets_la_SOURCES = \ $(widgetsinclude_HEADERS) \ $(pilot_sources) \ e-account-combo-box.c \ - e-activity-handler.c \ - e-calendar.c \ + e-account-manager.c \ + e-account-tree-view.c \ + e-action-combo-box.c \ + e-activity.c \ + e-activity-proxy.c \ + e-alert-activity.c \ e-attachment.c \ e-attachment-button.c \ e-attachment-dialog.c \ @@ -103,78 +111,61 @@ libemiscwidgets_la_SOURCES = \ e-attachment-store.c \ e-attachment-tree-view.c \ e-attachment-view.c \ + e-calendar.c \ e-calendar-item.c \ - e-cell-date-edit.c \ - e-cell-percent.c \ - e-cell-renderer-combo.c \ - e-charset-picker.c \ - e-combo-cell-editable.c \ - e-config-page.c \ - e-combo-button.c \ - e-dateedit.c \ - e-dropdown-button.c \ - e-icon-entry.c \ - e-image-chooser.c \ - e-info-label.c \ - e-map.c \ - e-multi-config-dialog.c \ - e-online-button.c \ - e-search-bar.c \ - e-task-bar.c \ - e-task-widget.c \ - e-send-options.c \ - e-url-entry.c \ + e-canvas.c \ e-canvas-background.c \ e-canvas-utils.c \ e-canvas-vbox.c \ - e-canvas.c \ + e-cell-renderer-combo.c \ + e-charset-combo-box.c \ + e-colors.c \ + e-combo-cell-editable.c \ e-cursors.c \ + e-dateedit.c \ e-gui-utils.c \ + e-hinted-entry.c \ e-hsv-utils.c \ + e-image-chooser.c \ + e-map.c \ + e-menu-tool-button.c \ + e-online-button.c \ + e-popup-action.c \ e-popup-menu.c \ + e-preferences-window.c \ e-printable.c \ - e-reflow-model.c \ - e-reflow.c \ + e-selection-model.c \ e-selection-model-array.c \ e-selection-model-simple.c \ - e-selection-model.c \ + e-send-options.c \ e-signature-combo-box.c \ - e-unicode.c \ - e-colors.c - + e-signature-editor.c \ + e-signature-manager.c \ + e-signature-preview.c \ + e-signature-script-dialog.c \ + e-signature-tree-view.c \ + e-timeout-activity.c \ + e-url-entry.c \ + ea-calendar-cell.c \ + ea-calendar-item.c \ + ea-cell-table.c \ + ea-widgets.c libemiscwidgets_la_LDFLAGS = $(NO_UNDEFINED) -libemiscwidgets_la_LIBADD = $(top_builddir)/e-util/libeutil.la \ - $(top_builddir)/e-util/libeutil.la \ - $(top_builddir)/widgets/table/libetable.la \ - $(top_builddir)/widgets/text/libetext.la \ - $(top_builddir)/a11y/widgets/libevolution-widgets-a11y.la \ - $(top_builddir)/a11y/libevolution-a11y.la \ - $(EVOLUTION_MAIL_LIBS) \ - $(GNOME_PLATFORM_LIBS) \ - $(EVOLUTON_MAIL_LIBS) \ +libemiscwidgets_la_LIBADD = \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/filter/libfilter.la \ + $(top_builddir)/a11y/libevolution-a11y.la \ + $(EVOLUTION_MAIL_LIBS) \ + $(GNOME_PLATFORM_LIBS) \ + $(MATH_LIB) \ $(ICONV_LIBS) -filterbarinclude_HEADERS = e-filter-bar.h - -libefilterbar_la_SOURCES = \ - e-filter-bar.c \ - $(filterbarinclude_HEADERS) - -libefilterbar_la_LDFLAGS = $(NO_UNDEFINED) - -libefilterbar_la_LIBADD = \ - $(WIN32_BOOTSTRAP_LIBS) \ - libemiscwidgets.la \ - $(E_WIDGETS_LIBS) - noinst_PROGRAMS = \ test-calendar \ test-dateedit \ - test-dropdown-button \ - test-multi-config-dialog \ - test-info-label + test-preferences-window # test-calendar @@ -184,6 +175,7 @@ test_calendar_SOURCES = \ test_calendar_LDADD = \ libemiscwidgets.la \ $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/filter/libfilter.la \ $(E_WIDGETS_LIBS) # test-dateedit @@ -194,36 +186,18 @@ test_dateedit_SOURCES = \ test_dateedit_LDADD = \ libemiscwidgets.la \ $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/filter/libfilter.la \ $(E_WIDGETS_LIBS) -# test-dropdown-button - -test_dropdown_button_SOURCES = \ - test-dropdown-button.c - -test_dropdown_button_LDADD = \ - libemiscwidgets.la \ - $(top_builddir)/e-util/libeutil.la \ - $(E_WIDGETS_LIBS) - -# test-multi-config-dialog - -test_multi_config_dialog_SOURCES = \ - test-multi-config-dialog.c - -test_multi_config_dialog_LDADD = \ - libemiscwidgets.la \ - $(top_builddir)/e-util/libeutil.la \ - $(E_WIDGETS_LIBS) - -# test-info-label +# test-preferences-window -test_info_label_SOURCES = \ - test-info-label.c +test_preferences_window_SOURCES = \ + test-preferences-window.c -test_info_label_LDADD = \ +test_preferences_window_LDADD = \ libemiscwidgets.la \ $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/filter/libfilter.la \ $(E_WIDGETS_LIBS) diff --git a/widgets/misc/e-account-combo-box.c b/widgets/misc/e-account-combo-box.c index a0d02bcd80..0ded393e72 100644 --- a/widgets/misc/e-account-combo-box.c +++ b/widgets/misc/e-account-combo-box.c @@ -1,4 +1,5 @@ /* + * e-account-combo-box.c * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/widgets/misc/e-account-combo-box.h b/widgets/misc/e-account-combo-box.h index b163278dcd..12d4be6c72 100644 --- a/widgets/misc/e-account-combo-box.h +++ b/widgets/misc/e-account-combo-box.h @@ -1,4 +1,5 @@ /* + * e-account-combo-box.h * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/widgets/misc/e-account-manager.c b/widgets/misc/e-account-manager.c new file mode 100644 index 0000000000..8d3d2d211b --- /dev/null +++ b/widgets/misc/e-account-manager.c @@ -0,0 +1,454 @@ +/* + * e-account-manager.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-account-manager.h" + +#include <glib/gi18n.h> +#include <gdk/gdkkeysyms.h> +#include "e-util/e-binding.h" +#include "e-account-tree-view.h" + +#define E_ACCOUNT_MANAGER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_ACCOUNT_MANAGER, EAccountManagerPrivate)) + +struct _EAccountManagerPrivate { + EAccountList *account_list; + + GtkWidget *tree_view; + GtkWidget *add_button; + GtkWidget *edit_button; + GtkWidget *delete_button; + GtkWidget *default_button; +}; + +enum { + PROP_0, + PROP_ACCOUNT_LIST +}; + +enum { + ADD_ACCOUNT, + EDIT_ACCOUNT, + DELETE_ACCOUNT, + LAST_SIGNAL +}; + +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; + +static void +account_manager_default_clicked_cb (EAccountManager *manager) +{ + EAccountTreeView *tree_view; + EAccountList *account_list; + EAccount *account; + + tree_view = e_account_manager_get_tree_view (manager); + account_list = e_account_manager_get_account_list (manager); + account = e_account_tree_view_get_selected (tree_view); + g_return_if_fail (account != NULL); + + e_account_list_set_default (account_list, account); + + /* This signals the tree view to refresh. */ + e_account_list_change (account_list, account); +} + +static gboolean +account_manager_key_press_event_cb (EAccountManager *manager, + GdkEventKey *event) +{ + if (event->keyval == GDK_Delete) { + e_account_manager_delete_account (manager); + return TRUE; + } + + return FALSE; +} + +static void +account_manager_selection_changed_cb (EAccountManager *manager, + GtkTreeSelection *selection) +{ + EAccountTreeView *tree_view; + EAccountList *account_list; + EAccount *default_account; + EAccount *account; + GtkWidget *add_button; + GtkWidget *edit_button; + GtkWidget *delete_button; + GtkWidget *default_button; + gboolean sensitive; + + add_button = manager->priv->add_button; + edit_button = manager->priv->edit_button; + delete_button = manager->priv->delete_button; + default_button = manager->priv->default_button; + + tree_view = e_account_manager_get_tree_view (manager); + account = e_account_tree_view_get_selected (tree_view); + account_list = e_account_tree_view_get_account_list (tree_view); + + if (account == NULL) + gtk_widget_grab_focus (add_button); + + /* XXX EAccountList misuses const */ + default_account = (EAccount *) + e_account_list_get_default (account_list); + + sensitive = (account != NULL); + gtk_widget_set_sensitive (edit_button, sensitive); + + sensitive = (account != NULL); + gtk_widget_set_sensitive (delete_button, sensitive); + + sensitive = (account != NULL && account != default_account); + gtk_widget_set_sensitive (default_button, sensitive); +} + +static void +account_manager_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ACCOUNT_LIST: + e_account_manager_set_account_list ( + E_ACCOUNT_MANAGER (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +account_manager_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ACCOUNT_LIST: + g_value_set_object ( + value, + e_account_manager_get_account_list ( + E_ACCOUNT_MANAGER (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +account_manager_dispose (GObject *object) +{ + EAccountManagerPrivate *priv; + + priv = E_ACCOUNT_MANAGER_GET_PRIVATE (object); + + if (priv->account_list != NULL) { + g_object_unref (priv->account_list); + priv->account_list = NULL; + } + + if (priv->tree_view != NULL) { + g_object_unref (priv->tree_view); + priv->tree_view = NULL; + } + + if (priv->add_button != NULL) { + g_object_unref (priv->add_button); + priv->add_button = NULL; + } + + if (priv->edit_button != NULL) { + g_object_unref (priv->edit_button); + priv->edit_button = NULL; + } + + if (priv->delete_button != NULL) { + g_object_unref (priv->delete_button); + priv->delete_button = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +account_manager_class_init (EAccountManagerClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EAccountManagerPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = account_manager_set_property; + object_class->get_property = account_manager_get_property; + object_class->dispose = account_manager_dispose; + + /* XXX If we moved the account editor to /widgets/misc we + * could handle adding and editing accounts directly. */ + + g_object_class_install_property ( + object_class, + PROP_ACCOUNT_LIST, + g_param_spec_object ( + "account-list", + "Account List", + NULL, + E_TYPE_ACCOUNT_LIST, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + signals[ADD_ACCOUNT] = g_signal_new ( + "add-account", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EAccountManagerClass, add_account), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[EDIT_ACCOUNT] = g_signal_new ( + "edit-account", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EAccountManagerClass, edit_account), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[DELETE_ACCOUNT] = g_signal_new ( + "delete-account", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EAccountManagerClass, delete_account), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +account_manager_init (EAccountManager *manager) +{ + GtkTreeSelection *selection; + GtkWidget *container; + GtkWidget *widget; + + manager->priv = E_ACCOUNT_MANAGER_GET_PRIVATE (manager); + + gtk_table_resize (GTK_TABLE (manager), 1, 2); + gtk_table_set_col_spacings (GTK_TABLE (manager), 6); + gtk_table_set_row_spacings (GTK_TABLE (manager), 12); + + container = GTK_WIDGET (manager); + + 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_table_attach ( + GTK_TABLE (container), widget, 0, 1, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (widget); + + container = widget; + + widget = e_account_tree_view_new (); + gtk_container_add (GTK_CONTAINER (container), widget); + manager->priv->tree_view = g_object_ref (widget); + gtk_widget_show (widget); + + e_mutual_binding_new ( + G_OBJECT (manager), "account-list", + G_OBJECT (widget), "account-list"); + + g_signal_connect_swapped ( + widget, "key-press-event", + G_CALLBACK (account_manager_key_press_event_cb), + manager); + + g_signal_connect_swapped ( + widget, "row-activated", + G_CALLBACK (e_account_manager_edit_account), + manager); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + + g_signal_connect_swapped ( + selection, "changed", + G_CALLBACK (account_manager_selection_changed_cb), + manager); + + container = GTK_WIDGET (manager); + + widget = gtk_vbutton_box_new (); + gtk_button_box_set_layout ( + GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_START); + gtk_box_set_spacing (GTK_BOX (widget), 6); + gtk_table_attach ( + GTK_TABLE (container), widget, + 1, 2, 0, 2, 0, GTK_FILL, 0, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_button_new_from_stock (GTK_STOCK_ADD); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + manager->priv->add_button = g_object_ref (widget); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (e_account_manager_add_account), manager); + + widget = gtk_button_new_from_stock (GTK_STOCK_EDIT); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + manager->priv->edit_button = g_object_ref (widget); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (e_account_manager_edit_account), manager); + + widget = gtk_button_new_from_stock (GTK_STOCK_DELETE); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + manager->priv->delete_button = g_object_ref (widget); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (e_account_manager_delete_account), manager); + + widget = gtk_button_new_with_mnemonic (_("De_fault")); + gtk_button_set_image ( + GTK_BUTTON (widget), gtk_image_new_from_icon_name ( + "emblem-default", GTK_ICON_SIZE_BUTTON)); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + manager->priv->default_button = g_object_ref (widget); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (account_manager_default_clicked_cb), manager); +} + +GType +e_account_manager_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EAccountManagerClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) account_manager_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_init */ + sizeof (EAccountManager), + 0, /* n_preallocs */ + (GInstanceInitFunc) account_manager_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_TABLE, "EAccountManager", &type_info, 0); + } + + return type; +} + +GtkWidget * +e_account_manager_new (EAccountList *account_list) +{ + g_return_val_if_fail (E_IS_ACCOUNT_LIST (account_list), NULL); + + return g_object_new ( + E_TYPE_ACCOUNT_MANAGER, + "account-list", account_list, NULL); +} + +void +e_account_manager_add_account (EAccountManager *manager) +{ + g_return_if_fail (E_IS_ACCOUNT_MANAGER (manager)); + + g_signal_emit (manager, signals[ADD_ACCOUNT], 0); +} + +void +e_account_manager_edit_account (EAccountManager *manager) +{ + g_return_if_fail (E_IS_ACCOUNT_MANAGER (manager)); + + g_signal_emit (manager, signals[EDIT_ACCOUNT], 0); +} + +void +e_account_manager_delete_account (EAccountManager *manager) +{ + g_return_if_fail (E_IS_ACCOUNT_MANAGER (manager)); + + g_signal_emit (manager, signals[DELETE_ACCOUNT], 0); +} + +EAccountList * +e_account_manager_get_account_list (EAccountManager *manager) +{ + g_return_val_if_fail (E_IS_ACCOUNT_MANAGER (manager), NULL); + + return manager->priv->account_list; +} + +void +e_account_manager_set_account_list (EAccountManager *manager, + EAccountList *account_list) +{ + g_return_if_fail (E_IS_ACCOUNT_MANAGER (manager)); + + if (account_list != NULL) { + g_return_if_fail (E_IS_ACCOUNT_LIST (account_list)); + g_object_ref (account_list); + } + + if (manager->priv->account_list != NULL) + g_object_unref (manager->priv->account_list); + + manager->priv->account_list = account_list; + + g_object_notify (G_OBJECT (manager), "account-list"); +} + +EAccountTreeView * +e_account_manager_get_tree_view (EAccountManager *manager) +{ + g_return_val_if_fail (E_IS_ACCOUNT_MANAGER (manager), NULL); + + return E_ACCOUNT_TREE_VIEW (manager->priv->tree_view); +} diff --git a/widgets/misc/e-account-manager.h b/widgets/misc/e-account-manager.h new file mode 100644 index 0000000000..dab8b2832f --- /dev/null +++ b/widgets/misc/e-account-manager.h @@ -0,0 +1,82 @@ +/* + * e-account-manager.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_ACCOUNT_MANAGER_H +#define E_ACCOUNT_MANAGER_H + +#include <gtk/gtk.h> +#include <libedataserver/e-account-list.h> +#include <misc/e-account-tree-view.h> + +/* Standard GObject macros */ +#define E_TYPE_ACCOUNT_MANAGER \ + (e_account_manager_get_type ()) +#define E_ACCOUNT_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_ACCOUNT_MANAGER, EAccountManager)) +#define E_ACCOUNT_MANAGER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_ACCOUNT_MANAGER, EAccountManagerClass)) +#define E_IS_ACCOUNT_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_ACCOUNT_MANAGER)) +#define E_IS_ACCOUNT_MANAGER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_ACCOUNT_MANAGER)) +#define E_ACCOUNT_MANAGER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_ACCOUNT_MANAGER, EAccountManagerClass)) + +G_BEGIN_DECLS + +typedef struct _EAccountManager EAccountManager; +typedef struct _EAccountManagerClass EAccountManagerClass; +typedef struct _EAccountManagerPrivate EAccountManagerPrivate; + +struct _EAccountManager { + GtkTable parent; + EAccountManagerPrivate *priv; +}; + +struct _EAccountManagerClass { + GtkTableClass parent_class; + + void (*add_account) (EAccountManager *manager); + void (*edit_account) (EAccountManager *manager); + void (*delete_account) (EAccountManager *manager); +}; + +GType e_account_manager_get_type (void); +GtkWidget * e_account_manager_new (EAccountList *account_list); +void e_account_manager_add_account (EAccountManager *manager); +void e_account_manager_edit_account (EAccountManager *manager); +void e_account_manager_delete_account(EAccountManager *manager); +EAccountList * e_account_manager_get_account_list + (EAccountManager *manager); +void e_account_manager_set_account_list + (EAccountManager *manager, + EAccountList *account_list); +EAccountTreeView * + e_account_manager_get_tree_view (EAccountManager *manager); + +G_END_DECLS + +#endif /* E_ACCOUNT_MANAGER_H */ diff --git a/widgets/misc/e-account-tree-view.c b/widgets/misc/e-account-tree-view.c new file mode 100644 index 0000000000..8e57dfcf66 --- /dev/null +++ b/widgets/misc/e-account-tree-view.c @@ -0,0 +1,632 @@ +/* + * e-account-tree-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-account-tree-view.h" + +#include <glib/gi18n.h> +#include <camel/camel-url.h> + +#define E_ACCOUNT_TREE_VIEW_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_ACCOUNT_TREE_VIEW, EAccountTreeViewPrivate)) + +enum { + COLUMN_ACCOUNT, + COLUMN_DEFAULT, + COLUMN_ENABLED, + COLUMN_NAME, + COLUMN_PROTOCOL +}; + +enum { + PROP_0, + PROP_ACCOUNT_LIST, + PROP_SELECTED +}; + +enum { + ENABLE_ACCOUNT, + DISABLE_ACCOUNT, + REFRESHED, + LAST_SIGNAL +}; + +struct _EAccountTreeViewPrivate { + EAccountList *account_list; + GHashTable *index; +}; + +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; + +static void +account_tree_view_refresh_cb (EAccountList *account_list, + EAccount *account, + EAccountTreeView *tree_view) +{ + GtkListStore *store; + GtkTreeModel *model; + GtkTreeIter tree_iter; + EIterator *account_iter; + EAccount *default_account; + GHashTable *index; + GList *list = NULL; + GList *iter; + + store = gtk_list_store_new ( + 5, E_TYPE_ACCOUNT, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_STRING, G_TYPE_STRING); + model = GTK_TREE_MODEL (store); + index = tree_view->priv->index; + + g_hash_table_remove_all (index); + + if (account_list == NULL) + goto skip; + + /* XXX EAccountList misuses const. */ + default_account = (EAccount *) + e_account_list_get_default (account_list); + + /* Build a list of EAccounts to display. */ + account_iter = e_list_get_iterator (E_LIST (account_list)); + while (e_iterator_is_valid (account_iter)) { + + /* XXX EIterator misuses const. */ + account = (EAccount *) e_iterator_get (account_iter); + list = g_list_prepend (list, account); + e_iterator_next (account_iter); + } + g_object_unref (account_iter); + + list = g_list_reverse (list); + + /* Populate the list store and index. */ + for (iter = list; iter != NULL; iter = iter->next) { + GtkTreeRowReference *reference; + GtkTreePath *path; + CamelURL *url = NULL; + gboolean is_default; + const gchar *protocol; + + account = iter->data; + + /* Skip proxy accounts. */ + if (account->parent_uid != NULL) + continue; + + is_default = (account == default_account); + + if (account->source != NULL && account->source->url != NULL) + url = camel_url_new (account->source->url, NULL); + + if (url != NULL && url->protocol != NULL) + protocol = url->protocol; + else + protocol = _("None"); + + gtk_list_store_append (store, &tree_iter); + gtk_list_store_set ( + store, &tree_iter, + COLUMN_ACCOUNT, account, + COLUMN_DEFAULT, is_default, + COLUMN_ENABLED, account->enabled, + COLUMN_NAME, account->name, + COLUMN_PROTOCOL, protocol, -1); + + path = gtk_tree_model_get_path (model, &tree_iter); + reference = gtk_tree_row_reference_new (model, path); + g_hash_table_insert (index, account, reference); + gtk_tree_path_free (path); + + if (url != NULL) + camel_url_free (url); + } + +skip: + /* Restore the previously selected account. */ + account = e_account_tree_view_get_selected (tree_view); + if (account != NULL) + g_object_ref (account); + gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model); + e_account_tree_view_set_selected (tree_view, account); + if (account != NULL) + g_object_unref (account); + + g_signal_emit (tree_view, signals[REFRESHED], 0); +} + +static void +account_tree_view_enabled_toggled_cb (EAccountTreeView *tree_view, + gchar *path_string, + GtkCellRendererToggle *renderer) +{ + GtkTreeSelection *selection; + GtkTreePath *path; + + /* Change the selection first so we enable or disable the + * correct account. */ + path = gtk_tree_path_new_from_string (path_string); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); + gtk_tree_selection_select_path (selection, path); + gtk_tree_path_free (path); + + if (gtk_cell_renderer_toggle_get_active (renderer)) + e_account_tree_view_disable_account (tree_view); + else + e_account_tree_view_enable_account (tree_view); +} + +static void +account_tree_view_selection_changed_cb (EAccountTreeView *tree_view) +{ + g_object_notify (G_OBJECT (tree_view), "selected"); +} + +static GObject * +account_tree_view_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *object; + GtkTreeView *tree_view; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + + /* Chain up to parent's constructor() method. */ + object = G_OBJECT_CLASS (parent_class)->constructor ( + type, n_construct_properties, construct_properties); + + tree_view = GTK_TREE_VIEW (object); + gtk_tree_view_set_headers_visible (tree_view, TRUE); + + /* Column: Enabled */ + + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_column_set_title (column, _("Enabled")); + + renderer = gtk_cell_renderer_toggle_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + + g_signal_connect_swapped ( + renderer, "toggled", + G_CALLBACK (account_tree_view_enabled_toggled_cb), + tree_view); + + gtk_tree_view_column_add_attribute ( + column, renderer, "active", COLUMN_ENABLED); + + gtk_tree_view_append_column (tree_view, column); + + /* Column: Account Name */ + + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_column_set_title (column, _("Account Name")); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + + gtk_tree_view_column_add_attribute ( + column, renderer, "text", COLUMN_NAME); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, "text", _("Default"), NULL); + gtk_tree_view_column_pack_end (column, renderer, FALSE); + + gtk_tree_view_column_add_attribute ( + column, renderer, "visible", COLUMN_DEFAULT); + + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set ( + renderer, "icon-name", "emblem-default", + "stock-size", GTK_ICON_SIZE_MENU, NULL); + gtk_tree_view_column_pack_end (column, renderer, FALSE); + + gtk_tree_view_column_add_attribute ( + column, renderer, "visible", COLUMN_DEFAULT); + + gtk_tree_view_append_column (tree_view, column); + + /* Column: Protocol */ + + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_column_set_title (column, _("Protocol")); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + + gtk_tree_view_column_add_attribute ( + column, renderer, "text", COLUMN_PROTOCOL); + + gtk_tree_view_append_column (tree_view, column); + + return object; +} + +static void +account_tree_view_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ACCOUNT_LIST: + e_account_tree_view_set_account_list ( + E_ACCOUNT_TREE_VIEW (object), + g_value_get_object (value)); + return; + + case PROP_SELECTED: + e_account_tree_view_set_selected ( + E_ACCOUNT_TREE_VIEW (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +account_tree_view_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ACCOUNT_LIST: + g_value_set_object ( + value, + e_account_tree_view_get_account_list ( + E_ACCOUNT_TREE_VIEW (object))); + return; + + case PROP_SELECTED: + g_value_set_object ( + value, + e_account_tree_view_get_selected ( + E_ACCOUNT_TREE_VIEW (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +account_tree_view_dispose (GObject *object) +{ + EAccountTreeViewPrivate *priv; + + priv = E_ACCOUNT_TREE_VIEW_GET_PRIVATE (object); + + if (priv->account_list != NULL) { + g_signal_handlers_disconnect_by_func ( + priv->account_list, + account_tree_view_refresh_cb, object); + g_object_unref (priv->account_list); + priv->account_list = NULL; + } + + g_hash_table_remove_all (priv->index); + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +account_tree_view_finalize (GObject *object) +{ + EAccountTreeViewPrivate *priv; + + priv = E_ACCOUNT_TREE_VIEW_GET_PRIVATE (object); + + g_hash_table_destroy (priv->index); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +account_tree_view_enable_account (EAccountTreeView *tree_view) +{ + EAccountList *account_list; + EAccount *account; + + account = e_account_tree_view_get_selected (tree_view); + if (account == NULL || account->enabled) + return; + + account_list = e_account_tree_view_get_account_list (tree_view); + g_return_if_fail (account_list != NULL); + + account->enabled = TRUE; + e_account_list_change (account_list, account); + + e_account_list_save (account_list); +} + +static void +account_tree_view_disable_account (EAccountTreeView *tree_view) +{ + EAccountList *account_list; + EAccount *account; + + account = e_account_tree_view_get_selected (tree_view); + if (account == NULL || !account->enabled) + return; + + account_list = e_account_tree_view_get_account_list (tree_view); + g_return_if_fail (account_list != NULL); + + account->enabled = FALSE; + e_account_list_change (account_list, account); + + e_account_list_save (account_list); +} + +static void +account_tree_view_class_init (EAccountTreeViewClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EAccountTreeViewPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->constructor = account_tree_view_constructor; + object_class->set_property = account_tree_view_set_property; + object_class->get_property = account_tree_view_get_property; + object_class->dispose = account_tree_view_dispose; + object_class->finalize = account_tree_view_finalize; + + class->enable_account = account_tree_view_enable_account; + class->disable_account = account_tree_view_disable_account; + + g_object_class_install_property ( + object_class, + PROP_SELECTED, + g_param_spec_object ( + "selected", + "Selected Account", + NULL, + E_TYPE_ACCOUNT, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_ACCOUNT_LIST, + g_param_spec_object ( + "account-list", + "Account List", + NULL, + E_TYPE_ACCOUNT_LIST, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + signals[ENABLE_ACCOUNT] = g_signal_new ( + "enable-account", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EAccountTreeViewClass, enable_account), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[DISABLE_ACCOUNT] = g_signal_new ( + "disable-account", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EAccountTreeViewClass, disable_account), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[REFRESHED] = g_signal_new ( + "refreshed", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EAccountTreeViewClass, refreshed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +account_tree_view_init (EAccountTreeView *tree_view) +{ + GHashTable *index; + GtkTreeSelection *selection; + + /* Reverse-lookup index */ + index = g_hash_table_new_full ( + g_direct_hash, g_direct_equal, + (GDestroyNotify) g_object_unref, + (GDestroyNotify) gtk_tree_row_reference_free); + + tree_view->priv = E_ACCOUNT_TREE_VIEW_GET_PRIVATE (tree_view); + tree_view->priv->index = index; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); + + g_signal_connect_swapped ( + selection, "changed", + G_CALLBACK (account_tree_view_selection_changed_cb), + tree_view); +} + +GType +e_account_tree_view_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EAccountTreeViewClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) account_tree_view_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EAccountTreeView), + 0, /* n_preallocs */ + (GInstanceInitFunc) account_tree_view_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_TREE_VIEW, "EAccountTreeView", + &type_info, 0); + } + + return type; +} + +GtkWidget * +e_account_tree_view_new (void) +{ + return g_object_new (E_TYPE_ACCOUNT_TREE_VIEW, NULL); +} + +void +e_account_tree_view_enable_account (EAccountTreeView *tree_view) +{ + g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view)); + + g_signal_emit (tree_view, signals[ENABLE_ACCOUNT], 0); +} + +void +e_account_tree_view_disable_account (EAccountTreeView *tree_view) +{ + g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view)); + + g_signal_emit (tree_view, signals[DISABLE_ACCOUNT], 0); +} + +EAccountList * +e_account_tree_view_get_account_list (EAccountTreeView *tree_view) +{ + g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), NULL); + + return tree_view->priv->account_list; +} + +void +e_account_tree_view_set_account_list (EAccountTreeView *tree_view, + EAccountList *account_list) +{ + EAccountTreeViewPrivate *priv; + + g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view)); + + if (account_list != NULL) + g_return_if_fail (E_IS_ACCOUNT_LIST (account_list)); + + priv = E_ACCOUNT_TREE_VIEW_GET_PRIVATE (tree_view); + + if (priv->account_list != NULL) { + g_signal_handlers_disconnect_by_func ( + priv->account_list, + account_tree_view_refresh_cb, tree_view); + g_object_unref (priv->account_list); + priv->account_list = NULL; + } + + if (account_list != NULL) { + priv->account_list = g_object_ref (account_list); + + /* Listen for changes to the account list. */ + g_signal_connect ( + priv->account_list, "account-added", + G_CALLBACK (account_tree_view_refresh_cb), + tree_view); + g_signal_connect ( + priv->account_list, "account-changed", + G_CALLBACK (account_tree_view_refresh_cb), + tree_view); + g_signal_connect ( + priv->account_list, "account-removed", + G_CALLBACK (account_tree_view_refresh_cb), + tree_view); + } + + account_tree_view_refresh_cb (account_list, NULL, tree_view); + + g_object_notify (G_OBJECT (tree_view), "account-list"); +} + +EAccount * +e_account_tree_view_get_selected (EAccountTreeView *tree_view) +{ + EAccount *account; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + + g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return NULL; + + gtk_tree_model_get (model, &iter, COLUMN_ACCOUNT, &account, -1); + + return account; +} + +gboolean +e_account_tree_view_set_selected (EAccountTreeView *tree_view, + EAccount *account) +{ + GtkTreeRowReference *reference; + GtkTreeSelection *selection; + GtkTreePath *path; + + g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), FALSE); + + if (account != NULL) + g_return_val_if_fail (E_IS_ACCOUNT (account), FALSE); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); + + /* NULL means clear the selection. */ + if (account == NULL) { + gtk_tree_selection_unselect_all (selection); + return TRUE; + } + + /* Lookup the tree row reference for the account. */ + reference = g_hash_table_lookup (tree_view->priv->index, account); + if (reference == NULL) + return FALSE; + + /* Select the referenced path. */ + path = gtk_tree_row_reference_get_path (reference); + gtk_tree_selection_select_path (selection, path); + gtk_tree_path_free (path); + + g_object_notify (G_OBJECT (tree_view), "selected"); + + return TRUE; +} diff --git a/widgets/misc/e-account-tree-view.h b/widgets/misc/e-account-tree-view.h new file mode 100644 index 0000000000..ea13dc3902 --- /dev/null +++ b/widgets/misc/e-account-tree-view.h @@ -0,0 +1,84 @@ +/* + * e-account-tree-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_ACCOUNT_TREE_VIEW_H +#define E_ACCOUNT_TREE_VIEW_H + +#include <gtk/gtk.h> +#include <libedataserver/e-account.h> +#include <libedataserver/e-account-list.h> + +/* Standard GObject macros */ +#define E_TYPE_ACCOUNT_TREE_VIEW \ + (e_account_tree_view_get_type ()) +#define E_ACCOUNT_TREE_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_ACCOUNT_TREE_VIEW, EAccountTreeView)) +#define E_ACCOUNT_TREE_VIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_ACCOUNT_TREE_VIEW, EAccountTreeViewClass)) +#define E_IS_ACCOUNT_TREE_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_ACCOUNT_TREE_VIEW)) +#define E_IS_ACCOUNT_TREE_VIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_ACCOUNT_TREE_VIEW)) +#define E_ACCOUNT_TREE_VIEW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_ACCOUNT_TREE_VIEW, EAccountTreeViewClass)) + +G_BEGIN_DECLS + +typedef struct _EAccountTreeView EAccountTreeView; +typedef struct _EAccountTreeViewClass EAccountTreeViewClass; +typedef struct _EAccountTreeViewPrivate EAccountTreeViewPrivate; + +struct _EAccountTreeView { + GtkTreeView parent; + EAccountTreeViewPrivate *priv; +}; + +struct _EAccountTreeViewClass { + GtkTreeViewClass parent_class; + + void (*enable_account) (EAccountTreeView *tree_view); + void (*disable_account) (EAccountTreeView *tree_view); + void (*refreshed) (EAccountTreeView *tree_view); +}; + +GType e_account_tree_view_get_type (void); +GtkWidget * e_account_tree_view_new (void); +void e_account_tree_view_enable_account + (EAccountTreeView *tree_view); +void e_account_tree_view_disable_account + (EAccountTreeView *tree_view); +EAccountList * e_account_tree_view_get_account_list + (EAccountTreeView *tree_view); +void e_account_tree_view_set_account_list + (EAccountTreeView *tree_view, + EAccountList *account_list); +EAccount * e_account_tree_view_get_selected(EAccountTreeView *tree_view); +gboolean e_account_tree_view_set_selected(EAccountTreeView *tree_view, + EAccount *account); + +G_END_DECLS + +#endif /* E_ACCOUNT_TREE_VIEW_H */ diff --git a/widgets/misc/e-action-combo-box.c b/widgets/misc/e-action-combo-box.c new file mode 100644 index 0000000000..e8a9be51ed --- /dev/null +++ b/widgets/misc/e-action-combo-box.c @@ -0,0 +1,582 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-action-combo-box.c + * + * Copyright (C) 2008 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU Lesser 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 Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "e-action-combo-box.h" + +#include <glib/gi18n.h> + +#define E_ACTION_COMBO_BOX_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_ACTION_COMBO_BOX, EActionComboBoxPrivate)) + +enum { + COLUMN_ACTION, + COLUMN_SORT +}; + +enum { + PROP_0, + PROP_ACTION +}; + +struct _EActionComboBoxPrivate { + GtkRadioAction *action; + GtkActionGroup *action_group; + GHashTable *index; + guint changed_handler_id; /* action::changed */ + guint group_sensitive_handler_id; /* action-group::sensitive */ + guint group_visible_handler_id; /* action-group::visible */ + gboolean group_has_icons : 1; +}; + +static gpointer parent_class; + +static void +action_combo_box_action_changed_cb (GtkRadioAction *action, + GtkRadioAction *current, + EActionComboBox *combo_box) +{ + GtkTreeRowReference *reference; + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + gboolean valid; + + reference = g_hash_table_lookup ( + combo_box->priv->index, GINT_TO_POINTER ( + gtk_radio_action_get_current_value (current))); + g_return_if_fail (reference != NULL); + + model = gtk_tree_row_reference_get_model (reference); + path = gtk_tree_row_reference_get_path (reference); + valid = gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_path_free (path); + g_return_if_fail (valid); + + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter); +} + +static void +action_combo_box_action_group_notify_cb (GtkActionGroup *action_group, + GParamSpec *pspec, + EActionComboBox *combo_box) +{ + g_object_set ( + combo_box, "sensitive", + gtk_action_group_get_sensitive (action_group), "visible", + gtk_action_group_get_visible (action_group), NULL); +} + +static void +action_combo_box_render_pixbuf (GtkCellLayout *layout, + GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + EActionComboBox *combo_box) +{ + GtkRadioAction *action; + gchar *icon_name; + gchar *stock_id; + gboolean sensitive; + gboolean visible; + gint width; + + gtk_tree_model_get (model, iter, COLUMN_ACTION, &action, -1); + + /* Do any of the actions have an icon? */ + if (!combo_box->priv->group_has_icons) + return; + + /* A NULL action means the row is a separator. */ + if (action == NULL) + return; + + g_object_get ( + G_OBJECT (action), + "icon-name", &icon_name, + "sensitive", &sensitive, + "stock-id", &stock_id, + "visible", &visible, + NULL); + + /* Keep the pixbuf renderer a fixed size for proper alignment. */ + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, NULL); + + /* We can't set both "icon-name" and "stock-id" because setting + * one unsets the other. So pick the one that has a non-NULL + * value. If both are non-NULL, "stock-id" wins. */ + + if (stock_id != NULL) + g_object_set ( + G_OBJECT (renderer), + "sensitive", sensitive, + "stock-id", stock_id, + "stock-size", GTK_ICON_SIZE_MENU, + "visible", visible, + "width", width, + NULL); + else + g_object_set ( + G_OBJECT (renderer), + "icon-name", icon_name, + "sensitive", sensitive, + "stock-size", GTK_ICON_SIZE_MENU, + "visible", visible, + "width", width, + NULL); + + g_free (icon_name); + g_free (stock_id); +} + +static void +action_combo_box_render_text (GtkCellLayout *layout, + GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + EActionComboBox *combo_box) +{ + GtkRadioAction *action; + gchar **strv; + gchar *label; + gboolean sensitive; + gboolean visible; + gint xpad; + + gtk_tree_model_get (model, iter, COLUMN_ACTION, &action, -1); + + /* A NULL action means the row is a separator. */ + if (action == NULL) + return; + + g_object_get ( + G_OBJECT (action), + "label", &label, + "sensitive", &sensitive, + "visible", &visible, + NULL); + + /* Strip out underscores. */ + strv = g_strsplit (label, "_", -1); + g_free (label); + label = g_strjoinv (NULL, strv); + g_strfreev (strv); + + xpad = combo_box->priv->group_has_icons ? 3 : 0; + + g_object_set ( + G_OBJECT (renderer), + "sensitive", sensitive, + "text", label, + "visible", visible, + "xpad", xpad, + NULL); + + g_free (label); +} + +static gboolean +action_combo_box_is_row_separator (GtkTreeModel *model, + GtkTreeIter *iter) +{ + GtkAction *action; + gboolean separator; + + /* NULL actions are rendered as separators. */ + gtk_tree_model_get (model, iter, COLUMN_ACTION, &action, -1); + separator = (action == NULL); + if (action != NULL) + g_object_unref (action); + + return separator; +} + +static void +action_combo_box_update_model (EActionComboBox *combo_box) +{ + GtkListStore *list_store; + GSList *list; + + g_hash_table_remove_all (combo_box->priv->index); + + if (combo_box->priv->action == NULL) { + gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), NULL); + return; + } + + /* We store values in the sort column as floats so that we can + * insert separators in between consecutive integer values and + * still maintain the proper ordering. */ + list_store = gtk_list_store_new ( + 2, GTK_TYPE_RADIO_ACTION, G_TYPE_FLOAT); + + list = gtk_radio_action_get_group (combo_box->priv->action); + combo_box->priv->group_has_icons = FALSE; + + while (list != NULL) { + GtkTreeRowReference *reference; + GtkRadioAction *action = list->data; + GtkTreePath *path; + GtkTreeIter iter; + gchar *icon_name; + gchar *stock_id; + gint value; + + g_object_get ( + action, "icon-name", &icon_name, + "stock-id", &stock_id, NULL); + combo_box->priv->group_has_icons |= + (icon_name != NULL || stock_id != NULL); + g_free (icon_name); + g_free (stock_id); + + gtk_list_store_append (list_store, &iter); + g_object_get (G_OBJECT (action), "value", &value, NULL); + gtk_list_store_set ( + list_store, &iter, COLUMN_ACTION, + list->data, COLUMN_SORT, (gfloat) value, -1); + + path = gtk_tree_model_get_path ( + GTK_TREE_MODEL (list_store), &iter); + reference = gtk_tree_row_reference_new ( + GTK_TREE_MODEL (list_store), path); + g_hash_table_insert ( + combo_box->priv->index, + GINT_TO_POINTER (value), reference); + gtk_tree_path_free (path); + + list = g_slist_next (list); + } + + gtk_tree_sortable_set_sort_column_id ( + GTK_TREE_SORTABLE (list_store), + COLUMN_SORT, GTK_SORT_ASCENDING); + gtk_combo_box_set_model ( + GTK_COMBO_BOX (combo_box), GTK_TREE_MODEL (list_store)); + + action_combo_box_action_changed_cb ( + combo_box->priv->action, + combo_box->priv->action, + combo_box); +} + +static void +action_combo_box_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ACTION: + e_action_combo_box_set_action ( + E_ACTION_COMBO_BOX (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +action_combo_box_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ACTION: + g_value_set_object ( + value, e_action_combo_box_get_action ( + E_ACTION_COMBO_BOX (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +action_combo_box_dispose (GObject *object) +{ + EActionComboBoxPrivate *priv = E_ACTION_COMBO_BOX_GET_PRIVATE (object); + + if (priv->action != NULL) { + g_object_unref (priv->action); + priv->action = NULL; + } + + if (priv->action_group != NULL) { + g_object_unref (priv->action_group); + priv->action_group = NULL; + } + + g_hash_table_remove_all (priv->index); + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +action_combo_box_finalize (GObject *object) +{ + EActionComboBoxPrivate *priv = E_ACTION_COMBO_BOX_GET_PRIVATE (object); + + g_hash_table_destroy (priv->index); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +action_combo_box_changed (GtkComboBox *combo_box) +{ + GtkRadioAction *action; + GtkTreeModel *model; + GtkTreeIter iter; + gint value; + + /* This method is virtual, so no need to chain up. */ + + if (!gtk_combo_box_get_active_iter (combo_box, &iter)) + return; + + model = gtk_combo_box_get_model (combo_box); + gtk_tree_model_get (model, &iter, COLUMN_ACTION, &action, -1); + g_object_get (G_OBJECT (action), "value", &value, NULL); + gtk_radio_action_set_current_value (action, value); +} + +static void +action_combo_box_class_init (EActionComboBoxClass *class) +{ + GObjectClass *object_class; + GtkComboBoxClass *combo_box_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EActionComboBoxPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = action_combo_box_set_property; + object_class->get_property = action_combo_box_get_property; + object_class->dispose = action_combo_box_dispose; + object_class->finalize = action_combo_box_finalize; + + combo_box_class = GTK_COMBO_BOX_CLASS (class); + combo_box_class->changed = action_combo_box_changed; + + g_object_class_install_property ( + object_class, + PROP_ACTION, + g_param_spec_object ( + "action", + _("Action"), + _("A GtkRadioAction"), + GTK_TYPE_RADIO_ACTION, + G_PARAM_READWRITE)); +} + +static void +action_combo_box_init (EActionComboBox *combo_box) +{ + GtkCellRenderer *renderer; + + combo_box->priv = E_ACTION_COMBO_BOX_GET_PRIVATE (combo_box); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start ( + GTK_CELL_LAYOUT (combo_box), renderer, FALSE); + gtk_cell_layout_set_cell_data_func ( + GTK_CELL_LAYOUT (combo_box), renderer, + (GtkCellLayoutDataFunc) action_combo_box_render_pixbuf, + combo_box, NULL); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start ( + GTK_CELL_LAYOUT (combo_box), renderer, TRUE); + gtk_cell_layout_set_cell_data_func ( + GTK_CELL_LAYOUT (combo_box), renderer, + (GtkCellLayoutDataFunc) action_combo_box_render_text, + combo_box, NULL); + + gtk_combo_box_set_row_separator_func ( + GTK_COMBO_BOX (combo_box), (GtkTreeViewRowSeparatorFunc) + action_combo_box_is_row_separator, NULL, NULL); + + combo_box->priv->index = g_hash_table_new_full ( + g_direct_hash, g_direct_equal, + (GDestroyNotify) NULL, + (GDestroyNotify) gtk_tree_row_reference_free); +} + +GType +e_action_combo_box_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EActionComboBoxClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) action_combo_box_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EActionComboBox), + 0, /* n_preallocs */ + (GInstanceInitFunc) action_combo_box_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_COMBO_BOX, "EActionComboBox", + &type_info, 0); + } + + return type; +} + +GtkWidget * +e_action_combo_box_new (void) +{ + return e_action_combo_box_new_with_action (NULL); +} + +GtkWidget * +e_action_combo_box_new_with_action (GtkRadioAction *action) +{ + return g_object_new (E_TYPE_ACTION_COMBO_BOX, "action", action, NULL); +} + +GtkRadioAction * +e_action_combo_box_get_action (EActionComboBox *combo_box) +{ + g_return_val_if_fail (E_ACTION_IS_COMBO_BOX (combo_box), NULL); + + return combo_box->priv->action; +} + +void +e_action_combo_box_set_action (EActionComboBox *combo_box, + GtkRadioAction *action) +{ + g_return_if_fail (E_ACTION_IS_COMBO_BOX (combo_box)); + + if (action != NULL) + g_return_if_fail (GTK_IS_RADIO_ACTION (action)); + + if (combo_box->priv->action != NULL) { + g_signal_handler_disconnect ( + combo_box->priv->action, + combo_box->priv->changed_handler_id); + g_object_unref (combo_box->priv->action); + } + + if (combo_box->priv->action_group != NULL) { + g_signal_handler_disconnect ( + combo_box->priv->action_group, + combo_box->priv->group_sensitive_handler_id); + g_signal_handler_disconnect ( + combo_box->priv->action_group, + combo_box->priv->group_visible_handler_id); + g_object_unref (combo_box->priv->action_group); + combo_box->priv->action_group = NULL; + } + + if (action != NULL) + g_object_get ( + g_object_ref (action), "action-group", + &combo_box->priv->action_group, NULL); + combo_box->priv->action = action; + action_combo_box_update_model (combo_box); + + if (combo_box->priv->action != NULL) + combo_box->priv->changed_handler_id = g_signal_connect ( + combo_box->priv->action, "changed", + G_CALLBACK (action_combo_box_action_changed_cb), + combo_box); + + if (combo_box->priv->action_group != NULL) { + combo_box->priv->group_sensitive_handler_id = + g_signal_connect ( + combo_box->priv->action_group, + "notify::sensitive", G_CALLBACK ( + action_combo_box_action_group_notify_cb), + combo_box); + combo_box->priv->group_visible_handler_id = + g_signal_connect ( + combo_box->priv->action_group, + "notify::visible", G_CALLBACK ( + action_combo_box_action_group_notify_cb), + combo_box); + } +} + +gint +e_action_combo_box_get_current_value (EActionComboBox *combo_box) +{ + g_return_val_if_fail (E_ACTION_IS_COMBO_BOX (combo_box), 0); + g_return_val_if_fail (combo_box->priv->action != NULL, 0); + + return gtk_radio_action_get_current_value (combo_box->priv->action); +} + +void +e_action_combo_box_set_current_value (EActionComboBox *combo_box, + gint current_value) +{ + g_return_if_fail (E_ACTION_IS_COMBO_BOX (combo_box)); + g_return_if_fail (combo_box->priv->action != NULL); + + gtk_radio_action_set_current_value ( + combo_box->priv->action, current_value); +} + +void +e_action_combo_box_add_separator_before (EActionComboBox *combo_box, + gint action_value) +{ + GtkTreeModel *model; + GtkTreeIter iter; + + g_return_if_fail (E_ACTION_IS_COMBO_BOX (combo_box)); + + /* NULL actions are rendered as separators. */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)); + gtk_list_store_append (GTK_LIST_STORE (model), &iter); + gtk_list_store_set ( + GTK_LIST_STORE (model), &iter, COLUMN_ACTION, + NULL, COLUMN_SORT, (gfloat) action_value - 0.5, -1); +} + +void +e_action_combo_box_add_separator_after (EActionComboBox *combo_box, + gint action_value) +{ + GtkTreeModel *model; + GtkTreeIter iter; + + g_return_if_fail (E_ACTION_IS_COMBO_BOX (combo_box)); + + /* NULL actions are rendered as separators. */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)); + gtk_list_store_append (GTK_LIST_STORE (model), &iter); + gtk_list_store_set ( + GTK_LIST_STORE (model), &iter, COLUMN_ACTION, + NULL, COLUMN_SORT, (gfloat) action_value + 0.5, -1); +} diff --git a/widgets/misc/e-action-combo-box.h b/widgets/misc/e-action-combo-box.h new file mode 100644 index 0000000000..300338639a --- /dev/null +++ b/widgets/misc/e-action-combo-box.h @@ -0,0 +1,85 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-action-combo-box.h + * + * Copyright (C) 2008 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU Lesser 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 Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef E_ACTION_COMBO_BOX_H +#define E_ACTION_COMBO_BOX_H + +/* This is a GtkComboBox that is driven by a group of GtkRadioActions. + * Just plug in a GtkRadioAction and the widget will handle the rest. + * (Based on GtkhtmlComboBox.) */ + +#include <gtk/gtk.h> + +/* Standard GObject macros */ +#define E_TYPE_ACTION_COMBO_BOX \ + (e_action_combo_box_get_type ()) +#define E_ACTION_COMBO_BOX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_ACTION_COMBO_BOX, EActionComboBox)) +#define E_ACTION_COMBO_BOX_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_ACTION_COMBO_BOX, EActionComboBoxClass)) +#define E_ACTION_IS_COMBO_BOX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_ACTION_COMBO_BOX)) +#define E_ACTION_IS_COMBO_BOX_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_ACTION_COMBO_BOX)) +#define E_ACTION_COMBO_BOX_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_ACTION_COMBO_BOX, EActionComboBoxClass)) + +G_BEGIN_DECLS + +typedef struct _EActionComboBox EActionComboBox; +typedef struct _EActionComboBoxClass EActionComboBoxClass; +typedef struct _EActionComboBoxPrivate EActionComboBoxPrivate; + +struct _EActionComboBox { + GtkComboBox parent; + EActionComboBoxPrivate *priv; +}; + +struct _EActionComboBoxClass { + GtkComboBoxClass parent_class; +}; + +GType e_action_combo_box_get_type (void); +GtkWidget * e_action_combo_box_new (void); +GtkWidget * e_action_combo_box_new_with_action + (GtkRadioAction *action); +GtkRadioAction *e_action_combo_box_get_action (EActionComboBox *combo_box); +void e_action_combo_box_set_action (EActionComboBox *combo_box, + GtkRadioAction *action); +gint e_action_combo_box_get_current_value + (EActionComboBox *combo_box); +void e_action_combo_box_set_current_value + (EActionComboBox *combo_box, + gint current_value); +void e_action_combo_box_add_separator_before + (EActionComboBox *combo_box, + gint action_value); +void e_action_combo_box_add_separator_after + (EActionComboBox *combo_box, + gint action_value); + +G_END_DECLS + +#endif /* E_ACTION_COMBO_BOX_H */ diff --git a/widgets/misc/e-activity-handler.c b/widgets/misc/e-activity-handler.c deleted file mode 100644 index 338e4015fb..0000000000 --- a/widgets/misc/e-activity-handler.c +++ /dev/null @@ -1,712 +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) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "e-activity-handler.h" - -#include <gtk/gtk.h> -#include <glib/gi18n.h> -#include <gdk-pixbuf/gdk-pixbuf.h> - -#include <misc/e-popup-menu.h> - -#define ICON_SIZE 16 - -struct _ActivityInfo { - gchar *component_id; - gint error_type; - guint id; - gchar *information; - gboolean cancellable; - double progress; - GtkWidget *menu; - void (*cancel_func) (gpointer data); - gpointer data; - gpointer error; - time_t error_time; -}; -typedef struct _ActivityInfo ActivityInfo; - -struct _EActivityHandlerPrivate { - guint next_activity_id; - GList *activity_infos; - GSList *task_bars; - ELogger *logger; - guint error_timer; - guint error_flush_interval; - -}; - -/* In the status bar, we show only errors and info. Errors are pictured as warnings. */ -const gchar *icon_data [] = {"dialog-warning", "dialog-information"}; - -G_DEFINE_TYPE (EActivityHandler, e_activity_handler, G_TYPE_OBJECT) - -/* Utility functions. */ - -static void handle_error (ETaskWidget *task); - -static guint -get_new_activity_id (EActivityHandler *activity_handler) -{ - EActivityHandlerPrivate *priv; - - priv = activity_handler->priv; - - return priv->next_activity_id ++; -} - -static GList * -lookup_activity (GList *list, - guint activity_id, - gint *order_number_return) -{ - GList *p; - gint i; - - for (p = list, i = 0; p != NULL; p = p->next, i ++) { - ActivityInfo *activity_info; - - activity_info = (ActivityInfo *) p->data; - if (activity_info->id == activity_id) { - *order_number_return = i; - return p; - } - } - - *order_number_return = -1; - return NULL; -} - -/* ETaskWidget actions. */ - -static gint -task_widget_button_press_event_callback (GtkWidget *widget, - GdkEventButton *button_event, - gpointer data) -{ - ActivityInfo *activity_info; - - activity_info = (ActivityInfo *) data; - - if (button_event->button == 3) - return activity_info->cancellable; - - if (button_event->button != 1) - return FALSE; - - return TRUE; -} - -/* Creating and destroying ActivityInfos. */ - -static ActivityInfo * -activity_info_new (const gchar *component_id, - guint id, - const gchar *information, - gboolean cancellable) -{ - ActivityInfo *info; - - info = g_new (ActivityInfo, 1); - info->component_id = g_strdup (component_id); - info->id = id; - info->information = g_strdup (information); - info->cancellable = cancellable; - info->progress = -1.0; /* (Unknown) */ - info->menu = NULL; - info->error = NULL; - info->cancel_func = NULL; - - return info; -} - -static void -activity_info_free (ActivityInfo *info) -{ - g_free (info->component_id); - g_free (info->information); - - if (info->menu != NULL) - gtk_widget_destroy (info->menu); - - g_free (info); -} - -static ETaskWidget * -task_widget_new_from_activity_info (ActivityInfo *activity_info) -{ - GtkWidget *widget; - ETaskWidget *etw; - - widget = e_task_widget_new_with_cancel ( - activity_info->component_id, - activity_info->information, - activity_info->cancel_func, - activity_info->data); - etw = (ETaskWidget *) widget; - etw->id = activity_info->id; - gtk_widget_show (widget); - - g_signal_connect (widget, "button_press_event", - G_CALLBACK (task_widget_button_press_event_callback), - activity_info); - - return E_TASK_WIDGET (widget); -} - -/* Task Bar handling. */ - -static void -setup_task_bar (EActivityHandler *activity_handler, - ETaskBar *task_bar) -{ - EActivityHandlerPrivate *priv; - GList *p; - - priv = activity_handler->priv; - - for (p = g_list_last (priv->activity_infos); p != NULL; p = p->prev) { - ActivityInfo *info = p->data; - ETaskWidget *task_widget = task_widget_new_from_activity_info (info); - task_widget->id = info->id; - e_task_bar_prepend_task (task_bar, task_widget); - if (info->error) { - /* Prepare to handle existing errors*/ - GtkWidget *tool; - const gchar *stock; - - stock = info->error_type ? icon_data [1] : icon_data[0]; - tool = e_task_widget_update_image (task_widget, (gchar *)stock, info->information); - g_object_set_data ((GObject *) task_widget, "tool", tool); - g_object_set_data ((GObject *) task_widget, "error", info->error); - g_object_set_data ((GObject *) task_widget, "activity-handler", activity_handler); - g_object_set_data ((GObject *) task_widget, "activity", GINT_TO_POINTER(info->id)); - g_object_set_data ((GObject *) task_widget, "error-type", GINT_TO_POINTER(info->error_type)); - g_signal_connect_swapped (tool, "clicked", G_CALLBACK(handle_error), task_widget); - } - } -} - -static void -task_bar_destroy_notify (gpointer data, - GObject *task_bar_instance) -{ - EActivityHandler *activity_handler; - EActivityHandlerPrivate *priv; - - activity_handler = E_ACTIVITY_HANDLER (data); - priv = activity_handler->priv; - - priv->task_bars = g_slist_remove (priv->task_bars, task_bar_instance); -} - -/* GObject methods. */ - -static void -impl_dispose (GObject *object) -{ - EActivityHandler *handler; - EActivityHandlerPrivate *priv; - GList *p; - GSList *sp; - - handler = E_ACTIVITY_HANDLER (object); - priv = handler->priv; - - for (p = priv->activity_infos; p != NULL; p = p->next) { - ActivityInfo *info; - - info = (ActivityInfo *) p->data; - activity_info_free (info); - } - - g_list_free (priv->activity_infos); - priv->activity_infos = NULL; - - for (sp = priv->task_bars; sp != NULL; sp = sp->next) - g_object_weak_unref (G_OBJECT (sp->data), task_bar_destroy_notify, handler); - priv->task_bars = NULL; - - (* G_OBJECT_CLASS (e_activity_handler_parent_class)->dispose) (object); -} - -static void -impl_finalize (GObject *object) -{ - EActivityHandler *handler; - EActivityHandlerPrivate *priv; - - handler = E_ACTIVITY_HANDLER (object); - priv = handler->priv; - - g_free (priv); - - (* G_OBJECT_CLASS (e_activity_handler_parent_class)->finalize) (object); -} - -static void -e_activity_handler_class_init (EActivityHandlerClass *activity_handler_class) -{ - GObjectClass *object_class = (GObjectClass *) activity_handler_class; - - object_class->dispose = impl_dispose; - object_class->finalize = impl_finalize; -} - -static void -e_activity_handler_init (EActivityHandler *activity_handler) -{ - EActivityHandlerPrivate *priv; - - priv = g_new (EActivityHandlerPrivate, 1); - priv->next_activity_id = 1; - priv->activity_infos = NULL; - priv->task_bars = NULL; - priv->logger = NULL; - priv->error_timer = 0; - priv->error_flush_interval = 0; - activity_handler->priv = priv; -} - -EActivityHandler * -e_activity_handler_new (void) -{ - return g_object_new (e_activity_handler_get_type (), NULL); -} - -void -e_activity_handler_set_error_flush_time (EActivityHandler *handler, gint time) -{ - handler->priv->error_flush_interval = time; -} -void -e_activity_handler_set_logger (EActivityHandler *handler, ELogger *logger) -{ - handler->priv->logger = logger; -} - -void -e_activity_handler_set_message (EActivityHandler *activity_handler, - const gchar *message) -{ - EActivityHandlerPrivate *priv; - GSList *i; - - priv = activity_handler->priv; - - for (i = priv->task_bars; i; i = i->next) - e_task_bar_set_message (E_TASK_BAR (i->data), message); -} - -void -e_activity_handler_unset_message (EActivityHandler *activity_handler) -{ - EActivityHandlerPrivate *priv; - GSList *i; - - priv = activity_handler->priv; - - for (i = priv->task_bars; i; i = i->next) - e_task_bar_unset_message (E_TASK_BAR (i->data)); -} - -void -e_activity_handler_attach_task_bar (EActivityHandler *activity_handler, - ETaskBar *task_bar) -{ - EActivityHandlerPrivate *priv; - - g_return_if_fail (activity_handler != NULL); - g_return_if_fail (E_IS_ACTIVITY_HANDLER (activity_handler)); - g_return_if_fail (task_bar != NULL); - g_return_if_fail (E_IS_TASK_BAR (task_bar)); - - priv = activity_handler->priv; - - g_object_weak_ref (G_OBJECT (task_bar), task_bar_destroy_notify, activity_handler); - - priv->task_bars = g_slist_prepend (priv->task_bars, task_bar); - - setup_task_bar (activity_handler, task_bar); -} - -struct _cancel_wdata { - EActivityHandler *handler; - ActivityInfo *info; - guint id; - void (*cancel)(gpointer); - gpointer data; -}; - -static void -cancel_wrapper (gpointer pdata) -{ - struct _cancel_wdata *data = (struct _cancel_wdata *) pdata; - /* This can be invoked in two scenario. Either to cancel or to hide error */ - if (data->info->error) { - /* Hide the error */ - EActivityHandler *handler = data->handler; - ActivityInfo *info; - gint order, len; - GSList *sp; - GList *p = lookup_activity (handler->priv->activity_infos, data->id, &order); - e_logger_log (handler->priv->logger, E_LOG_ERROR, g_object_get_data (data->info->error, "primary"), - g_object_get_data (data->info->error, "secondary")); - gtk_widget_destroy (data->info->error); - data->info->error = NULL; - info = data->info; - for (sp = handler->priv->task_bars; sp != NULL; sp = sp->next) { - ETaskBar *task_bar; - - task_bar = E_TASK_BAR (sp->data); - e_task_bar_remove_task_from_id (task_bar, info->id); - } - activity_info_free (info); - len = g_list_length (handler->priv->activity_infos); - handler->priv->activity_infos = g_list_remove_link (handler->priv->activity_infos, p); - if (len == 1) - handler->priv->activity_infos = NULL; - } else { - /* Cancel the operation */ - data->cancel (data->data); - } - /* No need to free the data. It will be freed as part of the task widget destroy */ -} - -/* CORBA methods. */ -guint e_activity_handler_cancelable_operation_started (EActivityHandler *activity_handler, - const gchar *component_id, - const gchar *information, - gboolean cancellable, - void (*cancel_func)(gpointer), - gpointer user_data) -{ - EActivityHandlerPrivate *priv; - ActivityInfo *activity_info; - guint activity_id; - GSList *p; - struct _cancel_wdata *data; - gboolean bfree = FALSE; - priv = activity_handler->priv; - - activity_id = get_new_activity_id (activity_handler); - activity_info = activity_info_new (component_id, activity_id, information, cancellable); - - data = g_new(struct _cancel_wdata, 1); - data->handler = activity_handler; - data->id = activity_id; - data->info = activity_info; - data->cancel = cancel_func; - data->data = user_data; - - activity_info->cancel_func = cancel_wrapper; - activity_info->data = data; - for (p = priv->task_bars; p != NULL; p = p->next) { - ETaskWidget *tw = task_widget_new_from_activity_info (activity_info); - tw->id = activity_id; - if (!bfree) { - /* The data will be freed part of the widget destroy */ - g_object_set_data_full ((GObject *) tw, "free-data", data, g_free); - bfree = TRUE; - } - e_task_bar_prepend_task (E_TASK_BAR (p->data), tw); - } - - priv->activity_infos = g_list_prepend (priv->activity_infos, activity_info); - - return activity_id; - -} - -guint -e_activity_handler_operation_started (EActivityHandler *activity_handler, - const gchar *component_id, - const gchar *information, - gboolean cancellable) -{ - EActivityHandlerPrivate *priv; - ActivityInfo *activity_info; - guint activity_id; - GSList *p; - - priv = activity_handler->priv; - - activity_id = get_new_activity_id (activity_handler); - - activity_info = activity_info_new (component_id, activity_id, information, cancellable); - - for (p = priv->task_bars; p != NULL; p = p->next) { - ETaskWidget *tw = task_widget_new_from_activity_info (activity_info); - tw->id = activity_id; - e_task_bar_prepend_task (E_TASK_BAR (p->data), tw); - } - - priv->activity_infos = g_list_prepend (priv->activity_infos, activity_info); - - return activity_id; -} - -static void -handle_error (ETaskWidget *task) -{ - GtkWidget *tool, *error; - EActivityHandler *activity_handler; - guint id; - gint error_type = GPOINTER_TO_INT((g_object_get_data ((GObject *) task, "error-type"))); - tool = g_object_get_data ((GObject *) task, "tool"); - error = g_object_get_data ((GObject *) task, "error"); - activity_handler = g_object_get_data ((GObject *) task, "activity-handler"); - id = GPOINTER_TO_UINT (g_object_get_data ((GObject *) task, "activity")); - e_activity_handler_operation_finished (activity_handler, id); - gtk_widget_show (error); - e_logger_log (activity_handler->priv->logger, error_type, - g_object_get_data ((GObject *) error, "primary"), - g_object_get_data ((GObject *) error, "secondary")); -} - -static gboolean -error_cleanup (EActivityHandler *activity_handler) -{ - EActivityHandlerPrivate *priv = activity_handler->priv; - GList *p, *node; - GSList *sp; - gint i; - time_t now = time (NULL); - gboolean berror = FALSE; - - for (p = priv->activity_infos, i = 0; p != NULL; i++) { - ActivityInfo *info; - - info = (ActivityInfo *) p->data; - if (info->error) - berror = TRUE; - if (info->error && info->error_time && (now - info->error_time) > 5 ) { - /* Error older than wanted time. So cleanup */ - e_logger_log (priv->logger, info->error_type, g_object_get_data (info->error, "primary"), - g_object_get_data (info->error, "secondary")); - - if (GTK_IS_DIALOG (info->error)) - gtk_dialog_response (GTK_DIALOG (info->error), GTK_RESPONSE_CLOSE); - else - gtk_widget_destroy (info->error); - - node = p; - p = p->next; - - for (sp = priv->task_bars; sp != NULL; sp = sp->next) { - ETaskBar *task_bar; - - task_bar = E_TASK_BAR (sp->data); - e_task_bar_remove_task_from_id (task_bar, info->id); - } - activity_info_free (info); - priv->activity_infos = g_list_remove_link (priv->activity_infos, node); - - } else - p = p->next; - } - if (!berror) - priv->error_timer = 0; - return berror; -} - -static gboolean -show_intrusive_errors (void) -{ - const gchar *intrusive = NULL; - - intrusive = g_getenv ("EVO-SHOW-INTRUSIVE-ERRORS"); - - if (intrusive && g_str_equal (intrusive, "1")) - return TRUE; - else - return FALSE; -} - -guint -e_activity_handler_make_error (EActivityHandler *activity_handler, - const gchar *component_id, - gint error_type, - GtkWidget *error) -{ - EActivityHandlerPrivate *priv; - ActivityInfo *activity_info; - guint activity_id; - GSList *p; - gchar *information = g_object_get_data((GObject *) error, "primary"); - const gchar *img; - - priv = activity_handler->priv; - activity_id = get_new_activity_id (activity_handler); - - if (show_intrusive_errors ()) { - gtk_widget_show (error); - return activity_id; - } - - activity_info = activity_info_new (component_id, activity_id, information, TRUE); - activity_info->error = error; - activity_info->error_time = time (NULL); - activity_info->error_type = error_type; - - img = error_type ? icon_data[1] : icon_data[0]; - for (p = priv->task_bars; p != NULL; p = p->next) { - ETaskBar *task_bar; - ETaskWidget *task_widget; - GtkWidget *tool; - - task_bar = E_TASK_BAR (p->data); - task_widget = task_widget_new_from_activity_info (activity_info); - task_widget->id = activity_id; - e_task_bar_prepend_task (E_TASK_BAR (p->data), task_widget); - - tool = e_task_widget_update_image (task_widget, (gchar *)img, information); - g_object_set_data ((GObject *) task_widget, "tool", tool); - g_object_set_data ((GObject *) task_widget, "error", error); - g_object_set_data ((GObject *) task_widget, "activity-handler", activity_handler); - g_object_set_data ((GObject *) task_widget, "activity", GINT_TO_POINTER(activity_id)); - g_object_set_data ((GObject *) task_widget, "error-type", GINT_TO_POINTER(error_type)); - g_signal_connect_swapped (tool, "clicked", G_CALLBACK(handle_error), task_widget); - } - - priv->activity_infos = g_list_prepend (priv->activity_infos, activity_info); - - if (!activity_handler->priv->error_timer) - activity_handler->priv->error_timer = g_timeout_add (activity_handler->priv->error_flush_interval, (GSourceFunc)error_cleanup, activity_handler); - - return activity_id; -} - -void -e_activity_handler_operation_set_error(EActivityHandler *activity_handler, - guint activity_id, - GtkWidget *error) -{ - EActivityHandlerPrivate *priv = activity_handler->priv; - ActivityInfo *activity_info; - GList *p; - GSList *sp; - gint order_number; - - p = lookup_activity (priv->activity_infos, activity_id, &order_number); - if (p == NULL) { - g_warning ("EActivityHandler: unknown operation %d", activity_id); - return; - } - - activity_info = (ActivityInfo *) p->data; - activity_info->error = error; - activity_info->error_time = time (NULL); - activity_info->error_type = E_LOG_ERROR; - g_free (activity_info->information); - activity_info->information = g_strdup (g_object_get_data ((GObject *) error, "primary")); - for (sp = priv->task_bars; sp != NULL; sp = sp->next) { - ETaskBar *task_bar; - ETaskWidget *task_widget; - GtkWidget *tool; - - task_bar = E_TASK_BAR (sp->data); - task_widget = e_task_bar_get_task_widget_from_id (task_bar, activity_info->id); - if (!task_widget) - continue; - - tool = e_task_widget_update_image (task_widget, (gchar *)icon_data[0], g_object_get_data ((GObject *) error, "primary")); - g_object_set_data ((GObject *) task_widget, "tool", tool); - g_object_set_data ((GObject *) task_widget, "error", error); - g_object_set_data ((GObject *) task_widget, "activity-handler", activity_handler); - g_object_set_data ((GObject *) task_widget, "activity", GINT_TO_POINTER(activity_id)); - g_object_set_data ((GObject *) task_widget, "error-type", GINT_TO_POINTER(E_LOG_ERROR)); - g_signal_connect_swapped (tool, "clicked", G_CALLBACK(handle_error), task_widget); - } - - if (!activity_handler->priv->error_timer) - activity_handler->priv->error_timer = g_timeout_add (activity_handler->priv->error_flush_interval, (GSourceFunc) error_cleanup, activity_handler); -} - -void -e_activity_handler_operation_progressing (EActivityHandler *activity_handler, - guint activity_id, - const gchar *information, - double progress) -{ - EActivityHandlerPrivate *priv = activity_handler->priv; - ActivityInfo *activity_info; - GList *p; - GSList *sp; - gint order_number; - - p = lookup_activity (priv->activity_infos, activity_id, &order_number); - if (p == NULL) { - g_warning ("EActivityHandler: unknown operation %d", activity_id); - return; - } - - activity_info = (ActivityInfo *) p->data; - - g_free (activity_info->information); - activity_info->information = g_strdup (information); - - activity_info->progress = progress; - - for (sp = priv->task_bars; sp != NULL; sp = sp->next) { - ETaskBar *task_bar; - ETaskWidget *task_widget; - - task_bar = E_TASK_BAR (sp->data); - task_widget = e_task_bar_get_task_widget_from_id (task_bar, activity_info->id); - if (!task_widget) - continue; - - e_task_widget_update (task_widget, information, progress); - } -} - -void -e_activity_handler_operation_finished (EActivityHandler *activity_handler, - guint activity_id) -{ - EActivityHandlerPrivate *priv = activity_handler->priv; - GList *p; - GSList *sp; - gint order_number; - - p = lookup_activity (priv->activity_infos, activity_id, &order_number); - if (p == NULL) { - g_warning ("e_activity_handler_operation_finished: Unknown activity %d\n", activity_id); - return; - } - - activity_info_free ((ActivityInfo *) p->data); - priv->activity_infos = g_list_remove_link (priv->activity_infos, p); - - for (sp = priv->task_bars; sp != NULL; sp = sp->next) { - ETaskBar *task_bar; - - task_bar = E_TASK_BAR (sp->data); - e_task_bar_remove_task_from_id (task_bar, activity_id); - } -} - diff --git a/widgets/misc/e-activity-handler.h b/widgets/misc/e-activity-handler.h deleted file mode 100644 index 3fd5c64d9a..0000000000 --- a/widgets/misc/e-activity-handler.h +++ /dev/null @@ -1,101 +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 _E_ACTIVITY_HANDLER_H_ -#define _E_ACTIVITY_HANDLER_H_ - -#include "e-task-bar.h" -#include "e-util/e-logger.h" -#include <glib-object.h> - -G_BEGIN_DECLS - -#define E_TYPE_ACTIVITY_HANDLER (e_activity_handler_get_type ()) -#define E_ACTIVITY_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_ACTIVITY_HANDLER, EActivityHandler)) -#define E_ACTIVITY_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_ACTIVITY_HANDLER, EActivityHandlerClass)) -#define E_IS_ACTIVITY_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_ACTIVITY_HANDLER)) -#define E_IS_ACTIVITY_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_ACTIVITY_HANDLER)) - -typedef struct _EActivityHandler EActivityHandler; -typedef struct _EActivityHandlerPrivate EActivityHandlerPrivate; -typedef struct _EActivityHandlerClass EActivityHandlerClass; - -#define EAH_ICON_INFO "stock_dialog-info" -#define EAH_ICON_ERROR "stock_dialog-warning" - -struct _EActivityHandler { - GObject parent; - - EActivityHandlerPrivate *priv; -}; - -struct _EActivityHandlerClass { - GObjectClass parent_class; -}; - -GType e_activity_handler_get_type (void); - -EActivityHandler *e_activity_handler_new (void); - -void e_activity_handler_attach_task_bar (EActivityHandler *activity_hanlder, - ETaskBar *task_bar); - -void e_activity_handler_set_message (EActivityHandler *activity_handler, - const gchar *message); - -void e_activity_handler_unset_message (EActivityHandler *activity_handler); - -guint e_activity_handler_operation_started (EActivityHandler *activity_handler, - const gchar *component_id, - const gchar *information, - gboolean cancellable); -guint e_activity_handler_cancelable_operation_started (EActivityHandler *activity_handler, - const gchar *component_id, - const gchar *information, - gboolean cancellable, - void (*cancel_func)(gpointer), - gpointer user_data); - -void e_activity_handler_operation_progressing (EActivityHandler *activity_handler, - guint activity_id, - const gchar *information, - double progress); - -void e_activity_handler_operation_finished (EActivityHandler *activity_handler, - guint activity_id); - -void e_activity_handler_set_logger (EActivityHandler *handler, ELogger *logger); -guint e_activity_handler_make_error (EActivityHandler *activity_handler, - const gchar *component_id, - gint error_type, - GtkWidget *error); -void -e_activity_handler_operation_set_error (EActivityHandler *activity_handler, - guint activity_id, - GtkWidget *error); - -void -e_activity_handler_set_error_flush_time (EActivityHandler *handler, gint time); - -G_END_DECLS - -#endif /* _E_ACTIVITY_HANDLER_H_ */ diff --git a/widgets/misc/e-activity-proxy.c b/widgets/misc/e-activity-proxy.c new file mode 100644 index 0000000000..10249b1911 --- /dev/null +++ b/widgets/misc/e-activity-proxy.c @@ -0,0 +1,346 @@ +/* + * e-activity-proxy.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-activity-proxy.h" + +#include <glib/gi18n.h> +#include <e-spinner.h> + +#define E_ACTIVITY_PROXY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_ACTIVITY_PROXY, EActivityProxyPrivate)) + +struct _EActivityProxyPrivate { + EActivity *activity; + GtkWidget *button; + GtkWidget *image; + GtkWidget *label; + GtkWidget *cancel; + GtkWidget *spinner; +}; + +enum { + PROP_0, + PROP_ACTIVITY +}; + +static gpointer parent_class; + +static void +activity_proxy_update (EActivityProxy *proxy) +{ + EActivity *activity = proxy->priv->activity; + const gchar *icon_name; + gboolean allow_cancel; + gboolean cancelled; + gboolean clickable; + gboolean completed; + gboolean sensitive; + gchar *description; + + allow_cancel = e_activity_get_allow_cancel (activity); + cancelled = e_activity_is_cancelled (activity); + clickable = e_activity_get_clickable (activity); + completed = e_activity_is_completed (activity); + icon_name = e_activity_get_icon_name (activity); + + description = e_activity_describe (activity); + gtk_widget_set_tooltip_text (GTK_WIDGET (proxy), description); + gtk_label_set_text (GTK_LABEL (proxy->priv->label), description); + g_free (description); + + /* Note, an activity requires an icon name in order to + * be clickable. We don't support spinner buttons. */ + if (icon_name != NULL) { + gtk_image_set_from_icon_name ( + GTK_IMAGE (proxy->priv->image), + icon_name, GTK_ICON_SIZE_MENU); + gtk_button_set_image ( + GTK_BUTTON (proxy->priv->button), + gtk_image_new_from_icon_name ( + icon_name, GTK_ICON_SIZE_MENU)); + gtk_widget_hide (proxy->priv->spinner); + if (clickable) { + gtk_widget_show (proxy->priv->button); + gtk_widget_hide (proxy->priv->image); + } else { + gtk_widget_hide (proxy->priv->button); + gtk_widget_show (proxy->priv->image); + } + } else { + gtk_widget_show (proxy->priv->spinner); + gtk_widget_hide (proxy->priv->button); + gtk_widget_hide (proxy->priv->image); + } + + if (allow_cancel) + gtk_widget_show (proxy->priv->cancel); + else + gtk_widget_hide (proxy->priv->cancel); + + sensitive = !(cancelled || completed); + gtk_widget_set_sensitive (proxy->priv->cancel, sensitive); +} + +static void +activity_proxy_set_activity (EActivityProxy *proxy, + EActivity *activity) +{ + g_return_if_fail (proxy->priv->activity == NULL); + + proxy->priv->activity = g_object_ref (activity); +} + +static void +activity_proxy_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ACTIVITY: + activity_proxy_set_activity ( + E_ACTIVITY_PROXY (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +activity_proxy_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ACTIVITY: + g_value_set_object ( + value, e_activity_proxy_get_activity ( + E_ACTIVITY_PROXY (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +activity_proxy_dispose (GObject *object) +{ + EActivityProxyPrivate *priv; + + priv = E_ACTIVITY_PROXY_GET_PRIVATE (object); + + if (priv->activity != NULL) { + g_signal_handlers_disconnect_matched ( + priv->activity, G_SIGNAL_MATCH_FUNC, 0, 0, + NULL, activity_proxy_update, NULL); + g_object_unref (priv->activity); + priv->activity = NULL; + } + + if (priv->button != NULL) { + g_object_unref (priv->button); + priv->button = NULL; + } + + if (priv->image != NULL) { + g_object_unref (priv->image); + priv->image = NULL; + } + + if (priv->label != NULL) { + g_object_unref (priv->label); + priv->label = NULL; + } + + if (priv->cancel != NULL) { + g_object_unref (priv->cancel); + priv->cancel = NULL; + } + + if (priv->spinner != NULL) { + g_object_unref (priv->spinner); + priv->spinner = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +activity_proxy_constructed (GObject *object) +{ + EActivityProxy *proxy; + + proxy = E_ACTIVITY_PROXY (object); + + g_signal_connect_swapped ( + proxy->priv->button, "clicked", + G_CALLBACK (e_activity_clicked), proxy->priv->activity); + + g_signal_connect_swapped ( + proxy->priv->cancel, "clicked", + G_CALLBACK (e_activity_cancel), proxy->priv->activity); + + g_signal_connect_swapped ( + proxy->priv->activity, "cancelled", + G_CALLBACK (activity_proxy_update), proxy); + + g_signal_connect_swapped ( + proxy->priv->activity, "completed", + G_CALLBACK (activity_proxy_update), proxy); + + g_signal_connect_swapped ( + proxy->priv->activity, "notify", + G_CALLBACK (activity_proxy_update), proxy); + + activity_proxy_update (proxy); +} + +static void +activity_proxy_class_init (EActivityProxyClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EActivityProxyPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = activity_proxy_set_property; + object_class->get_property = activity_proxy_get_property; + object_class->dispose = activity_proxy_dispose; + object_class->constructed = activity_proxy_constructed; + + g_object_class_install_property ( + object_class, + PROP_ACTIVITY, + g_param_spec_object ( + "activity", + NULL, + NULL, + E_TYPE_ACTIVITY, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); +} + +static void +activity_proxy_init (EActivityProxy *proxy) +{ + GtkWidget *container; + GtkWidget *widget; + + proxy->priv = E_ACTIVITY_PROXY_GET_PRIVATE (proxy); + + container = GTK_WIDGET (proxy); + + widget = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_hbox_new (FALSE, 3); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_image_new (); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + proxy->priv->image = g_object_ref (widget); + gtk_widget_hide (widget); + + widget = gtk_button_new (); + gtk_button_set_relief (GTK_BUTTON (widget), GTK_RELIEF_NONE); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + proxy->priv->button = g_object_ref (widget); + gtk_widget_hide (widget); + + /* XXX What's the rationale for killing the old spinner API? */ + widget = e_spinner_new_spinning_small_shown (); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + proxy->priv->spinner = g_object_ref (widget); + gtk_widget_show (widget); + + widget = gtk_label_new (NULL); + gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + proxy->priv->label = g_object_ref (widget); + gtk_widget_show (widget); + + widget = gtk_button_new (); + gtk_button_set_image ( + GTK_BUTTON (widget), gtk_image_new_from_stock ( + GTK_STOCK_STOP, GTK_ICON_SIZE_MENU)); + gtk_button_set_relief (GTK_BUTTON (widget), GTK_RELIEF_NONE); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_set_tooltip_text (widget, _("Cancel")); + proxy->priv->cancel = g_object_ref (widget); + gtk_widget_show (widget); +} + +GType +e_activity_proxy_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EActivityProxyClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) activity_proxy_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EActivityProxy), + 0, /* n_preallocs */ + (GInstanceInitFunc) activity_proxy_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_EVENT_BOX, "EActivityProxy", &type_info, 0); + } + + return type; +} + +GtkWidget * +e_activity_proxy_new (EActivity *activity) +{ + g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL); + + return g_object_new ( + E_TYPE_ACTIVITY_PROXY, + "activity", activity, NULL); +} + +EActivity * +e_activity_proxy_get_activity (EActivityProxy *proxy) +{ + g_return_val_if_fail (E_IS_ACTIVITY_PROXY (proxy), NULL); + + return proxy->priv->activity; +} diff --git a/widgets/misc/e-activity-proxy.h b/widgets/misc/e-activity-proxy.h new file mode 100644 index 0000000000..714dc63e0f --- /dev/null +++ b/widgets/misc/e-activity-proxy.h @@ -0,0 +1,68 @@ +/* + * e-activity-proxy.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_ACTIVITY_PROXY_H +#define E_ACTIVITY_PROXY_H + +#include <gtk/gtk.h> +#include <e-activity.h> + +/* Standard GObject macros */ +#define E_TYPE_ACTIVITY_PROXY \ + (e_activity_proxy_get_type ()) +#define E_ACTIVITY_PROXY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_ACTIVITY_PROXY, EActivityProxy)) +#define E_ACTIVITY_PROXY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_ACTIVITY_PROXY, EActivityProxyClass)) +#define E_IS_ACTIVITY_PROXY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_ACTIVITY_PROXY)) +#define E_IS_ACTIVITY_PROXY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_ACTIVITY_PROXY)) +#define E_ACTIVITY_PROXY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_ACTIVITY_PROXY, EActivityProxyClass)) + +G_BEGIN_DECLS + +typedef struct _EActivityProxy EActivityProxy; +typedef struct _EActivityProxyClass EActivityProxyClass; +typedef struct _EActivityProxyPrivate EActivityProxyPrivate; + +struct _EActivityProxy { + GtkEventBox parent; + EActivityProxyPrivate *priv; +}; + +struct _EActivityProxyClass { + GtkEventBoxClass parent_class; +}; + +GType e_activity_proxy_get_type (void); +GtkWidget * e_activity_proxy_new (EActivity *activity); +EActivity * e_activity_proxy_get_activity (EActivityProxy *proxy); + +G_END_DECLS + +#endif /* E_ACTIVITY_PROXY_H */ diff --git a/widgets/misc/e-activity.c b/widgets/misc/e-activity.c new file mode 100644 index 0000000000..9f8faf75cb --- /dev/null +++ b/widgets/misc/e-activity.c @@ -0,0 +1,605 @@ +/* + * e-activity.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-activity.h" + +#include <stdarg.h> +#include <glib/gi18n.h> + +#include "e-util/e-util.h" + +#define E_ACTIVITY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_ACTIVITY, EActivityPrivate)) + +struct _EActivityPrivate { + gchar *icon_name; + gchar *primary_text; + gchar *secondary_text; + gdouble percent; + + guint allow_cancel : 1; + guint cancelled : 1; + guint clickable : 1; + guint completed : 1; +}; + +enum { + PROP_0, + PROP_ALLOW_CANCEL, + PROP_CLICKABLE, + PROP_ICON_NAME, + PROP_PERCENT, + PROP_PRIMARY_TEXT, + PROP_SECONDARY_TEXT +}; + +enum { + CANCELLED, + CLICKED, + COMPLETED, + DESCRIBE, + LAST_SIGNAL +}; + +static gpointer parent_class; +static gulong signals[LAST_SIGNAL]; + +static gboolean +activity_describe_accumulator (GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer accu_data) +{ + const gchar *string; + + string = g_value_get_string (handler_return); + g_value_set_string (return_accu, string); + + return (string == NULL); +} + +static void +activity_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ALLOW_CANCEL: + e_activity_set_allow_cancel ( + E_ACTIVITY (object), + g_value_get_boolean (value)); + return; + + case PROP_CLICKABLE: + e_activity_set_clickable ( + E_ACTIVITY (object), + g_value_get_boolean (value)); + return; + + case PROP_ICON_NAME: + e_activity_set_icon_name ( + E_ACTIVITY (object), + g_value_get_string (value)); + return; + + case PROP_PERCENT: + e_activity_set_percent ( + E_ACTIVITY (object), + g_value_get_double (value)); + return; + + case PROP_PRIMARY_TEXT: + e_activity_set_primary_text ( + E_ACTIVITY (object), + g_value_get_string (value)); + return; + + case PROP_SECONDARY_TEXT: + e_activity_set_secondary_text ( + E_ACTIVITY (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +activity_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ALLOW_CANCEL: + g_value_set_boolean ( + value, e_activity_get_allow_cancel ( + E_ACTIVITY (object))); + return; + + case PROP_CLICKABLE: + g_value_set_boolean ( + value, e_activity_get_clickable ( + E_ACTIVITY (object))); + return; + + case PROP_ICON_NAME: + g_value_set_string ( + value, e_activity_get_icon_name ( + E_ACTIVITY (object))); + return; + + case PROP_PERCENT: + g_value_set_double ( + value, e_activity_get_percent ( + E_ACTIVITY (object))); + return; + + case PROP_PRIMARY_TEXT: + g_value_set_string ( + value, e_activity_get_primary_text ( + E_ACTIVITY (object))); + return; + + case PROP_SECONDARY_TEXT: + g_value_set_string ( + value, e_activity_get_secondary_text ( + E_ACTIVITY (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +activity_finalize (GObject *object) +{ + EActivityPrivate *priv; + + priv = E_ACTIVITY_GET_PRIVATE (object); + + g_free (priv->icon_name); + g_free (priv->primary_text); + g_free (priv->secondary_text); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +activity_cancelled (EActivity *activity) +{ + activity->priv->cancelled = TRUE; +} + +static void +activity_completed (EActivity *activity) +{ + activity->priv->completed = TRUE; +} + +static void +activity_clicked (EActivity *activity) +{ + /* Allow subclasses to safely chain up. */ +} + +static gchar * +activity_describe (EActivity *activity) +{ + GString *string; + const gchar *text; + gboolean cancelled; + gboolean completed; + gdouble percent; + + string = g_string_sized_new (256); + text = e_activity_get_primary_text (activity); + cancelled = e_activity_is_cancelled (activity); + completed = e_activity_is_completed (activity); + percent = e_activity_get_percent (activity); + + if (cancelled) { + /* Translators: This is a cancelled activity. */ + g_string_printf (string, _("%s (cancelled)"), text); + } else if (completed) { + /* Translators: This is a completed activity. */ + g_string_printf (string, _("%s (completed)"), text); + } else if (percent < 0.0) { + /* Translators: This is an activity whose percent + * complete is unknown. */ + g_string_printf (string, _("%s..."), text); + } else { + /* Translators: This is an activity whose percent + * complete is known. */ + g_string_printf ( + string, _("%s (%d%% complete)"), text, + (gint) (percent * 100.0 + 0.5)); + } + + return g_string_free (string, FALSE); +} + +static void +activity_class_init (EActivityClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EActivityPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = activity_set_property; + object_class->get_property = activity_get_property; + object_class->finalize = activity_finalize; + + class->cancelled = activity_cancelled; + class->completed = activity_completed; + class->clicked = activity_clicked; + class->describe = activity_describe; + + g_object_class_install_property ( + object_class, + PROP_ALLOW_CANCEL, + g_param_spec_boolean ( + "allow-cancel", + NULL, + NULL, + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_CLICKABLE, + g_param_spec_boolean ( + "clickable", + NULL, + NULL, + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_ICON_NAME, + g_param_spec_string ( + "icon-name", + NULL, + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_PERCENT, + g_param_spec_double ( + "percent", + NULL, + NULL, + -G_MAXDOUBLE, + G_MAXDOUBLE, + -1.0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_PRIMARY_TEXT, + g_param_spec_string ( + "primary-text", + NULL, + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_SECONDARY_TEXT, + g_param_spec_string ( + "secondary-text", + NULL, + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + signals[CANCELLED] = g_signal_new ( + "cancelled", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EActivityClass, cancelled), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[CLICKED] = g_signal_new ( + "clicked", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EActivityClass, clicked), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[COMPLETED] = g_signal_new ( + "completed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EActivityClass, completed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[DESCRIBE] = g_signal_new ( + "describe", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EActivityClass, describe), + activity_describe_accumulator, NULL, + e_marshal_STRING__VOID, + G_TYPE_STRING, 0); +} + +static void +activity_init (EActivity *activity) +{ + activity->priv = E_ACTIVITY_GET_PRIVATE (activity); +} + +GType +e_activity_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EActivityClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) activity_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EActivity), + 0, /* n_preallocs */ + (GInstanceInitFunc) activity_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + G_TYPE_OBJECT, "EActivity", &type_info, 0); + } + + return type; +} + +EActivity * +e_activity_new (const gchar *primary_text) +{ + return g_object_new ( + E_TYPE_ACTIVITY, + "primary-text", primary_text, NULL); +} + +EActivity * +e_activity_newv (const gchar *format, ...) +{ + EActivity *activity; + gchar *primary_text; + va_list args; + + va_start (args, format); + primary_text = g_strdup_vprintf (format, args); + activity = e_activity_new (primary_text); + g_free (primary_text); + va_end (args); + + return activity; +} + +void +e_activity_cancel (EActivity *activity) +{ + g_return_if_fail (E_IS_ACTIVITY (activity)); + + if (!activity->priv->allow_cancel) + return; + + if (activity->priv->cancelled) + return; + + if (activity->priv->completed) + return; + + g_signal_emit (activity, signals[CANCELLED], 0); +} + +void +e_activity_complete (EActivity *activity) +{ + g_return_if_fail (E_IS_ACTIVITY (activity)); + + if (activity->priv->cancelled) + return; + + if (activity->priv->completed) + return; + + g_signal_emit (activity, signals[COMPLETED], 0); +} + +void +e_activity_clicked (EActivity *activity) +{ + g_return_if_fail (E_IS_ACTIVITY (activity)); + + g_signal_emit (activity, signals[CLICKED], 0); +} + +gchar * +e_activity_describe (EActivity *activity) +{ + EActivityClass *class; + + g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL); + + class = E_ACTIVITY_GET_CLASS (activity); + g_return_val_if_fail (class->describe != NULL, NULL); + + return class->describe (activity); +} + +gboolean +e_activity_is_cancelled (EActivity *activity) +{ + g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE); + + return activity->priv->cancelled; +} + +gboolean +e_activity_is_completed (EActivity *activity) +{ + g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE); + + return activity->priv->completed; +} + +gboolean +e_activity_get_allow_cancel (EActivity *activity) +{ + g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE); + + return activity->priv->allow_cancel; +} + +void +e_activity_set_allow_cancel (EActivity *activity, + gboolean allow_cancel) +{ + g_return_if_fail (E_IS_ACTIVITY (activity)); + + activity->priv->allow_cancel = allow_cancel; + + g_object_notify (G_OBJECT (activity), "allow-cancel"); +} + +gboolean +e_activity_get_clickable (EActivity *activity) +{ + g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE); + + return activity->priv->clickable; +} + +void +e_activity_set_clickable (EActivity *activity, + gboolean clickable) +{ + g_return_if_fail (E_IS_ACTIVITY (activity)); + + activity->priv->clickable = clickable; + + g_object_notify (G_OBJECT (activity), "clickable"); +} + +const gchar * +e_activity_get_icon_name (EActivity *activity) +{ + g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL); + + return activity->priv->icon_name; +} + +void +e_activity_set_icon_name (EActivity *activity, + const gchar *icon_name) +{ + g_return_if_fail (E_IS_ACTIVITY (activity)); + + g_free (activity->priv->icon_name); + activity->priv->icon_name = g_strdup (icon_name); + + g_object_notify (G_OBJECT (activity), "icon-name"); +} + +gdouble +e_activity_get_percent (EActivity *activity) +{ + g_return_val_if_fail (E_IS_ACTIVITY (activity), -1.0); + + return activity->priv->percent; +} + +void +e_activity_set_percent (EActivity *activity, + gdouble percent) +{ + g_return_if_fail (E_IS_ACTIVITY (activity)); + + activity->priv->percent = percent; + + g_object_notify (G_OBJECT (activity), "percent"); +} + +const gchar * +e_activity_get_primary_text (EActivity *activity) +{ + g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL); + + return activity->priv->primary_text; +} + +void +e_activity_set_primary_text (EActivity *activity, + const gchar *primary_text) +{ + g_return_if_fail (E_IS_ACTIVITY (activity)); + + g_free (activity->priv->primary_text); + activity->priv->primary_text = g_strdup (primary_text); + + g_object_notify (G_OBJECT (activity), "primary-text"); +} + +const gchar * +e_activity_get_secondary_text (EActivity *activity) +{ + g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL); + + return activity->priv->secondary_text; +} + +void +e_activity_set_secondary_text (EActivity *activity, + const gchar *secondary_text) +{ + g_return_if_fail (E_IS_ACTIVITY (activity)); + + g_free (activity->priv->secondary_text); + activity->priv->secondary_text = g_strdup (secondary_text); + + g_object_notify (G_OBJECT (activity), "secondary-text"); +} diff --git a/widgets/misc/e-activity.h b/widgets/misc/e-activity.h new file mode 100644 index 0000000000..b396e3a630 --- /dev/null +++ b/widgets/misc/e-activity.h @@ -0,0 +1,98 @@ +/* + * e-activity.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_ACTIVITY_H +#define E_ACTIVITY_H + +#include <gtk/gtk.h> + +/* Standard GObject macros */ +#define E_TYPE_ACTIVITY \ + (e_activity_get_type ()) +#define E_ACTIVITY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_ACTIVITY, EActivity)) +#define E_ACTIVITY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_ACTIVITY, EActivityClass)) +#define E_IS_ACTIVITY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_ACTIVITY)) +#define E_IS_ACTIVITY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_ACTIVITY)) +#define E_ACTIVITY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_ACTIVITY, EActivityClass)) + +G_BEGIN_DECLS + +typedef struct _EActivity EActivity; +typedef struct _EActivityClass EActivityClass; +typedef struct _EActivityPrivate EActivityPrivate; + +struct _EActivity { + GObject parent; + EActivityPrivate *priv; +}; + +struct _EActivityClass { + GObjectClass parent_class; + + /* Signals */ + void (*cancelled) (EActivity *activity); + void (*completed) (EActivity *activity); + void (*clicked) (EActivity *activity); + gchar * (*describe) (EActivity *activity); +}; + +GType e_activity_get_type (void); +EActivity * e_activity_new (const gchar *primary_text); +EActivity * e_activity_newv (const gchar *format, + ...) G_GNUC_PRINTF (1, 2); +void e_activity_cancel (EActivity *activity); +void e_activity_complete (EActivity *activity); +void e_activity_clicked (EActivity *activity); +gchar * e_activity_describe (EActivity *activity); +gboolean e_activity_is_cancelled (EActivity *activity); +gboolean e_activity_is_completed (EActivity *activity); +gboolean e_activity_get_allow_cancel (EActivity *activity); +void e_activity_set_allow_cancel (EActivity *activity, + gboolean allow_cancel); +gboolean e_activity_get_clickable (EActivity *activity); +void e_activity_set_clickable (EActivity *activity, + gboolean clickable); +const gchar * e_activity_get_icon_name (EActivity *activity); +void e_activity_set_icon_name (EActivity *activity, + const gchar *icon_name); +gdouble e_activity_get_percent (EActivity *activity); +void e_activity_set_percent (EActivity *activity, + gdouble percent); +const gchar * e_activity_get_primary_text (EActivity *activity); +void e_activity_set_primary_text (EActivity *activity, + const gchar *primary_text); +const gchar * e_activity_get_secondary_text (EActivity *activity); +void e_activity_set_secondary_text (EActivity *activity, + const gchar *secondary_text); + +G_END_DECLS + +#endif /* E_ACTIVITY_H */ diff --git a/widgets/misc/e-alert-activity.c b/widgets/misc/e-alert-activity.c new file mode 100644 index 0000000000..1e8f915213 --- /dev/null +++ b/widgets/misc/e-alert-activity.c @@ -0,0 +1,258 @@ +/* + * e-alert-activity.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-alert-activity.h" + +#define E_ALERT_ACTIVITY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivityPrivate)) + +struct _EAlertActivityPrivate { + GtkWidget *message_dialog; +}; + +enum { + PROP_0, + PROP_MESSAGE_DIALOG +}; + +static gpointer parent_class; + +static void +alert_activity_set_message_dialog (EAlertActivity *alert_activity, + GtkWidget *message_dialog) +{ + g_return_if_fail (alert_activity->priv->message_dialog == NULL); + + alert_activity->priv->message_dialog = g_object_ref (message_dialog); +} + +static void +alert_activity_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_MESSAGE_DIALOG: + alert_activity_set_message_dialog ( + E_ALERT_ACTIVITY (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +alert_activity_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_MESSAGE_DIALOG: + g_value_set_object ( + value, e_alert_activity_get_message_dialog ( + E_ALERT_ACTIVITY (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +alert_activity_dispose (GObject *object) +{ + EAlertActivityPrivate *priv; + + priv = E_ALERT_ACTIVITY_GET_PRIVATE (object); + + if (priv->message_dialog != NULL) { + g_object_unref (priv->message_dialog); + priv->message_dialog = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +alert_activity_constructed (GObject *object) +{ + EActivity *activity; + EAlertActivity *alert_activity; + GtkWidget *message_dialog; + const gchar *primary_text; + const gchar *secondary_text; + + alert_activity = E_ALERT_ACTIVITY (object); + message_dialog = e_alert_activity_get_message_dialog (alert_activity); + + object = G_OBJECT (message_dialog); + primary_text = g_object_get_data (object, "primary"); + secondary_text = g_object_get_data (object, "secondary"); + + activity = E_ACTIVITY (alert_activity); + e_activity_set_primary_text (activity, primary_text); + e_activity_set_secondary_text (activity, secondary_text); + + /* This is a constructor property, so can't do it in init(). + * XXX What we really want to do is override the property's + * default value, but GObject does not support that. */ + e_activity_set_clickable (E_ACTIVITY (alert_activity), TRUE); +} + +static void +alert_activity_clicked (EActivity *activity) +{ + EAlertActivity *alert_activity; + GtkWidget *message_dialog; + + e_activity_complete (activity); + + alert_activity = E_ALERT_ACTIVITY (activity); + message_dialog = e_alert_activity_get_message_dialog (alert_activity); + gtk_dialog_run (GTK_DIALOG (message_dialog)); + gtk_widget_hide (message_dialog); + + /* Chain up to parent's clicked() method. */ + E_ACTIVITY_CLASS (parent_class)->clicked (activity); +} + +static void +alert_activity_timeout (ETimeoutActivity *activity) +{ + e_activity_complete (E_ACTIVITY (activity)); + + /* Chain up to parent's timeout() method. */ + E_TIMEOUT_ACTIVITY_CLASS (parent_class)->timeout (activity); +} + +static void +alert_activity_class_init (EAlertActivityClass *class) +{ + GObjectClass *object_class; + EActivityClass *activity_class; + ETimeoutActivityClass *timeout_activity_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EAlertActivityPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = alert_activity_set_property; + object_class->get_property = alert_activity_get_property; + object_class->dispose = alert_activity_dispose; + object_class->constructed = alert_activity_constructed; + + activity_class = E_ACTIVITY_CLASS (class); + activity_class->clicked = alert_activity_clicked; + + timeout_activity_class = E_TIMEOUT_ACTIVITY_CLASS (class); + timeout_activity_class->timeout = alert_activity_timeout; + + g_object_class_install_property ( + object_class, + PROP_MESSAGE_DIALOG, + g_param_spec_object ( + "message-dialog", + NULL, + NULL, + GTK_TYPE_DIALOG, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); +} + +static void +alert_activity_init (EAlertActivity *alert_activity) +{ + alert_activity->priv = E_ALERT_ACTIVITY_GET_PRIVATE (alert_activity); + + e_timeout_activity_set_timeout (E_TIMEOUT_ACTIVITY (alert_activity), 60); +} + +GType +e_alert_activity_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EAlertActivityClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) alert_activity_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EAlertActivity), + 0, /* n_preallocs */ + (GInstanceInitFunc) alert_activity_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + E_TYPE_TIMEOUT_ACTIVITY, "EAlertActivity", + &type_info, 0); + } + + return type; +} + +EActivity * +e_alert_activity_new_info (GtkWidget *message_dialog) +{ + g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL); + + return g_object_new ( + E_TYPE_ALERT_ACTIVITY, + "icon-name", "dialog-information", + "message-dialog", message_dialog, NULL); +} + +EActivity * +e_alert_activity_new_error (GtkWidget *message_dialog) +{ + g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL); + + return g_object_new ( + E_TYPE_ALERT_ACTIVITY, + "icon-name", "dialog-error", + "message-dialog", message_dialog, NULL); +} + +EActivity * +e_alert_activity_new_warning (GtkWidget *message_dialog) +{ + g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL); + + return g_object_new ( + E_TYPE_ALERT_ACTIVITY, + "icon-name", "dialog-warning", + "message-dialog", message_dialog, NULL); +} + +GtkWidget * +e_alert_activity_get_message_dialog (EAlertActivity *alert_activity) +{ + g_return_val_if_fail (E_IS_ALERT_ACTIVITY (alert_activity), NULL); + + return alert_activity->priv->message_dialog; +} diff --git a/widgets/misc/e-alert-activity.h b/widgets/misc/e-alert-activity.h new file mode 100644 index 0000000000..5557094dda --- /dev/null +++ b/widgets/misc/e-alert-activity.h @@ -0,0 +1,70 @@ +/* + * e-alert-activity.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_ALERT_ACTIVITY_H +#define E_ALERT_ACTIVITY_H + +#include <e-timeout-activity.h> + +/* Standard GObject macros */ +#define E_TYPE_ALERT_ACTIVITY \ + (e_alert_activity_get_type ()) +#define E_ALERT_ACTIVITY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivity)) +#define E_ALERT_ACTIVITY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_ALERT_ACTIVITY, EAlertActivityClass)) +#define E_IS_ALERT_ACTIVITY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_ALERT_ACTIVITY)) +#define E_IS_ALERT_ACTIVITY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_ALERT_ACTIVITY)) +#define E_ALERT_ACTIVITY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivityClass)) + +G_BEGIN_DECLS + +typedef struct _EAlertActivity EAlertActivity; +typedef struct _EAlertActivityClass EAlertActivityClass; +typedef struct _EAlertActivityPrivate EAlertActivityPrivate; + +struct _EAlertActivity { + ETimeoutActivity parent; + EAlertActivityPrivate *priv; +}; + +struct _EAlertActivityClass { + ETimeoutActivityClass parent_class; +}; + +GType e_alert_activity_get_type (void); +EActivity * e_alert_activity_new_info (GtkWidget *message_dialog); +EActivity * e_alert_activity_new_error (GtkWidget *message_dialog); +EActivity * e_alert_activity_new_warning (GtkWidget *message_dialog); +GtkWidget * e_alert_activity_get_message_dialog + (EAlertActivity *alert_activity); + +G_END_DECLS + +#endif /* E_ALERT_ACTIVITY_H */ diff --git a/widgets/misc/e-calendar.h b/widgets/misc/e-calendar.h index 2ee002807a..d6b50209a7 100644 --- a/widgets/misc/e-calendar.h +++ b/widgets/misc/e-calendar.h @@ -37,9 +37,24 @@ G_BEGIN_DECLS * to got to the current day. */ -#define E_CALENDAR(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, e_calendar_get_type (), ECalendar) -#define E_CALENDAR_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, e_calendar_get_type (), ECalendarClass) -#define E_IS_CALENDAR(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, e_calendar_get_type ()) +/* Standard GObject macros */ +#define E_TYPE_CALENDAR \ + (e_calendar_get_type ()) +#define E_CALENDAR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_CALENDAR, ECalendar)) +#define E_CALENDAR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_CALENDAR, ECalendarClass)) +#define E_IS_CALENDAR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_CALENDAR)) +#define E_IS_CALENDAR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_CALENDAR)) +#define E_CALENDAR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_CALENDAR, ECalendarClass)) typedef struct _ECalendar ECalendar; typedef struct _ECalendarClass ECalendarClass; diff --git a/widgets/misc/e-charset-combo-box.c b/widgets/misc/e-charset-combo-box.c new file mode 100644 index 0000000000..9c992ce1f7 --- /dev/null +++ b/widgets/misc/e-charset-combo-box.c @@ -0,0 +1,428 @@ +/* + * e-charset-combo-box.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-charset-combo-box.h" + +#include <glib/gi18n.h> + +#include "e-util/e-charset.h" +#include "e-util/e-util.h" + +#define E_CHARSET_COMBO_BOX_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_CHARSET_COMBO_BOX, ECharsetComboBoxPrivate)) + +#define DEFAULT_CHARSET "UTF-8" +#define OTHER_VALUE G_MAXINT + +struct _ECharsetComboBoxPrivate { + GtkActionGroup *action_group; + GtkRadioAction *other_action; + GHashTable *charset_index; + + /* Used when the user clicks Cancel in the character set + * dialog. Reverts to the previous combo box setting. */ + gint previous_index; + + /* When setting the character set programmatically, this + * prevents the custom character set dialog from running. */ + guint block_dialog : 1; +}; + +enum { + PROP_0, + PROP_CHARSET +}; + +static gpointer parent_class; + +static void +charset_combo_box_entry_changed_cb (GtkEntry *entry, + GtkDialog *dialog) +{ + const gchar *text; + gboolean sensitive; + + text = gtk_entry_get_text (entry); + sensitive = (text != NULL && *text != '\0'); + gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_OK, sensitive); +} + +static void +charset_combo_box_run_dialog (ECharsetComboBox *combo_box) +{ + GtkDialog *dialog; + GtkEntry *entry; + GtkWidget *container; + GtkWidget *widget; + GObject *object; + gpointer parent; + const gchar *charset; + + /* FIXME Using a dialog for this is lame. Selecting "Other..." + * should unlock an entry directly in the Preferences tab. + * Unfortunately space in Preferences is at a premium right + * now, but we should revisit this when the space issue is + * finally resolved. */ + + parent = gtk_widget_get_toplevel (GTK_WIDGET (combo_box)); + parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; + + object = G_OBJECT (combo_box->priv->other_action); + charset = g_object_get_data (object, "charset"); + + widget = gtk_dialog_new_with_buttons ( + _("Character Encoding"), parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); + + /* Load the broken border width defaults so we can override them. */ + gtk_widget_ensure_style (widget); + + dialog = GTK_DIALOG (widget); + + gtk_dialog_set_has_separator (dialog, FALSE); + gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK); + + gtk_container_set_border_width (GTK_CONTAINER (dialog), 12); + + widget = gtk_dialog_get_action_area (dialog); + gtk_container_set_border_width (GTK_CONTAINER (widget), 0); + + widget = gtk_dialog_get_content_area (dialog); + gtk_box_set_spacing (GTK_BOX (widget), 12); + gtk_container_set_border_width (GTK_CONTAINER (widget), 0); + + container = widget; + + widget = gtk_label_new (_("Enter the character set to use")); + gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0); + gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 12, 0); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_entry_new (); + entry = GTK_ENTRY (widget); + gtk_entry_set_activates_default (entry, TRUE); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + g_signal_connect ( + entry, "changed", + G_CALLBACK (charset_combo_box_entry_changed_cb), dialog); + + /* Set the default text -after- connecting the signal handler. + * This will initialize the "OK" button to the proper state. */ + gtk_entry_set_text (entry, charset); + + if (gtk_dialog_run (dialog) != GTK_RESPONSE_OK) { + gint active; + + /* Revert to the previously selected character set. */ + combo_box->priv->block_dialog = TRUE; + active = combo_box->priv->previous_index; + gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), active); + combo_box->priv->block_dialog = FALSE; + + goto exit; + } + + charset = gtk_entry_get_text (entry); + g_return_if_fail (charset != NULL && charset != '\0'); + + g_object_set_data_full ( + object, "charset", g_strdup (charset), + (GDestroyNotify) g_free); + +exit: + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +static void +charset_combo_box_notify_charset_cb (ECharsetComboBox *combo_box) +{ + GtkToggleAction *action; + + action = GTK_TOGGLE_ACTION (combo_box->priv->other_action); + if (!gtk_toggle_action_get_active (action)) + return; + + if (combo_box->priv->block_dialog) + return; + + /* "Other" action was selected by user. */ + charset_combo_box_run_dialog (combo_box); +} + +static void +charset_combo_box_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CHARSET: + e_charset_combo_box_set_charset ( + E_CHARSET_COMBO_BOX (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +charset_combo_box_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CHARSET: + g_value_set_string ( + value, e_charset_combo_box_get_charset ( + E_CHARSET_COMBO_BOX (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +charset_combo_box_dispose (GObject *object) +{ + ECharsetComboBoxPrivate *priv; + + priv = E_CHARSET_COMBO_BOX_GET_PRIVATE (object); + + if (priv->action_group != NULL) { + g_object_unref (priv->action_group); + priv->action_group = NULL; + } + + if (priv->other_action != NULL) { + g_object_unref (priv->other_action); + priv->other_action = NULL; + } + + g_hash_table_remove_all (priv->charset_index); + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +charset_combo_box_finalize (GObject *object) +{ + ECharsetComboBoxPrivate *priv; + + priv = E_CHARSET_COMBO_BOX_GET_PRIVATE (object); + + g_hash_table_destroy (priv->charset_index); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +charset_combo_box_changed (GtkComboBox *combo_box) +{ + ECharsetComboBoxPrivate *priv; + + priv = E_CHARSET_COMBO_BOX_GET_PRIVATE (combo_box); + + /* Chain up to parent's changed() method. */ + GTK_COMBO_BOX_CLASS (parent_class)->changed (combo_box); + + /* Notify -before- updating previous index. */ + g_object_notify (G_OBJECT (combo_box), "charset"); + priv->previous_index = gtk_combo_box_get_active (combo_box); +} + +static void +charset_combo_box_class_init (ECharsetComboBoxClass *class) +{ + GObjectClass *object_class; + GtkComboBoxClass *combo_box_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (ECharsetComboBoxPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = charset_combo_box_set_property; + object_class->get_property = charset_combo_box_get_property; + object_class->dispose = charset_combo_box_dispose; + object_class->finalize = charset_combo_box_finalize; + + combo_box_class = GTK_COMBO_BOX_CLASS (class); + combo_box_class->changed = charset_combo_box_changed; + + g_object_class_install_property ( + object_class, + PROP_CHARSET, + g_param_spec_string ( + "charset", + "Charset", + "The selected character set", + "UTF-8", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +charset_combo_box_init (ECharsetComboBox *combo_box) +{ + GtkActionGroup *action_group; + GtkRadioAction *radio_action; + GHashTable *charset_index; + GSList *group, *iter; + + action_group = gtk_action_group_new ("charset-combo-box-internal"); + + charset_index = g_hash_table_new_full ( + g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); + + combo_box->priv = E_CHARSET_COMBO_BOX_GET_PRIVATE (combo_box); + combo_box->priv->action_group = action_group; + combo_box->priv->charset_index = charset_index; + + group = e_charset_add_radio_actions ( + action_group, "charset-", NULL, NULL, NULL); + + /* Populate the character set index. */ + for (iter = group; iter != NULL; iter = iter->next) { + GObject *object = iter->data; + const gchar *charset; + + charset = g_object_get_data (object, "charset"); + g_return_if_fail (charset != NULL); + + g_hash_table_insert ( + charset_index, g_strdup (charset), + g_object_ref (object)); + } + + /* Note the "other" action is not included in the index. */ + + radio_action = gtk_radio_action_new ( + "charset-other", _("Other..."), NULL, NULL, OTHER_VALUE); + + g_object_set_data (G_OBJECT (radio_action), "charset", (gpointer) ""); + + gtk_radio_action_set_group (radio_action, group); + group = gtk_radio_action_get_group (radio_action); + + e_action_combo_box_set_action ( + E_ACTION_COMBO_BOX (combo_box), radio_action); + + e_action_combo_box_add_separator_after ( + E_ACTION_COMBO_BOX (combo_box), g_slist_length (group)); + + g_signal_connect ( + combo_box, "notify::charset", + G_CALLBACK (charset_combo_box_notify_charset_cb), NULL); + + combo_box->priv->other_action = radio_action; +} + +GType +e_charset_combo_box_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (ECharsetComboBoxClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) charset_combo_box_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (ECharsetComboBox), + 0, /* n_preallocs */ + (GInstanceInitFunc) charset_combo_box_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + E_TYPE_ACTION_COMBO_BOX, "ECharsetComboBox", + &type_info, 0); + } + + return type; +} + +GtkWidget * +e_charset_combo_box_new (void) +{ + return g_object_new (E_TYPE_CHARSET_COMBO_BOX, NULL); +} + +const gchar * +e_charset_combo_box_get_charset (ECharsetComboBox *combo_box) +{ + GtkRadioAction *radio_action; + + g_return_val_if_fail (E_IS_CHARSET_COMBO_BOX (combo_box), NULL); + + radio_action = combo_box->priv->other_action; + radio_action = e_radio_action_get_current_action (radio_action); + + return g_object_get_data (G_OBJECT (radio_action), "charset"); +} + +void +e_charset_combo_box_set_charset (ECharsetComboBox *combo_box, + const gchar *charset) +{ + GHashTable *charset_index; + GtkRadioAction *radio_action; + + g_return_if_fail (E_IS_CHARSET_COMBO_BOX (combo_box)); + + if (charset == NULL || *charset == '\0') + charset = "UTF-8"; + + charset_index = combo_box->priv->charset_index; + radio_action = g_hash_table_lookup (charset_index, charset); + + if (radio_action == NULL) { + radio_action = combo_box->priv->other_action; + g_object_set_data_full ( + G_OBJECT (radio_action), + "charset", g_strdup (charset), + (GDestroyNotify) g_free); + } + + combo_box->priv->block_dialog = TRUE; + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (radio_action), TRUE); + combo_box->priv->block_dialog = FALSE; +} diff --git a/widgets/misc/e-charset-combo-box.h b/widgets/misc/e-charset-combo-box.h new file mode 100644 index 0000000000..471dfa6a54 --- /dev/null +++ b/widgets/misc/e-charset-combo-box.h @@ -0,0 +1,69 @@ +/* + * e-charset-combo-box.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_CHARSET_COMBO_BOX_H +#define E_CHARSET_COMBO_BOX_H + +#include <misc/e-action-combo-box.h> + +/* Standard GObject macros */ +#define E_TYPE_CHARSET_COMBO_BOX \ + (e_charset_combo_box_get_type ()) +#define E_CHARSET_COMBO_BOX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_CHARSET_COMBO_BOX, ECharsetComboBox)) +#define E_CHARSET_COMBO_BOX_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_CHARSET_COMBO_BOX, ECharsetComboBoxClass)) +#define E_IS_CHARSET_COMBO_BOX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_CHARSET_COMBO_BOX)) +#define E_IS_CHARSET_COMBO_BOX_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_CHARSET_COMBO_BOX)) +#define E_CHARSET_COMBO_BOX_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_CHARSET_COMBO_BOX, ECharsetComboBoxClass)) + +G_BEGIN_DECLS + +typedef struct _ECharsetComboBox ECharsetComboBox; +typedef struct _ECharsetComboBoxClass ECharsetComboBoxClass; +typedef struct _ECharsetComboBoxPrivate ECharsetComboBoxPrivate; + +struct _ECharsetComboBox { + EActionComboBox parent; + ECharsetComboBoxPrivate *priv; +}; + +struct _ECharsetComboBoxClass { + EActionComboBoxClass parent_class; +}; + +GType e_charset_combo_box_get_type (void); +GtkWidget * e_charset_combo_box_new (void); +const gchar * e_charset_combo_box_get_charset (ECharsetComboBox *combo_box); +void e_charset_combo_box_set_charset (ECharsetComboBox *combo_box, + const gchar *charset); + +G_END_DECLS + +#endif /* E_CHARSET_COMBO_BOX_H */ diff --git a/widgets/misc/e-charset-picker.c b/widgets/misc/e-charset-picker.c deleted file mode 100644 index 53beaa9c11..0000000000 --- a/widgets/misc/e-charset-picker.c +++ /dev/null @@ -1,715 +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) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "e-charset-picker.h" -#include "e-util/e-dialog-utils.h" - -#include <string.h> -#include <iconv.h> - -#include <glib/gi18n-lib.h> - -#include <bonobo/bonobo-ui-node.h> -#include <bonobo/bonobo-ui-util.h> - -typedef enum { - E_CHARSET_UNKNOWN, - E_CHARSET_ARABIC, - E_CHARSET_BALTIC, - E_CHARSET_CENTRAL_EUROPEAN, - E_CHARSET_CHINESE, - E_CHARSET_CYRILLIC, - E_CHARSET_GREEK, - E_CHARSET_HEBREW, - E_CHARSET_JAPANESE, - E_CHARSET_KOREAN, - E_CHARSET_THAI, - E_CHARSET_TURKISH, - E_CHARSET_UNICODE, - E_CHARSET_WESTERN_EUROPEAN, - E_CHARSET_WESTERN_EUROPEAN_NEW -} ECharsetClass; - -static const gchar *classnames[] = { - N_("Unknown"), - N_("Arabic"), - N_("Baltic"), - N_("Central European"), - N_("Chinese"), - N_("Cyrillic"), - N_("Greek"), - N_("Hebrew"), - N_("Japanese"), - N_("Korean"), - N_("Thai"), - N_("Turkish"), - N_("Unicode"), - N_("Western European"), - N_("Western European, New"), -}; - -typedef struct { - const gchar *name; - ECharsetClass class; - const gchar *subclass; -} ECharset; - -/* This list is based on what other mailers/browsers support. There's - * not a lot of point in using, say, ISO-8859-3, if anything that can - * read that can read UTF8 too. - */ -/* To Translators: Character set "Logical Hebrew" */ -static ECharset charsets[] = { - { "ISO-8859-6", E_CHARSET_ARABIC, NULL }, - { "ISO-8859-13", E_CHARSET_BALTIC, NULL }, - { "ISO-8859-4", E_CHARSET_BALTIC, NULL }, - { "ISO-8859-2", E_CHARSET_CENTRAL_EUROPEAN, NULL }, - { "Big5", E_CHARSET_CHINESE, N_("Traditional") }, - { "BIG5HKSCS", E_CHARSET_CHINESE, N_("Traditional") }, - { "EUC-TW", E_CHARSET_CHINESE, N_("Traditional") }, - { "GB18030", E_CHARSET_CHINESE, N_("Simplified") }, - { "GB2312", E_CHARSET_CHINESE, N_("Simplified") }, - { "HZ", E_CHARSET_CHINESE, N_("Simplified") }, - { "ISO-2022-CN", E_CHARSET_CHINESE, N_("Simplified") }, - { "KOI8-R", E_CHARSET_CYRILLIC, NULL }, - { "Windows-1251", E_CHARSET_CYRILLIC, NULL }, - { "KOI8-U", E_CHARSET_CYRILLIC, N_("Ukrainian") }, - { "ISO-8859-5", E_CHARSET_CYRILLIC, NULL }, - { "ISO-8859-7", E_CHARSET_GREEK, NULL }, - { "ISO-8859-8", E_CHARSET_HEBREW, N_("Visual") }, - { "ISO-2022-JP", E_CHARSET_JAPANESE, NULL }, - { "EUC-JP", E_CHARSET_JAPANESE, NULL }, - { "Shift_JIS", E_CHARSET_JAPANESE, NULL }, - { "EUC-KR", E_CHARSET_KOREAN, NULL }, - { "TIS-620", E_CHARSET_THAI, NULL }, - { "ISO-8859-9", E_CHARSET_TURKISH, NULL }, - { "UTF-8", E_CHARSET_UNICODE, NULL }, - { "UTF-7", E_CHARSET_UNICODE, NULL }, - { "ISO-8859-1", E_CHARSET_WESTERN_EUROPEAN, NULL }, - { "ISO-8859-15", E_CHARSET_WESTERN_EUROPEAN_NEW, NULL }, -}; -static const gint num_charsets = sizeof (charsets) / sizeof (charsets[0]); - -static void -select_item (GtkMenuShell *menu_shell, GtkWidget *item) -{ - gtk_menu_shell_select_item (menu_shell, item); - gtk_menu_shell_deactivate (menu_shell); -} - -static void -activate (GtkWidget *item, gpointer menu) -{ - g_object_set_data ((GObject *) menu, "activated_item", item); -} - -static GtkWidget * -add_charset (GtkWidget *menu, ECharset *charset, gboolean free_name) -{ - GtkWidget *item; - gchar *label; - - if (charset->subclass) { - label = g_strdup_printf ("%s, %s (%s)", - _(classnames[charset->class]), - _(charset->subclass), - charset->name); - } else if (charset->class) { - label = g_strdup_printf ("%s (%s)", - _(classnames[charset->class]), - charset->name); - } else { - label = g_strdup (charset->name); - } - - item = gtk_menu_item_new_with_label (label); - g_object_set_data_full ((GObject *) item, "charset", - (gpointer) charset->name, free_name ? g_free : NULL); - g_free (label); - - gtk_widget_show (item); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - g_signal_connect (item, "activate", G_CALLBACK (activate), menu); - - return item; -} - -static gboolean -add_other_charset (GtkWidget *menu, GtkWidget *other, const gchar *new_charset) -{ - ECharset charset = { NULL, E_CHARSET_UNKNOWN, NULL }; - GtkWidget *item; - iconv_t ic; - - ic = iconv_open ("UTF-8", new_charset); - if (ic == (iconv_t)-1) { - GtkWidget *window = gtk_widget_get_ancestor (other, GTK_TYPE_WINDOW); - e_notice (window, GTK_MESSAGE_ERROR, - _("Unknown character set: %s"), new_charset); - return FALSE; - } - iconv_close (ic); - - /* Temporarily remove the "Other..." item */ - g_object_ref (other); - gtk_container_remove (GTK_CONTAINER (menu), other); - - /* Create new menu item */ - charset.name = g_strdup (new_charset); - item = add_charset (menu, &charset, TRUE); - - /* And re-add "Other..." */ - gtk_menu_shell_append (GTK_MENU_SHELL (menu), other); - g_object_unref (other); - - g_object_set_data_full ((GObject *) menu, "other_charset", - g_strdup (new_charset), g_free); - - g_object_set_data ((GObject *) menu, "activated_item", item); - select_item (GTK_MENU_SHELL (menu), item); - - return TRUE; -} - -static void -activate_entry (GtkWidget *entry, GtkDialog *dialog) -{ - gtk_dialog_response (dialog, GTK_RESPONSE_OK); -} - -static void -activate_other (GtkWidget *item, gpointer menu) -{ - GtkWidget *window, *entry, *label, *vbox, *hbox; - gchar *old_charset, *new_charset; - GtkDialog *dialog; - - window = gtk_widget_get_toplevel (menu); - if (!GTK_WIDGET_TOPLEVEL (window)) - window = gtk_widget_get_ancestor (item, GTK_TYPE_WINDOW); - - old_charset = g_object_get_data(menu, "other_charset"); - - dialog = GTK_DIALOG (gtk_dialog_new_with_buttons (_("Character Encoding"), - GTK_WINDOW (window), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, - NULL)); - - gtk_dialog_set_has_separator (dialog, FALSE); - gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK); - - vbox = gtk_vbox_new (FALSE, 6); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 12); - gtk_box_pack_start (GTK_BOX (dialog->vbox), vbox, TRUE, TRUE, 0); - gtk_widget_show (vbox); - - label = gtk_label_new (_("Enter the character set to use")); - gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); - gtk_widget_show (label); - - hbox = gtk_hbox_new (FALSE, 12); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - gtk_widget_show (hbox); - - label = gtk_label_new (""); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - gtk_widget_show (label); - - entry = gtk_entry_new (); - gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0); - gtk_widget_show (entry); - - if (old_charset) - gtk_entry_set_text (GTK_ENTRY (entry), old_charset); - g_signal_connect (entry, "activate", - G_CALLBACK (activate_entry), dialog); - - gtk_container_set_border_width (GTK_CONTAINER (dialog->vbox), 0); - gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 12); - - gtk_widget_show_all (GTK_WIDGET (dialog)); - - g_object_ref (dialog); - if (gtk_dialog_run (dialog) == GTK_RESPONSE_OK) { - new_charset = (gchar *)gtk_entry_get_text (GTK_ENTRY (entry)); - - if (*new_charset) { - if (add_other_charset (menu, item, new_charset)) { - gtk_widget_destroy (GTK_WIDGET (dialog)); - g_object_unref (dialog); - return; - } - } - } - gtk_widget_destroy (GTK_WIDGET (dialog)); - g_object_unref (dialog); - - /* Revert to previous selection */ - select_item (GTK_MENU_SHELL (menu), g_object_get_data(G_OBJECT(menu), "activated_item")); -} - -/** - * e_charset_picker_new: - * @default_charset: the default character set, or %NULL to use the - * locale character set. - * - * This creates an option menu widget and fills it in with a selection - * of available character sets. The @default_charset (or locale character - * set if @default_charset is %NULL) will be listed first, and selected - * by default (except that iso-8859-1 will always be used instead of - * US-ASCII). Any other character sets of the same language class as - * the default will be listed next, followed by the remaining character - * sets, a separator, and an "Other..." menu item, which can be used to - * select other charsets. - * - * Return value: an option menu widget, filled in and with signals - * attached. - */ -GtkWidget * -e_charset_picker_new (const gchar *default_charset) -{ - GtkWidget *menu, *item; - gint def, i; - const gchar *locale_charset; - - g_get_charset (&locale_charset); - if (!g_ascii_strcasecmp (locale_charset, "US-ASCII")) - locale_charset = "iso-8859-1"; - - if (!default_charset) - default_charset = locale_charset; - for (def = 0; def < num_charsets; def++) { - if (!g_ascii_strcasecmp (charsets[def].name, default_charset)) - break; - } - - menu = gtk_menu_new (); - for (i = 0; i < num_charsets; i++) { - item = add_charset (menu, &charsets[i], FALSE); - if (i == def) { - activate (item, menu); - select_item (GTK_MENU_SHELL (menu), item); - } - } - - /* do the Unknown/Other section */ - gtk_menu_shell_append (GTK_MENU_SHELL (menu), gtk_menu_item_new ()); - - if (def == num_charsets) { - ECharset other = { NULL, E_CHARSET_UNKNOWN, NULL }; - - /* Add an entry for @default_charset */ - other.name = g_strdup (default_charset); - item = add_charset (menu, &other, TRUE); - activate (item, menu); - select_item (GTK_MENU_SHELL (menu), item); - g_object_set_data_full ((GObject *) menu, "other_charset", - g_strdup (default_charset), g_free); - def++; - } - - item = gtk_menu_item_new_with_label (_("Other...")); - g_signal_connect (item, "activate", G_CALLBACK (activate_other), menu); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - - gtk_widget_show_all (menu); - - return menu; -} - -/** - * e_charset_picker_get_charset: - * @menu: a character set menu from e_charset_picker_new() - * - * Return value: the currently-selected character set in @picker, - * which must be freed with g_free(). - **/ -gchar * -e_charset_picker_get_charset (GtkWidget *menu) -{ - GtkWidget *item; - gchar *charset; - - g_return_val_if_fail (GTK_IS_MENU (menu), NULL); - - item = gtk_menu_get_active (GTK_MENU (menu)); - charset = g_object_get_data ((GObject *) item, "charset"); - - return g_strdup (charset); -} - -/** - * e_charset_picker_dialog: - * @title: title for the dialog box - * @prompt: prompt string for the dialog box - * @default_charset: as for e_charset_picker_new() - * @parent: a parent window for the dialog box, or %NULL - * - * This creates a new dialog box with the given @title and @prompt and - * a character set picker menu. It then runs the dialog and returns - * the selected character set, or %NULL if the user clicked "Cancel". - * - * Return value: the selected character set (which must be freed with - * g_free()), or %NULL. - **/ -gchar * -e_charset_picker_dialog (const gchar *title, const gchar *prompt, - const gchar *default_charset, GtkWindow *parent) -{ - GtkDialog *dialog; - GtkWidget *label, *omenu, *picker, *vbox, *hbox; - gchar *charset = NULL; - - dialog = GTK_DIALOG (gtk_dialog_new_with_buttons (title, - parent, - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, - NULL)); - - gtk_dialog_set_has_separator (dialog, FALSE); - gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK); - - vbox = gtk_vbox_new (FALSE, 6); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 12); - gtk_box_pack_start (GTK_BOX (dialog->vbox), vbox, FALSE, FALSE, 0); - gtk_widget_show (vbox); - - label = gtk_label_new (prompt); - gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); - gtk_widget_show (label); - - hbox = gtk_hbox_new (FALSE, 12); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - gtk_widget_show (hbox); - - label = gtk_label_new (""); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - gtk_widget_show (label); - - picker = e_charset_picker_new (default_charset); - omenu = gtk_option_menu_new (); - gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), picker); - gtk_box_pack_start (GTK_BOX (hbox), omenu, TRUE, TRUE, 0); - gtk_widget_show (omenu); - - gtk_container_set_border_width (GTK_CONTAINER (dialog->vbox), 0); - gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 12); - - gtk_widget_show_all (GTK_WIDGET (dialog)); - - g_object_ref (dialog); - - if (gtk_dialog_run (dialog) == GTK_RESPONSE_OK) - charset = e_charset_picker_get_charset (picker); - - gtk_widget_destroy (GTK_WIDGET (dialog)); - g_object_unref (dialog); - - return charset; -} - -/** - * e_charset_add_radio_actions: - * @action_group: a #GtkActionGroup - * @default_charset: the default character set, or %NULL to use the - * locale character set - * @callback: a callback function for actions in the group, or %NULL - * @user_data: user data to be passed to @callback, or %NULL - * - * Adds a set of #GtkRadioActions for available character sets to - * @action_group. The @default_charset (or locale character set if - * @default_charset is %NULL) will be added first, and selected by - * default (except that iso-8859-1 will always be used instead of - * US-ASCII). Any other character sets of the same language class as - * the default will be added next, followed by the remaining character - * sets. - **/ -void -e_charset_add_radio_actions (GtkActionGroup *action_group, - const gchar *default_charset, - GCallback callback, - gpointer user_data) -{ - GtkRadioAction *action = NULL; - GSList *group = NULL; - const gchar *locale_charset; - gint def, ii; - - g_return_if_fail (GTK_IS_ACTION_GROUP (action_group)); - - /* XXX I could try to factor out code common to this - * function and e_charset_picker_bonobo_ui_populate() - * instead of duplicating it, but I expect the latter - * function to be obsolete in the foreseeable future. */ - - g_get_charset (&locale_charset); - if (!g_ascii_strcasecmp (locale_charset, "US-ASCII")) - locale_charset = "iso-8859-1"; - - if (default_charset == NULL) - default_charset = locale_charset; - for (def = 0; def < G_N_ELEMENTS (charsets); def++) - if (!g_ascii_strcasecmp (charsets[def].name, default_charset)) - break; - - for (ii = 0; ii < G_N_ELEMENTS (charsets); ii++) { - gchar *escaped_name; - gchar *charset_label; - gchar **str_array; - - /* Escape underlines in the character set name so - * they're not treated as GtkLabel mnemonics. */ - str_array = g_strsplit (charsets[ii].name, "_", -1); - escaped_name = g_strjoinv ("__", str_array); - g_strfreev (str_array); - - if (charsets[ii].subclass != NULL) - charset_label = g_strdup_printf ( - "%s, %s (%s)", - gettext (classnames[charsets[ii].class]), - gettext (charsets[ii].subclass), - escaped_name); - else if (charsets[ii].class != E_CHARSET_UNKNOWN) - charset_label = g_strdup_printf ( - "%s (%s)", - gettext (classnames[charsets[ii].class]), - escaped_name); - else - charset_label = g_strdup (escaped_name); - - action = gtk_radio_action_new ( - charsets[ii].name, charset_label, NULL, NULL, ii); - - gtk_radio_action_set_group (action, group); - group = gtk_radio_action_get_group (action); - - if (callback != NULL) - g_signal_connect ( - action, "changed", callback, user_data); - - gtk_action_group_add_action ( - action_group, GTK_ACTION (action)); - - g_object_unref (action); - - g_free (escaped_name); - g_free (charset_label); - } - - if (def == G_N_ELEMENTS (charsets)) { - gchar *charset_label; - gchar **str_array; - - /* Escape underlines in the character set name so - * they're not treated as GtkLabel mnemonics. */ - str_array = g_strsplit (default_charset, "_", -1); - charset_label = g_strjoinv ("__", str_array); - g_strfreev (str_array); - - action = gtk_radio_action_new ( - default_charset, charset_label, NULL, NULL, def); - - gtk_radio_action_set_group (action, group); - group = gtk_radio_action_get_group (action); - - if (callback != NULL) - g_signal_connect ( - action, "changed", callback, user_data); - - gtk_action_group_add_action ( - action_group, GTK_ACTION (action)); - - g_object_unref (action); - - g_free (charset_label); - } - - /* Any of the actions in the action group will do. */ - if (action != NULL) - gtk_radio_action_set_current_value (action, def); -} - -/** - * e_charset_picker_bonobo_ui_populate: - * @uic: Bonobo UI Component - * @path: menu path - * @default_charset: the default character set, or %NULL to use the - * locale character set. - * @cb: Callback function - * @user_data: data to be passed to the callback. - * - * This creates a Bonobo UI menu and fills it in with a selection - * of available character sets. The @default_charset (or locale character - * set if @default_charset is %NULL) will be listed first, and selected - * by default (except that iso-8859-1 will always be used instead of - * US-ASCII). Any other character sets of the same language class as - * the default will be listed next, followed by the remaining character - * sets. - **/ -void -e_charset_picker_bonobo_ui_populate (BonoboUIComponent *uic, const gchar *path, - const gchar *default_charset, - BonoboUIListenerFn cb, gpointer user_data) -{ - gchar *encoded_label, *label; - const gchar *locale_charset; - GString *menuitems; - gint def, i; - - g_get_charset (&locale_charset); - if (!g_ascii_strcasecmp (locale_charset, "US-ASCII")) - locale_charset = "iso-8859-1"; - - if (!default_charset) - default_charset = locale_charset; - for (def = 0; def < num_charsets; def++) { - if (!g_ascii_strcasecmp (charsets[def].name, default_charset)) - break; - } - - label = g_strdup (_("Ch_aracter Encoding")); - encoded_label = bonobo_ui_util_encode_str (label); - menuitems = g_string_new (""); - g_string_append_printf (menuitems, "<submenu name=\"ECharsetPicker\" label=\"%s\">\n", - encoded_label); - g_free (encoded_label); - g_free (label); - - for (i = 0; i < num_charsets; i++) { - gchar *charset_name; - gchar *command, *u; - - /* escape _'s in the charset name so that it doesn't become an underline in a GtkLabel */ - if ((u = strchr (charsets[i].name, '_'))) { - gint extra = 1; - const gchar *s; - gchar *d; - - while ((u = strchr (u + 1, '_'))) - extra++; - - d = charset_name = g_alloca (strlen (charsets[i].name) + extra + 1); - s = charsets[i].name; - while (*s != '\0') { - if (*s == '_') - *d++ = '_'; - *d++ = *s++; - } - *d = '\0'; - } else { - charset_name = (gchar *) charsets[i].name; - } - - if (charsets[i].subclass) { - label = g_strdup_printf ("%s, %s (%s)", - _(classnames[charsets[i].class]), - _(charsets[i].subclass), - charset_name); - } else if (charsets[i].class) { - label = g_strdup_printf ("%s (%s)", - _(classnames[charsets[i].class]), - charset_name); - } else { - label = g_strdup (charset_name); - } - - encoded_label = bonobo_ui_util_encode_str (label); - g_free (label); - - command = g_strdup_printf ("<cmd name=\"Charset-%s\" label=\"%s\" type=\"radio\"" - " group=\"charset_picker\" state=\"%d\"/>\n", - charsets[i].name, encoded_label, i == def); - - bonobo_ui_component_set (uic, "/commands", command, NULL); - g_free (command); - - g_string_append_printf (menuitems, " <menuitem name=\"Charset-%s\" verb=\"\"/>\n", - charsets[i].name); - - g_free (encoded_label); - - label = g_strdup_printf ("Charset-%s", charsets[i].name); - bonobo_ui_component_add_listener (uic, label, cb, user_data); - g_free (label); - } - - if (def == num_charsets) { - gchar *command; - gchar *charset_name, *u; - - /* escape _'s in the charset name so that it doesn't become an underline in a GtkLabel */ - if ((u = strchr (default_charset, '_'))) { - gint extra = 1; - gchar *s, *d; - - while ((u = strchr (u + 1, '_'))) - extra++; - - d = charset_name = g_alloca (strlen (default_charset) + extra + 1); - s = (gchar *) default_charset; - while (*s != '\0') { - if (*s == '_') - *d++ = '_'; - *d++ = *s++; - } - *d = '\0'; - } else { - charset_name = (gchar *) default_charset; - } - - label = g_strdup (charset_name); - encoded_label = bonobo_ui_util_encode_str (label); - g_free (label); - - command = g_strdup_printf ("<cmd name=\"Charset-%s\" label=\"%s\" type=\"radio\"" - " group=\"charset_picker\" state=\"1\"/>\n", - default_charset, encoded_label); - - bonobo_ui_component_set (uic, "/commands", command, NULL); - g_free (command); - - g_string_append (menuitems, " <separator/>\n"); - g_string_append_printf (menuitems, " <menuitem name=\"Charset-%s\" verb=\"\"/>\n", - default_charset); - - g_free (encoded_label); - - label = g_strdup_printf ("Charset-%s", default_charset); - bonobo_ui_component_add_listener (uic, label, cb, user_data); - g_free (label); - } - - g_string_append (menuitems, "</submenu>\n"); - - bonobo_ui_component_set (uic, path, menuitems->str, NULL); - g_string_free (menuitems, TRUE); -} diff --git a/widgets/misc/e-charset-picker.h b/widgets/misc/e-charset-picker.h deleted file mode 100644 index 04c013bd88..0000000000 --- a/widgets/misc/e-charset-picker.h +++ /dev/null @@ -1,50 +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/> - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef E_CHARSETPICKER_H -#define E_CHARSETPICKER_H - -#include <gtk/gtk.h> -#include <bonobo/bonobo-ui-component.h> - -G_BEGIN_DECLS - -GtkWidget * e_charset_picker_new (const gchar *default_charset); -gchar * e_charset_picker_get_charset (GtkWidget *picker); -gchar * e_charset_picker_dialog (const gchar *title, - const gchar *prompt, - const gchar *default_charset, - GtkWindow *parent); - -void e_charset_add_radio_actions (GtkActionGroup *action_group, - const gchar *default_charset, - GCallback callback, - gpointer user_data); - -void e_charset_picker_bonobo_ui_populate - (BonoboUIComponent *uic, - const gchar *path, - const gchar *default_charset, - BonoboUIListenerFn cb, - gpointer user_data); - -G_END_DECLS - -#endif /* E_CHARSETPICKER_H */ diff --git a/widgets/misc/e-combo-button.c b/widgets/misc/e-combo-button.c deleted file mode 100644 index 3caf793611..0000000000 --- a/widgets/misc/e-combo-button.c +++ /dev/null @@ -1,625 +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) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "e-combo-button.h" -#include "ea-widgets.h" - -struct _EComboButtonPrivate { - GdkPixbuf *icon; - - GtkWidget *icon_image; - GtkWidget *label; - GtkWidget *arrow_image; - GtkWidget *hbox; - GtkWidget *vbox; - - GtkMenu *menu; - - gboolean menu_popped_up; - gboolean is_already_packed; -}; - -#define SPACING 2 - -enum { - ACTIVATE_DEFAULT, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE (EComboButton, e_combo_button, GTK_TYPE_BUTTON) - -/* Utility functions. */ - -static void -set_icon (EComboButton *combo_button, - GdkPixbuf *pixbuf) -{ - EComboButtonPrivate *priv; - - priv = combo_button->priv; - - if (priv->icon != NULL) - g_object_unref (priv->icon); - - if (pixbuf == NULL) { - priv->icon = NULL; - gtk_widget_hide (priv->icon_image); - return; - } - - priv->icon = g_object_ref (pixbuf); - - gtk_image_set_from_pixbuf (GTK_IMAGE (priv->icon_image), priv->icon); - - gtk_widget_show (priv->icon_image); -} - - -/* Paint the borders. */ - -static void -paint (EComboButton *combo_button, - GdkRectangle *area) -{ - EComboButtonPrivate *priv = combo_button->priv; - GtkWidget *widget = GTK_WIDGET (combo_button); - GtkButton *button = GTK_BUTTON (combo_button); - GtkShadowType shadow_type; - gboolean interior_focus; - gint separator_x; - gint focus_width, focus_pad; - gint x, y, width, height; - gint border_width; - - if (GTK_BUTTON (widget)->depressed || priv->menu_popped_up) { - shadow_type = GTK_SHADOW_IN; - gtk_widget_set_state (widget, GTK_STATE_ACTIVE); - } else if (GTK_BUTTON (widget)->relief == GTK_RELIEF_NONE && - (GTK_WIDGET_STATE (widget) == GTK_STATE_NORMAL || - GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE)) - shadow_type = GTK_SHADOW_NONE; - else - shadow_type = GTK_SHADOW_OUT; - - border_width = GTK_CONTAINER (widget)->border_width; - - x = widget->allocation.x + border_width; - y = widget->allocation.y + border_width; - width = widget->allocation.width - border_width * 2; - height = widget->allocation.height - border_width * 2; - - separator_x = (priv->label->allocation.width - + priv->label->allocation.x - + priv->arrow_image->allocation.x) / 2; - - gtk_widget_style_get (GTK_WIDGET (widget), - "focus-line-width", &focus_width, - "focus-padding", &focus_pad, - "interior-focus", &interior_focus, - NULL); - - if (GTK_WIDGET_HAS_DEFAULT (widget) - && GTK_BUTTON (widget)->relief == GTK_RELIEF_NORMAL) - gtk_paint_box (widget->style, widget->window, - GTK_STATE_NORMAL, GTK_SHADOW_IN, - area, widget, "buttondefault", - x, y, width, height); - - if (!interior_focus && GTK_WIDGET_HAS_FOCUS (widget)) { - x += focus_width + focus_pad; - y += focus_width + focus_pad; - width -= 2 * (focus_width + focus_pad); - height -= 2 * (focus_width + focus_pad); - } - - if (button->relief != GTK_RELIEF_NONE || button->depressed || - priv->menu_popped_up || - GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT) { - - gtk_paint_box (widget->style, widget->window, - GTK_WIDGET_STATE (widget), shadow_type, - area, widget, "button", - x, y, separator_x, height); - - if (width - separator_x > 0) - gtk_paint_box (widget->style, widget->window, - GTK_WIDGET_STATE (widget), shadow_type, - area, widget, "button", - separator_x, y, width - separator_x, height); - } - - if (GTK_WIDGET_HAS_FOCUS (widget)) { - if (interior_focus) { - x += widget->style->xthickness + focus_pad; - y += widget->style->ythickness + focus_pad; - width -= 2 * (widget->style->xthickness + focus_pad); - height -= 2 * (widget->style->xthickness + focus_pad); - } else { - x -= focus_width + focus_pad; - y -= focus_width + focus_pad; - width += 2 * (focus_width + focus_pad); - height += 2 * (focus_width + focus_pad); - } - - gtk_paint_focus (widget->style, widget->window, - GTK_WIDGET_STATE (widget), - area, widget, "button", - x, y, width, height); - } -} - - -/* Callbacks for the associated menu. */ - -static void -menu_detacher (GtkWidget *widget, - GtkMenu *menu) -{ - EComboButton *combo_button; - EComboButtonPrivate *priv; - - combo_button = E_COMBO_BUTTON (widget); - priv = combo_button->priv; - g_signal_handlers_disconnect_matched (menu, - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - combo_button); - priv->menu = NULL; -} - -static void -menu_deactivate_callback (GtkMenuShell *menu_shell, - gpointer data) -{ - EComboButton *combo_button; - EComboButtonPrivate *priv; - - combo_button = E_COMBO_BUTTON (data); - priv = combo_button->priv; - - priv->menu_popped_up = FALSE; - - GTK_BUTTON (combo_button)->button_down = FALSE; - GTK_BUTTON (combo_button)->in_button = FALSE; - gtk_button_leave (GTK_BUTTON (combo_button)); - gtk_button_clicked (GTK_BUTTON (combo_button)); -} - -static void -menu_position_func (GtkMenu *menu, - gint *x_return, - gint *y_return, - gboolean *push_in, - gpointer data) -{ - EComboButton *combo_button; - GtkAllocation *allocation; - - combo_button = E_COMBO_BUTTON (data); - allocation = & (GTK_WIDGET (combo_button)->allocation); - - gdk_window_get_origin (GTK_WIDGET (combo_button)->window, x_return, y_return); - - *y_return += allocation->height; -} - - -/* GtkObject methods. */ - -static void -impl_destroy (GtkObject *object) -{ - EComboButton *combo_button; - EComboButtonPrivate *priv; - - combo_button = E_COMBO_BUTTON (object); - priv = combo_button->priv; - - if (priv) { - if (priv->arrow_image != NULL) { - gtk_widget_destroy (priv->arrow_image); - priv->arrow_image = NULL; - } - - if (priv->icon != NULL) { - g_object_unref (priv->icon); - priv->icon = NULL; - } - - g_free (priv); - combo_button->priv = NULL; - } - - (* GTK_OBJECT_CLASS (e_combo_button_parent_class)->destroy) (object); -} - - - -static gboolean -e_combo_button_popup (EComboButton *combo_button, GdkEventButton *event) -{ - EComboButtonPrivate *priv; - - g_return_val_if_fail (combo_button != NULL, FALSE); - g_return_val_if_fail (E_IS_COMBO_BUTTON (combo_button), FALSE); - - priv = combo_button->priv; - - priv->menu_popped_up = TRUE; - - if (event) - gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL, - menu_position_func, combo_button, - event->button, event->time); - else - gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL, - menu_position_func, combo_button, - 0, gtk_get_current_event_time()); - - return TRUE; -} -/* GtkWidget methods. */ - -static gint -impl_button_press_event (GtkWidget *widget, - GdkEventButton *event) -{ - EComboButton *combo_button; - EComboButtonPrivate *priv; - - combo_button = E_COMBO_BUTTON (widget); - priv = combo_button->priv; - - if (event->type == GDK_BUTTON_PRESS && - (event->button == 1 || event->button == 3)) { - GTK_BUTTON (widget)->button_down = TRUE; - - if (event->button == 3 || - event->x >= priv->arrow_image->allocation.x) { - /* User clicked on the right side: pop up the menu. */ - gtk_button_pressed (GTK_BUTTON (widget)); - - e_combo_button_popup (combo_button, event); - } else { - /* User clicked on the left side: just behave like a - normal button (i.e. not a toggle). */ - gtk_button_pressed (GTK_BUTTON (widget)); - } - } - - return TRUE; -} - -static gint -impl_leave_notify_event (GtkWidget *widget, - GdkEventCrossing *event) -{ - EComboButton *combo_button; - EComboButtonPrivate *priv; - - combo_button = E_COMBO_BUTTON (widget); - priv = combo_button->priv; - - /* This is to override the standard behavior of deactivating the button - when the pointer gets out of the widget, in the case in which we - have just popped up the menu. Otherwise, the button would look as - inactive when the menu is popped up. */ - if (! priv->menu_popped_up) - return (* GTK_WIDGET_CLASS (e_combo_button_parent_class)->leave_notify_event) (widget, event); - - return FALSE; -} - -static gint -impl_expose_event (GtkWidget *widget, - GdkEventExpose *event) -{ - GtkBin *bin; - GdkEventExpose child_event; - - if (! GTK_WIDGET_DRAWABLE (widget)) - return FALSE; - - bin = GTK_BIN (widget); - - paint (E_COMBO_BUTTON (widget), &event->area); - - child_event = *event; - if (bin->child && GTK_WIDGET_NO_WINDOW (bin->child) && - gtk_widget_intersect (bin->child, &event->area, &child_event.area)) - gtk_container_propagate_expose (GTK_CONTAINER (widget), bin->child, &child_event); - - return FALSE; -} - - -/* GtkButton methods. */ - -static void -impl_released (GtkButton *button) -{ - EComboButton *combo_button; - EComboButtonPrivate *priv; - - combo_button = E_COMBO_BUTTON (button); - priv = combo_button->priv; - - /* Massive cut & paste from GtkButton here... The only change in - behavior here is that we want to emit ::activate_default when not - the menu hasn't been popped up. */ - - if (button->button_down) { - gint new_state; - - button->button_down = FALSE; - - if (button->in_button) { - gtk_button_clicked (button); - - if (! priv->menu_popped_up) - g_signal_emit (button, signals[ACTIVATE_DEFAULT], 0); - } - - new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); - - if (GTK_WIDGET_STATE (button) != new_state) { - gtk_widget_set_state (GTK_WIDGET (button), new_state); - - /* We _draw () instead of queue_draw so that if the - operation blocks, the label doesn't vanish. */ - /* XXX gtk_widget_draw() is deprecated. - * Replace it with GTK's implementation. */ - gtk_widget_queue_draw (GTK_WIDGET (button)); - gdk_window_process_updates ( - GTK_WIDGET (button)->window, TRUE); - } - } -} - - -static void -e_combo_button_class_init (EComboButtonClass *combo_button_class) -{ - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - GtkButtonClass *button_class; - - object_class = GTK_OBJECT_CLASS (combo_button_class); - object_class->destroy = impl_destroy; - - widget_class = GTK_WIDGET_CLASS (object_class); - widget_class->button_press_event = impl_button_press_event; - widget_class->leave_notify_event = impl_leave_notify_event; - widget_class->expose_event = impl_expose_event; - - button_class = GTK_BUTTON_CLASS (object_class); - button_class->released = impl_released; - - signals[ACTIVATE_DEFAULT] = g_signal_new ("activate_default", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (EComboButtonClass, activate_default), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - e_combo_button_a11y_init (); -} - -static void -e_combo_button_init (EComboButton *combo_button) -{ - EComboButtonPrivate *priv; - - priv = g_new (EComboButtonPrivate, 1); - combo_button->priv = priv; - - priv->icon = NULL; - priv->menu = NULL; - priv->menu_popped_up = FALSE; - priv->is_already_packed = FALSE; -} - -void -e_combo_button_pack_hbox (EComboButton *combo_button) -{ - EComboButtonPrivate *priv; - - priv = combo_button->priv; - - if (priv->is_already_packed) { - gtk_widget_destroy (priv->hbox); - } - - priv->hbox = gtk_hbox_new (FALSE, SPACING); - gtk_container_add (GTK_CONTAINER (combo_button), priv->hbox); - gtk_widget_show (priv->hbox); - - priv->icon_image = gtk_image_new_from_stock ( - GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_MENU); - gtk_box_pack_start (GTK_BOX (priv->hbox), priv->icon_image, TRUE, TRUE, 0); - gtk_widget_show (priv->icon_image); - - priv->label = gtk_label_new (""); - gtk_box_pack_start (GTK_BOX (priv->hbox), priv->label, TRUE, TRUE, - 0); - gtk_widget_show (priv->label); - - priv->arrow_image = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); - gtk_box_pack_end (GTK_BOX (priv->hbox), priv->arrow_image, TRUE, TRUE, - GTK_WIDGET (combo_button)->style->xthickness); - gtk_widget_show (priv->arrow_image); - - gtk_widget_show (priv->hbox); - - priv->is_already_packed = TRUE; -} - -void -e_combo_button_pack_vbox (EComboButton *combo_button) -{ - EComboButtonPrivate *priv; - - priv = combo_button->priv; - - if (priv->is_already_packed) { - gtk_widget_destroy (priv->hbox); - } - - priv->hbox = gtk_hbox_new (FALSE, SPACING); - gtk_container_add (GTK_CONTAINER (combo_button), priv->hbox); - gtk_widget_show (priv->hbox); - - priv->vbox = gtk_vbox_new (FALSE, 0); - gtk_widget_show (priv->vbox); - - priv->icon_image = gtk_image_new_from_stock ( - GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_MENU); - gtk_box_pack_start (GTK_BOX (priv->vbox), priv->icon_image, TRUE, TRUE, 0); - gtk_widget_show (priv->icon_image); - - priv->label = gtk_label_new (""); - gtk_box_pack_start (GTK_BOX (priv->vbox), priv->label, TRUE, TRUE, - 0); - gtk_widget_show (priv->label); - - gtk_box_pack_start (GTK_BOX(priv->hbox),priv->vbox, TRUE, TRUE, 0); - - priv->arrow_image = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); - gtk_box_pack_end (GTK_BOX (priv->hbox), priv->arrow_image, TRUE, TRUE, - GTK_WIDGET (combo_button)->style->xthickness); - gtk_widget_show (priv->arrow_image); - - gtk_widget_show (priv->hbox); - - priv->is_already_packed = TRUE; -} - - -void -e_combo_button_construct (EComboButton *combo_button) -{ - EComboButtonPrivate *priv; - - g_return_if_fail (combo_button != NULL); - g_return_if_fail (E_IS_COMBO_BUTTON (combo_button)); - - priv = combo_button->priv; - g_return_if_fail (priv->menu == NULL); - - GTK_WIDGET_UNSET_FLAGS (combo_button, GTK_CAN_FOCUS); - - gtk_button_set_relief (GTK_BUTTON (combo_button), GTK_RELIEF_NONE); -} - -GtkWidget * -e_combo_button_new (void) -{ - EComboButton *new; - - new = g_object_new (e_combo_button_get_type (), NULL); - e_combo_button_construct (new); - - return GTK_WIDGET (new); -} - - -void -e_combo_button_set_icon (EComboButton *combo_button, - GdkPixbuf *pixbuf) -{ - g_return_if_fail (combo_button != NULL); - g_return_if_fail (E_IS_COMBO_BUTTON (combo_button)); - - set_icon (combo_button, pixbuf); -} - -void -e_combo_button_set_label (EComboButton *combo_button, - const gchar *label) -{ - EComboButtonPrivate *priv; - - g_return_if_fail (combo_button != NULL); - g_return_if_fail (E_IS_COMBO_BUTTON (combo_button)); - - priv = combo_button->priv; - - if (label == NULL) - label = ""; - - gtk_label_set_label (GTK_LABEL (priv->label), label); - gtk_label_set_use_markup (GTK_LABEL (priv->label), FALSE); - gtk_label_set_use_underline (GTK_LABEL (priv->label), TRUE); -} - -void -e_combo_button_set_menu (EComboButton *combo_button, - GtkMenu *menu) -{ - EComboButtonPrivate *priv; - - g_return_if_fail (combo_button != NULL); - g_return_if_fail (E_IS_COMBO_BUTTON (combo_button)); - g_return_if_fail (menu != NULL); - g_return_if_fail (GTK_IS_MENU (menu)); - - priv = combo_button->priv; - - if (priv->menu != NULL) - gtk_menu_detach (priv->menu); - - priv->menu = menu; - if (menu == NULL) - return; - - gtk_menu_attach_to_widget (menu, GTK_WIDGET (combo_button), menu_detacher); - - g_signal_connect((menu), "deactivate", - G_CALLBACK (menu_deactivate_callback), - combo_button); -} - -GtkWidget * -e_combo_button_get_label (EComboButton *combo_button) -{ - EComboButtonPrivate *priv; - - g_return_val_if_fail (combo_button != NULL, NULL); - g_return_val_if_fail (E_IS_COMBO_BUTTON (combo_button), NULL); - - priv = combo_button->priv; - - return priv->label; -} - -gboolean -e_combo_button_popup_menu (EComboButton *combo_button) -{ - return e_combo_button_popup (combo_button, NULL); -} diff --git a/widgets/misc/e-combo-button.h b/widgets/misc/e-combo-button.h deleted file mode 100644 index 29d4b2efe7..0000000000 --- a/widgets/misc/e-combo-button.h +++ /dev/null @@ -1,78 +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 _E_COMBO_BUTTON_H_ -#define _E_COMBO_BUTTON_H_ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define E_TYPE_COMBO_BUTTON (e_combo_button_get_type ()) -#define E_COMBO_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_COMBO_BUTTON, EComboButton)) -#define E_COMBO_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_COMBO_BUTTON, EComboButtonClass)) -#define E_IS_COMBO_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_COMBO_BUTTON)) -#define E_IS_COMBO_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_COMBO_BUTTON)) - - -typedef struct _EComboButton EComboButton; -typedef struct _EComboButtonPrivate EComboButtonPrivate; -typedef struct _EComboButtonClass EComboButtonClass; - -struct _EComboButton { - GtkButton parent; - - EComboButtonPrivate *priv; -}; - -struct _EComboButtonClass { - GtkButtonClass parent_class; - - /* Signals. */ - void (* activate_default) (EComboButton *combo_button); -}; - - -GType e_combo_button_get_type (void); -void e_combo_button_construct (EComboButton *combo_button); -GtkWidget *e_combo_button_new (void); - -void e_combo_button_set_icon (EComboButton *combo_button, - GdkPixbuf *pixbuf); -void e_combo_button_set_label (EComboButton *combo_button, - const gchar *label); -void e_combo_button_set_menu (EComboButton *combo_button, - GtkMenu *menu); -void e_combo_button_pack_vbox (EComboButton *combo_button); -void e_combo_button_pack_hbox (EComboButton *combo_button); - -GtkWidget *e_combo_button_get_label (EComboButton *combo_button); - -gboolean e_combo_button_popup_menu (EComboButton *combo_button); - -G_END_DECLS - -#endif /* _E_COMBO_BUTTON_H_ */ diff --git a/widgets/misc/e-config-page.h b/widgets/misc/e-config-page.h deleted file mode 100644 index 1de9591397..0000000000 --- a/widgets/misc/e-config-page.h +++ /dev/null @@ -1,62 +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 _E_CONFIG_PAGE_H_ -#define _E_CONFIG_PAGE_H_ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define E_TYPE_CONFIG_PAGE (e_config_page_get_type ()) -#define E_CONFIG_PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CONFIG_PAGE, EConfigPage)) -#define E_CONFIG_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CONFIG_PAGE, EConfigPageClass)) -#define E_IS_CONFIG_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CONFIG_PAGE)) -#define E_IS_CONFIG_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_CONFIG_PAGE)) - - -typedef struct _EConfigPage EConfigPage; -typedef struct _EConfigPagePrivate EConfigPagePrivate; -typedef struct _EConfigPageClass EConfigPageClass; - -struct _EConfigPage { - GtkEventBox parent; - - EConfigPagePrivate *priv; -}; - -struct _EConfigPageClass { - GtkEventBoxClass parent_class; - -}; - - -GType e_config_page_get_type (void); -GtkWidget *e_config_page_new (void); - -G_END_DECLS - -#endif /* _E_CONFIG_PAGE_H_ */ diff --git a/widgets/misc/e-dropdown-button.c b/widgets/misc/e-dropdown-button.c deleted file mode 100644 index 0ff0c99fef..0000000000 --- a/widgets/misc/e-dropdown-button.c +++ /dev/null @@ -1,236 +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> - * Damon Chaplin <damon@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "e-dropdown-button.h" - -#include <stdio.h> - -struct _EDropdownButtonPrivate { - GtkAccelGroup *accel_group; - GtkWidget *menu; -}; - -G_DEFINE_TYPE (EDropdownButton, e_dropdown_button, GTK_TYPE_TOGGLE_BUTTON) - -/* Callback to position the pop-up menu. */ - -static void -menu_position_cb (GtkMenu *menu, - gint *x, - gint *y, - gboolean *push_in, - gpointer data) -{ - EDropdownButton *dropdown_button; - EDropdownButtonPrivate *priv; - GtkRequisition menu_requisition; - gint max_x, max_y; - - dropdown_button = E_DROPDOWN_BUTTON (data); - priv = dropdown_button->priv; - - /* Calculate our preferred position. */ - gdk_window_get_origin (GTK_WIDGET (dropdown_button)->window, x, y); - *y += GTK_WIDGET (dropdown_button)->allocation.height; - - /* Now make sure we are on the screen. */ - gtk_widget_size_request (GTK_WIDGET (priv->menu), &menu_requisition); - max_x = MAX (0, gdk_screen_width () - menu_requisition.width); - max_y = MAX (0, gdk_screen_height () - menu_requisition.height); - - *x = CLAMP (*x, 0, max_x); - *y = CLAMP (*y, 0, max_y); -} - -/* Callback for the "deactivate" signal on the pop-up menu. This is used so - that we unset the state of the toggle button when the pop-up menu - disappears. */ - -static gint -menu_deactivate_cb (GtkMenuShell *menu_shell, - gpointer data) -{ - EDropdownButton *dropdown_button; - - dropdown_button = E_DROPDOWN_BUTTON (data); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dropdown_button), FALSE); - return TRUE; -} - - -/* GtkObject methods. */ - -static void -impl_destroy (GtkObject *object) -{ - EDropdownButton *dropdown_button; - EDropdownButtonPrivate *priv; - - dropdown_button = E_DROPDOWN_BUTTON (object); - priv = dropdown_button->priv; - - g_object_unref (priv->accel_group); - gtk_widget_destroy (priv->menu); - - g_free (priv); - - if (GTK_OBJECT_CLASS (e_dropdown_button_parent_class)->destroy) - (* GTK_OBJECT_CLASS (e_dropdown_button_parent_class)->destroy) (object); -} - - -/* GtkWidget methods. */ - -static void -impl_toggled (GtkToggleButton *toggle_button) -{ - EDropdownButton *dropdown_button; - EDropdownButtonPrivate *priv; - - if (GTK_TOGGLE_BUTTON_CLASS (e_dropdown_button_parent_class)->toggled) - GTK_TOGGLE_BUTTON_CLASS (e_dropdown_button_parent_class)->toggled (toggle_button); - - dropdown_button = E_DROPDOWN_BUTTON (toggle_button); - priv = dropdown_button->priv; - - if (toggle_button->active) { - gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL, - menu_position_cb, dropdown_button, - 1, GDK_CURRENT_TIME); - } else { - gtk_menu_popdown (GTK_MENU (priv->menu)); - } -} - - -static void -e_dropdown_button_class_init (EDropdownButtonClass *klass) -{ - GtkObjectClass *object_class; - GtkToggleButtonClass *toggle_class; - - object_class = GTK_OBJECT_CLASS (klass); - toggle_class = GTK_TOGGLE_BUTTON_CLASS (klass); - - object_class->destroy = impl_destroy; - toggle_class->toggled = impl_toggled; -} - -static void -e_dropdown_button_init (EDropdownButton *dropdown_button) -{ - EDropdownButtonPrivate *priv; - - priv = g_new (EDropdownButtonPrivate, 1); - priv->accel_group = gtk_accel_group_new (); - priv->menu = NULL; - - dropdown_button->priv = priv; -} - - -/** - * e_dropdown_button_construct: - * @dropdown_button: A pointer to an %EDropdownButton object - * @label_text: Text to display in the button - * @menu: The menu to pop up when the button is pressed - * - * Construct the @dropdown_button with the specified @label_text and the - * associated @menu. - **/ -void -e_dropdown_button_construct (EDropdownButton *dropdown_button, - const gchar *label_text, - GtkMenu *menu) -{ - EDropdownButtonPrivate *priv; - GtkWidget *hbox; - GtkWidget *arrow; - GtkWidget *label; - guint accel_key; - - g_return_if_fail (dropdown_button != NULL); - g_return_if_fail (E_IS_DROPDOWN_BUTTON (dropdown_button)); - g_return_if_fail (label_text != NULL); - g_return_if_fail (menu != NULL); - g_return_if_fail (GTK_IS_MENU (menu)); - - priv = dropdown_button->priv; - - hbox = gtk_hbox_new (FALSE, 2); - gtk_container_add (GTK_CONTAINER (dropdown_button), hbox); - gtk_widget_show (hbox); - - label = gtk_label_new (""); - gtk_label_set_label (GTK_LABEL (label), label_text); - gtk_label_set_use_markup (GTK_LABEL (label), FALSE); - gtk_label_set_use_underline (GTK_LABEL (label), TRUE); - - accel_key = gtk_label_get_mnemonic_keyval (GTK_LABEL (label)); - gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); - gtk_widget_show (label); - gtk_widget_add_accelerator (GTK_WIDGET (dropdown_button), "clicked", - priv->accel_group, accel_key, GDK_MOD1_MASK, 0); - - arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); - gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 2); - gtk_widget_show (arrow); - - priv->menu = GTK_WIDGET (menu); - - g_signal_connect_object (priv->menu, "deactivate", - G_CALLBACK (menu_deactivate_cb), - dropdown_button, 0); -} - -/** - * e_dropdown_button_new: - * @label_text: Text to display in the button - * @menu: The menu to pop up when the button is pressed - * - * Create a new dropdown button. When the button is clicked, the specified - * @menu will be popped up. - * - * Return value: A pointer to the newly created %EDropdownButton. - **/ -GtkWidget * -e_dropdown_button_new (const gchar *label_text, - GtkMenu *menu) -{ - GtkWidget *widget; - - g_return_val_if_fail (label_text != NULL, NULL); - g_return_val_if_fail (menu != NULL, NULL); - g_return_val_if_fail (GTK_IS_MENU (menu), NULL); - - widget = g_object_new (e_dropdown_button_get_type (), NULL); - - e_dropdown_button_construct (E_DROPDOWN_BUTTON (widget), label_text, menu); - return widget; -} - diff --git a/widgets/misc/e-dropdown-button.h b/widgets/misc/e-dropdown-button.h deleted file mode 100644 index f58cd73085..0000000000 --- a/widgets/misc/e-dropdown-button.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: - * Ettore Perazzoli <ettore@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef _E_DROPDOWN_BUTTON_H_ -#define _E_DROPDOWN_BUTTON_H_ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define E_TYPE_DROPDOWN_BUTTON (e_dropdown_button_get_type ()) -#define E_DROPDOWN_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_DROPDOWN_BUTTON, EDropdownButton)) -#define E_DROPDOWN_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_DROPDOWN_BUTTON, EDropdownButtonClass)) -#define E_IS_DROPDOWN_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_DROPDOWN_BUTTON)) -#define E_IS_DROPDOWN_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_DROPDOWN_BUTTON)) - - -typedef struct _EDropdownButton EDropdownButton; -typedef struct _EDropdownButtonPrivate EDropdownButtonPrivate; -typedef struct _EDropdownButtonClass EDropdownButtonClass; - -struct _EDropdownButton { - GtkToggleButton parent; - - EDropdownButtonPrivate *priv; -}; - -struct _EDropdownButtonClass { - GtkToggleButtonClass parent_class; -}; - - -GType e_dropdown_button_get_type (void); -void e_dropdown_button_construct (EDropdownButton *dropdown_button, - const gchar *label_text, - GtkMenu *menu); -GtkWidget *e_dropdown_button_new (const gchar *label_text, - GtkMenu *menu); - -G_END_DECLS - -#endif /* _E_DROPDOWN_BUTTON_H_ */ diff --git a/widgets/misc/e-filter-bar.c b/widgets/misc/e-filter-bar.c deleted file mode 100644 index 42fc03882f..0000000000 --- a/widgets/misc/e-filter-bar.c +++ /dev/null @@ -1,1032 +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 <libxml/tree.h> -#include <libxml/parser.h> - -#include <glib/gi18n.h> - -#include "e-dropdown-button.h" -#include "e-filter-bar.h" -#include "filter/rule-editor.h" - -#define d(x) - -enum { - LAST_SIGNAL -}; - -/*static gint esb_signals [LAST_SIGNAL] = { 0, };*/ - -static ESearchBarClass *parent_class = NULL; - -/* The arguments we take */ -enum { - PROP_0, - PROP_QUERY, - PROP_STATE -}; - -/* Callbacks. */ - -static void rule_changed (FilterRule *rule, gpointer user_data); - -/* rule editor thingy */ -static void -rule_editor_destroyed (EFilterBar *efb, GObject *deadbeef) -{ - efb->save_dialog = NULL; - e_search_bar_set_menu_sensitive (E_SEARCH_BAR (efb), E_FILTERBAR_SAVE_ID, TRUE); -} - -/* FIXME: need to update the popup menu to match any edited rules, sigh */ -static void -full_rule_editor_response (GtkWidget *dialog, gint response, gpointer data) -{ - EFilterBar *efb = data; - - if (response == GTK_RESPONSE_OK) - rule_context_save (efb->context, efb->userrules); - - gtk_widget_destroy (dialog); -} - -static void -rule_editor_response (GtkWidget *dialog, gint response, gpointer data) -{ - EFilterBar *efb = data; - FilterRule *rule; - - if (response == GTK_RESPONSE_OK) { - rule = g_object_get_data (G_OBJECT (dialog), "rule"); - if (rule) { - if (!filter_rule_validate (rule)) - return; - - rule_context_add_rule (efb->context, rule); - /* FIXME: check return */ - rule_context_save (efb->context, efb->userrules); - } - } - - gtk_widget_destroy (dialog); -} - -static void -rule_advanced_response (GtkWidget *dialog, gint response, gpointer data) -{ - EFilterBar *efb = data; - /* the below generates a compiler warning about incompatible pointer types */ - ESearchBar *esb = (ESearchBar *)efb; - FilterRule *rule; - - if (response == GTK_RESPONSE_OK || response == GTK_RESPONSE_APPLY) { - rule = g_object_get_data ((GObject *) dialog, "rule"); - if (rule) { - GtkStyle *style = gtk_widget_get_default_style (); - - if (!filter_rule_validate (rule)) - return; - - efb->current_query = rule; - g_object_ref (rule); - - gtk_widget_modify_base (esb->entry, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - gtk_widget_modify_text (esb->entry, GTK_STATE_NORMAL, &(style->text[GTK_STATE_SELECTED])); - gtk_widget_modify_base (esb->icon_entry, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - gtk_widget_modify_base (esb->viewoption, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - e_search_bar_set_text (esb,_("Advanced Search")); - gtk_widget_set_sensitive (esb->clear_button, TRUE); - - g_signal_emit_by_name (efb, "search_activated"); - - if (response == GTK_RESPONSE_APPLY) { - if (!rule_context_find_rule (efb->context, rule->name, rule->source)) - rule_context_add_rule (efb->context, rule); - /* FIXME: check return */ - rule_context_save (efb->context, efb->userrules); - } - } - } else { - e_search_bar_set_item_id (esb, esb->last_search_option); - } - - if (response != GTK_RESPONSE_APPLY) - gtk_widget_destroy (dialog); -} - -static void -dialog_rule_changed (FilterRule *fr, GtkWidget *dialog) -{ - gboolean sensitive; - - g_return_if_fail (dialog != NULL); - - sensitive = fr && fr->parts; - gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive); - gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_APPLY, sensitive); -} - -static void -do_advanced (ESearchBar *esb) -{ - EFilterBar *efb = (EFilterBar *)esb; - - d(printf("Advanced search!\n")); - - if (!efb->save_dialog && !efb->setquery) { - GtkWidget *dialog, *w; - FilterRule *rule; - - if (efb->current_query) - rule = filter_rule_clone (efb->current_query); - else { - rule = filter_rule_new (); - efb->current_query = rule; - } - - w = filter_rule_get_widget (rule, efb->context); - filter_rule_set_source (rule, FILTER_SOURCE_INCOMING); - gtk_container_set_border_width (GTK_CONTAINER (w), 12); - - /* FIXME: get the toplevel window... */ - dialog = gtk_dialog_new_with_buttons (_("Advanced Search"), NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_SAVE, GTK_RESPONSE_APPLY, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); - - efb->save_dialog = dialog; - gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); - - gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE); - gtk_window_set_default_size (GTK_WINDOW (dialog), 600, 300); - gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 0); - gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 12); - - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), w, TRUE, TRUE, 0); - - g_object_ref (rule); - g_object_set_data_full ((GObject *) dialog, "rule", rule, (GDestroyNotify) g_object_unref); - - g_signal_connect (rule, "changed", G_CALLBACK (dialog_rule_changed), dialog); - dialog_rule_changed (rule, dialog); - - g_signal_connect (dialog, "response", G_CALLBACK (rule_advanced_response), efb); - g_object_weak_ref ((GObject *) dialog, (GWeakNotify) rule_editor_destroyed, efb); - - e_search_bar_set_menu_sensitive (esb, E_FILTERBAR_SAVE_ID, FALSE); - - gtk_widget_show (dialog); - } -} - -static void -save_search_dialog (ESearchBar *esb) -{ - FilterRule *rule; - gchar *name, *text; - GtkWidget *dialog, *w; - - EFilterBar *efb = (EFilterBar *)esb; - - rule = filter_rule_clone (efb->current_query); - text = e_search_bar_get_text (esb); - name = g_strdup_printf ("%s %s", rule->name, text && text[0] ? text : "''"); - filter_rule_set_name (rule, name); - g_free (text); - g_free (name); - - w = filter_rule_get_widget (rule, efb->context); - filter_rule_set_source (rule, FILTER_SOURCE_INCOMING); - gtk_container_set_border_width (GTK_CONTAINER (w), 12); - - /* FIXME: get the toplevel window... */ - dialog = gtk_dialog_new_with_buttons (_("Save Search"), NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); - efb->save_dialog = dialog; - gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); - gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 0); - gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 12); - - gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 300); - - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), w, TRUE, TRUE, 0); - - g_object_ref (rule); - g_object_set_data_full ((GObject *) dialog, "rule", rule, (GDestroyNotify) g_object_unref); - g_signal_connect (dialog, "response", G_CALLBACK (rule_editor_response), efb); - g_object_weak_ref ((GObject *) dialog, (GWeakNotify) rule_editor_destroyed, efb); - - g_signal_connect (rule, "changed", G_CALLBACK (dialog_rule_changed), dialog); - dialog_rule_changed (rule, dialog); - - e_search_bar_set_menu_sensitive (esb, E_FILTERBAR_SAVE_ID, FALSE); - - gtk_widget_show (dialog); -} - -static void -menubar_activated (ESearchBar *esb, gint id, gpointer data) -{ - EFilterBar *efb = (EFilterBar *)esb; - GtkWidget *dialog; - GtkStyle *style; - - d(printf ("menubar activated!\n")); - - switch (id) { - case E_FILTERBAR_EDIT_ID: - if (!efb->save_dialog) { - efb->save_dialog = dialog = (GtkWidget *) rule_editor_new (efb->context, FILTER_SOURCE_INCOMING, _("_Searches")); - - gtk_window_set_title (GTK_WINDOW (dialog), _("Searches")); - g_signal_connect (dialog, "response", G_CALLBACK (full_rule_editor_response), efb); - g_object_weak_ref ((GObject *) dialog, (GWeakNotify) rule_editor_destroyed, efb); - gtk_widget_show (dialog); - } - break; - case E_FILTERBAR_SAVE_ID: - if (efb->current_query && !efb->save_dialog) - save_search_dialog (esb); - - d(printf("Save menu\n")); - break; - case E_FILTERBAR_ADVANCED_ID: - e_search_bar_set_item_id (esb, E_FILTERBAR_ADVANCED_ID); - break; - default: - if (id >= efb->menu_base && id < efb->menu_base + efb->menu_rules->len) { -#if d(!)0 - GString *out = g_string_new (""); - - printf("Selected rule: %s\n", ((FilterRule *)efb->menu_rules->pdata[id - efb->menu_base])->name); - filter_rule_build_code (efb->menu_rules->pdata[id - efb->menu_base], out); - printf("query: '%s'\n", out->str); - g_string_free (out, TRUE); -#endif - efb->current_query = (FilterRule *)efb->menu_rules->pdata[id - efb->menu_base]; - - efb->setquery = TRUE; - e_search_bar_set_item_id (esb, E_FILTERBAR_ADVANCED_ID); - efb->setquery = FALSE; - - /* saved searches activated */ - style = gtk_widget_get_default_style (); - efb->setquery = TRUE; - gtk_widget_modify_base (esb->entry , GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED] )); - gtk_widget_modify_text (esb->entry, GTK_STATE_NORMAL, &(style->text [GTK_STATE_SELECTED] )); - gtk_widget_modify_base (esb->icon_entry, GTK_STATE_NORMAL, &(style->base [GTK_STATE_SELECTED] )); - gtk_widget_modify_base (esb->viewoption, GTK_STATE_NORMAL, &(style->base [GTK_STATE_SELECTED] )); - e_search_bar_set_text (esb,_("Advanced Search")); - g_signal_emit_by_name (efb, "search_activated", NULL); - efb->setquery = FALSE; - } else { - return; - } - } - - g_signal_stop_emission_by_name (esb, "menu_activated"); -} - -static void -option_changed (ESearchBar *esb, gpointer data) -{ - EFilterBar *efb = (EFilterBar *)esb; - gint id = e_search_bar_get_item_id (esb); - gchar *query; - - d(printf("option changed, id = %d, setquery = %s %d\n", id, efb->setquery ? "true" : "false", esb->block_search)); - - if (efb->setquery) - return; - - switch (id) { - case E_FILTERBAR_SAVE_ID: - /* Fixme */ - /* save_search_dialog (esb); */ - break; - case E_FILTERBAR_ADVANCED_ID: - d(printf ("do_advanced\n")); - if (!esb->block_search) - do_advanced (esb); - break; - default: - if (id >= efb->option_base && id < efb->option_base + efb->option_rules->len) { - efb->current_query = (FilterRule *)efb->option_rules->pdata[id - efb->option_base]; - if (efb->config && efb->current_query) { - query = e_search_bar_get_text (esb); - efb->config (efb, efb->current_query, id, query, efb->config_data); - g_free (query); - } - } else { - gtk_widget_modify_base (esb->entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_text (esb->entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_base (esb->icon_entry, GTK_STATE_NORMAL, NULL); - efb->current_query = NULL; - gtk_entry_set_text ((GtkEntry *)esb->entry, ""); - } - } -} - -static void -dup_item_no_subitems (ESearchBarItem *dest, - const ESearchBarItem *src) -{ - dest->id = src->id; - dest->text = g_strdup (src->text); - dest->type = src->type; -} - -static GArray * -build_items (ESearchBar *esb, ESearchBarItem *items, gint type, gint *start, GPtrArray *rules) -{ - FilterRule *rule = NULL; - EFilterBar *efb = (EFilterBar *)esb; - gint id = 0, i; - GArray *menu = g_array_new (FALSE, FALSE, sizeof (ESearchBarItem)); - ESearchBarItem item = { NULL, -1, 2 }; - const gchar *source; - GSList *gtksux = NULL; - gint num; - - for (i=0;i<rules->len;i++) - gtksux = g_slist_prepend(gtksux, rules->pdata[i]); - - g_ptr_array_set_size(rules, 0); - - /* find a unique starting point for the id's of our items */ - for (i = 0; items[i].id != -1; i++) { - ESearchBarItem dup_item = { NULL, -1, 2 }; - - if (items[i].id >= id) - id = items[i].id + 1; - - dup_item_no_subitems (&dup_item, items + i); - g_array_append_vals (menu, &dup_item, 1); - } - - *start = id; - - if (type == 0) { - source = FILTER_SOURCE_INCOMING; - - /* Add a separator if there is at least one custom rule. */ - if (rule_context_next_rule (efb->context, rule, source) != NULL) { - item.id = 0; - item.text = NULL; - item.type = 0; - g_array_append_vals (menu, &item, 1); - } - } else { - source = FILTER_SOURCE_DEMAND; - } - - num = 1; - while ((rule = rule_context_next_rule (efb->context, rule, source))) { - item.id = id++; - - if (type == 0 && num <= 10) { - item.text = g_strdup_printf ("_%d. %s", num % 10, rule->name); - num ++; - } else { - item.text = g_strdup (rule->name); - } - g_array_append_vals (menu, &item, 1); - - if (g_slist_find(gtksux, rule) == NULL) { - g_object_ref (rule); - g_signal_connect (rule, "changed", G_CALLBACK (rule_changed), efb); - } else { - gtksux = g_slist_remove(gtksux, rule); - } - g_ptr_array_add (rules, rule); - } - - /* anything elft in gtksux has gone away, and we need to unref/disconnect from it */ - while (gtksux) { - GSList *next; - - next = gtksux->next; - rule = gtksux->data; - - g_signal_handlers_disconnect_by_func (rule, G_CALLBACK (rule_changed), efb); - g_object_unref (rule); - - g_slist_free_1(gtksux); - gtksux = next; - } - - /* always add on the advanced menu */ - if (type == 1) { - ESearchBarItem sb_items[2] = { E_FILTERBAR_SEPARATOR, E_FILTERBAR_ADVANCED, - /* E_FILTERBAR_SEPARATOR, E_FILTERBAR_SAVE */ }; - ESearchBarItem dup_items[2]; - - dup_item_no_subitems (&dup_items[0], &sb_items[0]); - dup_item_no_subitems (&dup_items[1], &sb_items[1]); - /* dup_item_no_subitems (&dup_items[2], &sb_items[2]); */ - /* dup_item_no_subitems (&dup_items[3], &sb_items[3]); */ - g_array_append_vals (menu, &dup_items, 2); - } - - item.id = -1; - item.text = NULL; - g_array_append_vals (menu, &item, 1); - - return menu; -} - -static void -free_built_items (GArray *menu) -{ - gint i; - - for (i = 0; i < menu->len; i ++) { - ESearchBarItem *item; - - item = & g_array_index (menu, ESearchBarItem, i); - g_free (item->text); - } - - g_array_free (menu, TRUE); -} - -static void -generate_menu (ESearchBar *esb, ESearchBarItem *items) -{ - EFilterBar *efb = (EFilterBar *)esb; - GArray *menu; - - menu = build_items (esb, items, 0, &efb->menu_base, efb->menu_rules); - ((ESearchBarClass *)parent_class)->set_menu (esb, (ESearchBarItem *)menu->data); - free_built_items (menu); -} - -static void -free_items (ESearchBarItem *items) -{ - gint i; - - for (i = 0; items[i].id != -1; i++) - g_free (items[i].text); - - g_free (items); -} - -/* Virtual methods */ -static void -set_menu (ESearchBar *esb, ESearchBarItem *items) -{ - EFilterBar *efb = E_FILTER_BAR (esb); - ESearchBarItem *default_items; - gint i, num; - - if (efb->default_items) - free_items (efb->default_items); - - for (num = 0; items[num].id != -1; num++) - ; - - default_items = g_new (ESearchBarItem, num + 1); - for (i = 0; i < num + 1; i++) { - default_items[i].text = g_strdup (items[i].text); - default_items[i].id = items[i].id; - default_items[i].type = items[i].type; - } - - efb->default_items = default_items; - - generate_menu (esb, default_items); -} - -static void -set_option (ESearchBar *esb, ESearchBarItem *items) -{ - GArray *menu; - EFilterBar *efb = (EFilterBar *)esb; - - menu = build_items (esb, items, 1, &efb->option_base, efb->option_rules); - ((ESearchBarClass *)parent_class)->set_option (esb, (ESearchBarItem *)menu->data); - free_built_items (menu); - - e_search_bar_set_item_id (esb, efb->option_base); -} - -static void -context_changed (RuleContext *context, gpointer user_data) -{ - EFilterBar *efb = E_FILTER_BAR (user_data); - ESearchBar *esb = E_SEARCH_BAR (user_data); - - /* just generate whole menu again */ - generate_menu (esb, efb->default_items); -} - -static void -context_rule_removed (RuleContext *context, FilterRule *rule, gpointer user_data) -{ - EFilterBar *efb = E_FILTER_BAR (user_data); - ESearchBar *esb = E_SEARCH_BAR (user_data); - - /* just generate whole menu again */ - generate_menu (esb, efb->default_items); -} - -static void -rule_changed (FilterRule *rule, gpointer user_data) -{ - EFilterBar *efb = E_FILTER_BAR (user_data); - ESearchBar *esb = E_SEARCH_BAR (user_data); - - /* just generate whole menu again */ - generate_menu (esb, efb->default_items); -} - - -/* GtkObject methods. */ - -static void -get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) -{ - EFilterBar *efb = (EFilterBar *) object; - ESearchBar *esb = E_SEARCH_BAR (object); - - switch (property_id) { - case PROP_QUERY: { - gchar *text = e_search_bar_get_text (E_SEARCH_BAR (efb)); - - /* empty search text means searching turned off */ - if (efb->current_query && text && *text) { - GString *out = g_string_new (""); - - filter_rule_build_code (efb->current_query, out); - g_value_take_string (value, out->str); - g_string_free (out, FALSE); - } else { - g_value_set_string (value, NULL); - } - - g_free (text); - break; } - case PROP_STATE: { - /* FIXME: we should have ESearchBar save its own state to the xmlDocPtr */ - xmlChar *xmlbuf; - gchar *text, buf[12]; - gint searchscope, item_id, n, view_id; - xmlNodePtr root, node; - xmlDocPtr doc; - - item_id = e_search_bar_get_item_id ((ESearchBar *) efb); - - doc = xmlNewDoc ((const guchar *)"1.0"); - root = xmlNewDocNode (doc, NULL, (const guchar *)"state", NULL); - xmlDocSetRootElement (doc, root); - searchscope = e_search_bar_get_search_scope ((ESearchBar *) efb); - view_id = e_search_bar_get_viewitem_id ((ESearchBar *) efb); - - if (searchscope < E_FILTERBAR_CURRENT_FOLDER_ID) - item_id = esb->last_search_option; - - if (item_id == E_FILTERBAR_ADVANCED_ID) { - /* advanced query, save the filterbar state */ - node = xmlNewChild (root, NULL, (const guchar *)"filter-bar", NULL); - - sprintf (buf, "%d", esb->last_search_option); - xmlSetProp (node, (const guchar *)"item_id", (guchar *)buf); - sprintf (buf, "%d", searchscope); - xmlSetProp (node, (const guchar *)"searchscope", (guchar *)buf); - sprintf (buf, "%d", view_id); - xmlSetProp (node, (const guchar *)"view_id", (guchar *)buf); - - xmlAddChild (node, filter_rule_xml_encode (efb->current_query)); - } else { - /* simple query, save the searchbar state */ - text = e_search_bar_get_text ((ESearchBar *) efb); - - node = xmlNewChild (root, NULL, (const guchar *)"search-bar", NULL); - xmlSetProp (node, (const guchar *)"text", (guchar *)(text ? text : "")); - sprintf (buf, "%d", item_id); - xmlSetProp (node, (const guchar *)"item_id", (guchar *)buf); - sprintf (buf, "%d", searchscope); - xmlSetProp (node, (const guchar *)"searchscope", (guchar *)buf); - sprintf (buf, "%d", view_id); - xmlSetProp (node, (const guchar *)"view_id", (guchar *)buf); - g_free (text); - } - - xmlDocDumpMemory (doc, &xmlbuf, &n); - xmlFreeDoc (doc); - - /* remap to glib memory */ - text = g_malloc (n + 1); - memcpy (text, (gchar *)xmlbuf, n); - text[n] = '\0'; - xmlFree (xmlbuf); - - g_value_take_string (value, text); - - break; } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static gint -xml_get_prop_int (xmlNodePtr node, const gchar *prop) -{ - gchar *buf; - gint ret; - - if ((buf = (gchar *)xmlGetProp (node, (guchar *)prop))) { - ret = strtol (buf, NULL, 10); - xmlFree (buf); - } else { - ret = -1; - } - - return ret; -} - -static void -set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) -{ - EFilterBar *efb = (EFilterBar *) object; - ESearchBar *esb = E_SEARCH_BAR (object); - xmlNodePtr root, node; - const gchar *state; - xmlDocPtr doc; - gboolean rule_set = FALSE, is_cur_folder=FALSE; - gint view_id, scope, item_id; - - switch (property_id) { - case PROP_STATE: - if ((state = g_value_get_string (value))) { - if (!(doc = xmlParseDoc ((guchar *) state))) - return; - - root = doc->children; - if (strcmp ((gchar *)root->name, "state") != 0) { - xmlFreeDoc (doc); - return; - } - - node = root->children; - while (node != NULL) { - if (!strcmp ((gchar *)node->name, "filter-bar")) { - FilterRule *rule = NULL; - - view_id = xml_get_prop_int (node, "view_id"); - scope = xml_get_prop_int (node, "searchscope"); - item_id = xml_get_prop_int (node, "item_id"); - if (item_id == -1) - item_id = 0; - - if (scope == E_FILTERBAR_CURRENT_FOLDER_ID) - is_cur_folder = TRUE; - - if ((node = node->children)) { - GtkStyle *style = gtk_widget_get_default_style (); - - rule = filter_rule_new (); - if (filter_rule_xml_decode (rule, node, efb->context) != 0) { - gtk_widget_modify_base (E_SEARCH_BAR (efb)->entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_text (((ESearchBar *)efb)->entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_base (((ESearchBar *)efb)->icon_entry, GTK_STATE_NORMAL, NULL); - g_object_unref (rule); - rule = NULL; - } else { - rule_set = TRUE; - gtk_widget_set_sensitive (esb->clear_button, TRUE); - gtk_widget_modify_base (((ESearchBar *)efb)->entry, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - gtk_widget_modify_text (((ESearchBar *)efb)->entry, GTK_STATE_NORMAL, &(style->text[GTK_STATE_SELECTED])); - gtk_widget_modify_base (((ESearchBar *)efb)->icon_entry, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - gtk_widget_modify_base (((ESearchBar *)efb)->viewoption, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - g_object_set_data_full (object, "rule", rule, (GDestroyNotify) g_object_unref); - } - } - - if (rule_set) { - esb->block_search = TRUE; - e_search_bar_set_text (esb, _("Advanced Search")); - e_search_bar_set_item_menu ((ESearchBar *) efb, item_id); - e_search_bar_set_search_scope ((ESearchBar *) efb, scope); - esb->block_search = FALSE; - efb->current_query = (FilterRule *)efb->option_rules->pdata[item_id - efb->option_base]; - if (efb->config && efb->current_query) { - gchar *query = e_search_bar_get_text (esb); - efb->config (efb, efb->current_query, item_id, query, efb->config_data); - g_free (query); - - } - } - e_search_bar_set_viewitem_id ((ESearchBar *) efb, view_id); - efb->current_query = rule; - efb->setquery = TRUE; - e_search_bar_set_item_id ((ESearchBar *) efb, E_FILTERBAR_ADVANCED_ID); - efb->setquery = FALSE; - - break; - } else if (!strcmp ((gchar *)node->name, "search-bar")) { - gint subitem_id, item_id, scope, view_id; - gchar *text; - GtkStyle *style = gtk_widget_get_default_style (); - - /* set the text first (it doesn't emit a signal) */ - - /* now set the item_id and subitem_id */ - item_id = xml_get_prop_int (node, "item_id"); - subitem_id = xml_get_prop_int (node, "subitem_id"); - - esb->block_search = TRUE; - if (subitem_id >= 0) - e_search_bar_set_ids (E_SEARCH_BAR (efb), item_id, subitem_id); - else - e_search_bar_set_item_menu (E_SEARCH_BAR (efb), item_id); - esb->block_search = FALSE; - view_id = xml_get_prop_int (node, "view_id"); - e_search_bar_set_viewitem_id (E_SEARCH_BAR (efb), view_id); - scope = xml_get_prop_int (node, "searchscope"); - e_search_bar_set_search_scope (E_SEARCH_BAR (efb), scope); - - text = (gchar *)xmlGetProp (node, (const guchar *)"text"); - e_search_bar_set_text (E_SEARCH_BAR (efb), text); - if (text && *text) { - efb->current_query = (FilterRule *)efb->option_rules->pdata[item_id - efb->option_base]; - if (efb->config && efb->current_query) - efb->config (efb, efb->current_query, item_id, text, efb->config_data); - gtk_widget_set_sensitive (esb->clear_button, TRUE); - gtk_widget_modify_base (((ESearchBar *)efb)->entry, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - gtk_widget_modify_text (((ESearchBar *)efb)->entry, GTK_STATE_NORMAL, &(style->text[GTK_STATE_SELECTED])); - gtk_widget_modify_base (((ESearchBar *)efb)->icon_entry, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - gtk_widget_modify_base (((ESearchBar *)efb)->viewoption, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - } else { - gtk_widget_modify_base (((ESearchBar *)efb)->entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_text (((ESearchBar *)efb)->entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_base (((ESearchBar *)efb)->icon_entry, GTK_STATE_NORMAL, NULL); - e_search_bar_paint (esb); - efb->current_query = (FilterRule *)efb->option_rules->pdata[item_id - efb->option_base]; - if (efb->config && efb->current_query) - efb->config (efb, efb->current_query, item_id, "", efb->config_data); - } - - xmlFree (text); - - break; - } - - node = node->next; - } - - xmlFreeDoc (doc); - } else { - /* set default state */ - e_search_bar_set_item_id ((ESearchBar *) efb, 0); - e_search_bar_set_viewitem_id ((ESearchBar *) efb, 0); - e_search_bar_set_search_scope ((ESearchBar *) efb, E_FILTERBAR_CURRENT_FOLDER_ID); - } - - /* we don't want to run option_changed */ - efb->setquery = TRUE; - g_signal_emit_by_name (efb, "search_activated", NULL); - efb->setquery = FALSE; - - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void clear_rules(EFilterBar *efb, GPtrArray *rules) -{ - gint i; - FilterRule *rule; - - /* clear out any data on old rules */ - for (i=0;i<rules->len;i++) { - rule = rules->pdata[i]; - g_signal_handlers_disconnect_by_func (rule, G_CALLBACK (rule_changed), efb); - g_object_unref(rule); - } - g_ptr_array_set_size (rules, 0); -} - -static void -dispose (GObject *object) -{ - EFilterBar *bar; - - g_return_if_fail (object != NULL); - g_return_if_fail (E_IS_FILTER_BAR (object)); - - bar = E_FILTER_BAR (object); - - if (bar->context != NULL && bar->userrules != NULL) - rule_context_save (bar->context, bar->userrules); - - if (bar->menu_rules != NULL) { - clear_rules(bar, bar->menu_rules); - clear_rules(bar, bar->option_rules); - - g_ptr_array_free (bar->menu_rules, TRUE); - g_ptr_array_free (bar->option_rules, TRUE); - - g_free (bar->systemrules); - g_free (bar->userrules); - - bar->menu_rules = NULL; - bar->option_rules = NULL; - bar->systemrules = NULL; - bar->userrules = NULL; - } - - if (bar->context != NULL) { - g_signal_handlers_disconnect_by_func (bar->context, G_CALLBACK (context_changed), bar); - g_signal_handlers_disconnect_by_func (bar->context, G_CALLBACK (context_rule_removed), bar); - - g_object_unref (bar->context); - bar->context = NULL; - } - - if (bar->default_items) { - free_items (bar->default_items); - bar->default_items = NULL; - } - - (* G_OBJECT_CLASS (parent_class)->dispose) (object); -} - - -static void -class_init (EFilterBarClass *klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - ESearchBarClass *esb_class = (ESearchBarClass *) klass; - GParamSpec *pspec; - - parent_class = g_type_class_ref (e_search_bar_get_type ()); - - object_class->dispose = dispose; - object_class->get_property = get_property; - object_class->set_property = set_property; - - esb_class->set_menu = set_menu; - esb_class->set_option = set_option; - - pspec = g_param_spec_string ("query", NULL, NULL, NULL, G_PARAM_READABLE); - g_object_class_install_property (object_class, PROP_QUERY, pspec); - - pspec = g_param_spec_string ("state", NULL, NULL, NULL, G_PARAM_READWRITE); - g_object_class_install_property (object_class, PROP_STATE, pspec); - - /*gtk_object_add_arg_type ("EFilterBar::query", G_TYPE_STRING, GTK_ARG_READABLE, ARG_QUERY);*/ - -#if 0 - esb_signals [QUERY_CHANGED] = - g_signal_new ("query_changed", - G_SIGNAL_RUN_LAST, - object_class->type, - G_STRUCT_OFFSET (EFilterBarClass, query_changed), - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - esb_signals [MENU_ACTIVATED] = - g_signal_new ("menu_activated", - G_SIGNAL_RUN_LAST, - object_class->type, - G_STRUCT_OFFSET (EFilterBarClass, menu_activated), - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); - - gtk_object_class_add_signals (object_class, esb_signals, LAST_SIGNAL); -#endif -} - -static void -init (EFilterBar *efb) -{ - g_signal_connect (efb, "menu_activated", G_CALLBACK (menubar_activated), NULL); - g_signal_connect (efb, "query_changed", G_CALLBACK (option_changed), NULL); - g_signal_connect (efb, "search_activated", G_CALLBACK (option_changed), NULL); - - efb->menu_rules = g_ptr_array_new (); - efb->option_rules = g_ptr_array_new (); -} - - -/* Object construction. */ - -EFilterBar * -e_filter_bar_new (RuleContext *context, - const gchar *systemrules, - const gchar *userrules, - EFilterBarConfigRule config, - gpointer data) -{ - EFilterBar *bar; - - bar = g_object_new (e_filter_bar_get_type (), NULL); - ((ESearchBar *)bar)->lite = FALSE; - - e_filter_bar_new_construct (context, systemrules, userrules, config, data, bar); - - return bar; -} - -EFilterBar * -e_filter_bar_lite_new (RuleContext *context, - const gchar *systemrules, - const gchar *userrules, - EFilterBarConfigRule config, - gpointer data) -{ - EFilterBar *bar; - - bar = g_object_new (e_filter_bar_get_type (), NULL); - ((ESearchBar *)bar)->lite = TRUE; - e_filter_bar_new_construct (context, systemrules, userrules, config, data, bar); - - return bar; -} - -void -e_filter_bar_new_construct (RuleContext *context, - const gchar *systemrules, - const gchar *userrules, - EFilterBarConfigRule config, - gpointer data ,EFilterBar *bar ) -{ - ESearchBarItem item = { NULL, -1, 0 }; - - bar->context = context; - g_object_ref (context); - - bar->config = config; - bar->config_data = data; - - bar->systemrules = g_strdup (systemrules); - bar->userrules = g_strdup (userrules); - - bar->all_account_search_vf = NULL; - bar->account_search_vf = NULL; - bar->account_search_cancel = NULL; - - e_search_bar_construct ((ESearchBar *)bar, &item, &item); - - g_signal_connect (context, "changed", G_CALLBACK (context_changed), bar); - g_signal_connect (context, "rule_removed", G_CALLBACK (context_rule_removed), bar); - -} - -GType -e_filter_bar_get_type (void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) { - static const GTypeInfo type_info = { - sizeof (EFilterBarClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ - sizeof (EFilterBar), - 0, /* n_preallocs */ - (GInstanceInitFunc) init, - NULL /* value_table */ - }; - - type = g_type_register_static ( - e_search_bar_get_type (), "EFilterBar", &type_info, 0); - } - - return type; -} diff --git a/widgets/misc/e-filter-bar.h b/widgets/misc/e-filter-bar.h deleted file mode 100644 index 8659f0a638..0000000000 --- a/widgets/misc/e-filter-bar.h +++ /dev/null @@ -1,138 +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 __E_FILTER_BAR_H__ -#define __E_FILTER_BAR_H__ - -#include <gtk/gtk.h> -#include <camel/camel-vee-folder.h> -#include <camel/camel-operation.h> - -#include "e-search-bar.h" - -#include "filter/rule-context.h" -#include "filter/filter-rule.h" - -G_BEGIN_DECLS - -/* EFilterBar - A filter rule driven search bar. - * - * The following arguments are available: - * - * name type read/write description - * --------------------------------------------------------------------------------- - * query string R String representing query. - * state string RW XML string representing the state. - */ - -#define E_FILTER_BAR_TYPE (e_filter_bar_get_type ()) -#define E_FILTER_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_FILTER_BAR_TYPE, EFilterBar)) -#define E_FILTER_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_FILTER_BAR_TYPE, EFilterBarClass)) -#define E_IS_FILTER_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_FILTER_BAR_TYPE)) -#define E_IS_FILTER_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_FILTER_BAR_TYPE)) - -typedef struct _EFilterBar EFilterBar; -typedef struct _EFilterBarClass EFilterBarClass; - -typedef void (*EFilterBarConfigRule)(EFilterBar *, FilterRule *rule, gint id, const gchar *query, gpointer data); - -struct _EFilterBar { - ESearchBar parent; - gint menu_base, option_base; - GPtrArray *menu_rules, *option_rules; - - ESearchBarItem *default_items; - - GtkWidget *save_dialog; /* current save dialogue (so we dont pop up multiple ones) */ - - FilterRule *current_query; /* as it says */ - gint setquery; /* true when we're setting a query directly to advanced, so dont popup the dialog */ - - RuleContext *context; - gchar *systemrules; - gchar *userrules; - - EFilterBarConfigRule config; - gpointer config_data; - - CamelVeeFolder *all_account_search_vf; - CamelVeeFolder *account_search_vf; - CamelOperation *account_search_cancel; -}; - -struct _EFilterBarClass -{ - ESearchBarClass parent_class; -}; - -/* "preset" items */ -enum { - /* preset menu options */ - E_FILTERBAR_SAVE_ID = -3, - E_FILTERBAR_EDIT_ID = -4, - - /* preset option options */ - E_FILTERBAR_ADVANCED_ID = -5, - E_FILTERBAR_CURRENT_FOLDER_ID = -7, - E_FILTERBAR_CURRENT_ACCOUNT_ID = -8, - E_FILTERBAR_ALL_ACCOUNTS_ID = -9 -}; - -#define E_FILTERBAR_SAVE { (gchar *) N_("_Save Search..."), E_FILTERBAR_SAVE_ID, 0 } -#define E_FILTERBAR_EDIT { (gchar *) N_("_Edit Saved Searches..."), E_FILTERBAR_EDIT_ID, 0 } -#define E_FILTERBAR_ADVANCED { (gchar *) N_("_Advanced Search..."), E_FILTERBAR_ADVANCED_ID, 0 } -#define E_FILTERBAR_ALL_ACCOUNTS { (gchar *) N_("All Accounts"), E_FILTERBAR_ALL_ACCOUNTS_ID, ESB_ITEMTYPE_RADIO } -#define E_FILTERBAR_CURRENT_ACCOUNT { (gchar *) N_("Current Account"), E_FILTERBAR_CURRENT_ACCOUNT_ID, ESB_ITEMTYPE_RADIO } -#define E_FILTERBAR_CURRENT_FOLDER { (gchar *) N_("Current Folder"), E_FILTERBAR_CURRENT_FOLDER_ID, ESB_ITEMTYPE_RADIO } -#define E_FILTERBAR_SEPARATOR { NULL, 0, 0 } - -#ifdef JUST_FOR_TRANSLATORS -const gchar * strings[] = { - N_("_Save Search..."), - N_("_Edit Saved Searches..."), - N_("_Advanced Search...") -}; -#endif - -GType e_filter_bar_get_type (void); - -EFilterBar *e_filter_bar_new (RuleContext *context, - const gchar *systemrules, - const gchar *userrules, - EFilterBarConfigRule config, - gpointer data); -EFilterBar *e_filter_bar_lite_new (RuleContext *context, - const gchar *systemrules, - const gchar *userrules, - EFilterBarConfigRule config, - gpointer data); - -void -e_filter_bar_new_construct (RuleContext *context, - const gchar *systemrules, - const gchar *userrules, - EFilterBarConfigRule config, - gpointer data ,EFilterBar *bar ); - -G_END_DECLS - -#endif /* __E_FILTER_BAR_H__ */ diff --git a/widgets/misc/e-hinted-entry.c b/widgets/misc/e-hinted-entry.c new file mode 100644 index 0000000000..ca75e85297 --- /dev/null +++ b/widgets/misc/e-hinted-entry.c @@ -0,0 +1,298 @@ +/* + * e-hinted-entry.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-hinted-entry.h" + +#define E_HINTED_ENTRY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_HINTED_ENTRY, EHintedEntryPrivate)) + +struct _EHintedEntryPrivate { + gchar *hint; + guint hint_shown : 1; +}; + +enum { + PROP_0, + PROP_HINT, + PROP_HINT_SHOWN +}; + +static gpointer parent_class; + +static void +hinted_entry_hide_hint (EHintedEntry *entry) +{ + gtk_entry_set_text (GTK_ENTRY (entry), ""); + + gtk_widget_modify_text (GTK_WIDGET (entry), GTK_STATE_NORMAL, NULL); + + entry->priv->hint_shown = FALSE; + + g_object_notify (G_OBJECT (entry), "hint-shown"); +} + +static void +hinted_entry_show_hint (EHintedEntry *entry) +{ + GtkStyle *style; + const GdkColor *color; + const gchar *hint; + + hint = e_hinted_entry_get_hint (entry); + gtk_entry_set_text (GTK_ENTRY (entry), hint); + + style = gtk_widget_get_style (GTK_WIDGET (entry)); + color = &style->text[GTK_STATE_INSENSITIVE]; + gtk_widget_modify_text (GTK_WIDGET (entry), GTK_STATE_NORMAL, color); + + entry->priv->hint_shown = TRUE; + + g_object_notify (G_OBJECT (entry), "hint-shown"); +} + +static void +hinted_entry_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_HINT: + e_hinted_entry_set_hint ( + E_HINTED_ENTRY (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +hinted_entry_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_HINT: + g_value_set_string ( + value, e_hinted_entry_get_hint ( + E_HINTED_ENTRY (object))); + return; + + case PROP_HINT_SHOWN: + g_value_set_boolean ( + value, e_hinted_entry_get_hint_shown ( + E_HINTED_ENTRY (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +hinted_entry_finalize (GObject *object) +{ + EHintedEntryPrivate *priv; + + priv = E_HINTED_ENTRY_GET_PRIVATE (object); + + g_free (priv->hint); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +hinted_entry_focus_in_event (GtkWidget *widget, + GdkEventFocus *event) +{ + EHintedEntry *entry = E_HINTED_ENTRY (widget); + + if (e_hinted_entry_get_hint_shown (entry)) + hinted_entry_hide_hint (entry); + + /* Chain up to parent's focus_in_event() method. */ + return GTK_WIDGET_CLASS (parent_class)-> + focus_in_event (widget, event); +} + +static gboolean +hinted_entry_focus_out_event (GtkWidget *widget, + GdkEventFocus *event) +{ + EHintedEntry *entry = E_HINTED_ENTRY (widget); + const gchar *text; + + text = e_hinted_entry_get_text (entry); + + if (text == NULL || *text == '\0') + hinted_entry_show_hint (E_HINTED_ENTRY (widget)); + + /* Chain up to parent's focus_out_event() method. */ + return GTK_WIDGET_CLASS (parent_class)-> + focus_out_event (widget, event); +} + +static void +hinted_entry_class_init (EHintedEntryClass *class) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EHintedEntryPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = hinted_entry_set_property; + object_class->get_property = hinted_entry_get_property; + object_class->finalize = hinted_entry_finalize; + + widget_class = GTK_WIDGET_CLASS (class); + widget_class->focus_in_event = hinted_entry_focus_in_event; + widget_class->focus_out_event = hinted_entry_focus_out_event; + + g_object_class_install_property ( + object_class, + PROP_HINT, + g_param_spec_string ( + "hint", + "Hint", + NULL, + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_HINT_SHOWN, + g_param_spec_boolean ( + "hint-shown", + "Hint Shown", + NULL, + FALSE, + G_PARAM_READABLE)); +} + +static void +hinted_entry_init (EHintedEntry *entry) +{ + entry->priv = E_HINTED_ENTRY_GET_PRIVATE (entry); + entry->priv->hint = g_strdup (""); /* hint must never be NULL */ +} + +GType +e_hinted_entry_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EHintedEntryClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) hinted_entry_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EHintedEntry), + 0, /* n_preallocs */ + (GInstanceInitFunc) hinted_entry_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_ENTRY, "EHintedEntry", &type_info, 0); + } + + return type; +} + +GtkWidget * +e_hinted_entry_new (void) +{ + return g_object_new (E_TYPE_HINTED_ENTRY, NULL); +} + +const gchar * +e_hinted_entry_get_hint (EHintedEntry *entry) +{ + g_return_val_if_fail (E_IS_HINTED_ENTRY (entry), NULL); + + return entry->priv->hint; +} + +void +e_hinted_entry_set_hint (EHintedEntry *entry, + const gchar *hint) +{ + g_return_if_fail (E_IS_HINTED_ENTRY (entry)); + + if (hint == NULL) + hint = ""; + + g_free (entry->priv->hint); + entry->priv->hint = g_strdup (hint); + + if (e_hinted_entry_get_hint_shown (entry)) + gtk_entry_set_text (GTK_ENTRY (entry), hint); + + g_object_notify (G_OBJECT (entry), "hint"); +} + +gboolean +e_hinted_entry_get_hint_shown (EHintedEntry *entry) +{ + g_return_val_if_fail (E_IS_HINTED_ENTRY (entry), FALSE); + + return entry->priv->hint_shown; +} + +const gchar * +e_hinted_entry_get_text (EHintedEntry *entry) +{ + /* XXX This clumsily overrides gtk_entry_get_text(). */ + + g_return_val_if_fail (E_IS_HINTED_ENTRY (entry), NULL); + + if (e_hinted_entry_get_hint_shown (entry)) + return ""; + + return gtk_entry_get_text (GTK_ENTRY (entry)); +} + +void +e_hinted_entry_set_text (EHintedEntry *entry, + const gchar *text) +{ + /* XXX This clumsily overrides gtk_entry_set_text(). */ + + g_return_if_fail (E_IS_HINTED_ENTRY (entry)); + + if (text == NULL) + text = ""; + + if (*text == '\0' && !GTK_WIDGET_HAS_FOCUS (entry)) + hinted_entry_show_hint (entry); + else { + hinted_entry_hide_hint (entry); + gtk_entry_set_text (GTK_ENTRY (entry), text); + } +} diff --git a/widgets/misc/e-hinted-entry.h b/widgets/misc/e-hinted-entry.h new file mode 100644 index 0000000000..02379d4ad7 --- /dev/null +++ b/widgets/misc/e-hinted-entry.h @@ -0,0 +1,73 @@ +/* + * e-hinted-entry.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_HINTED_ENTRY_H +#define E_HINTED_ENTRY_H + +#include <gtk/gtk.h> + +/* Standard GObject macros */ +#define E_TYPE_HINTED_ENTRY \ + (e_hinted_entry_get_type ()) +#define E_HINTED_ENTRY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_HINTED_ENTRY, EHintedEntry)) +#define E_HINTED_ENTRY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_HINTED_ENTRY, EHintedEntryClass)) +#define E_IS_HINTED_ENTRY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_HINTED_ENTRY)) +#define E_IS_HINTED_ENTRY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_HINTED_ENTRY)) +#define E_HINTED_ENTRY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_HINTED_ENTRY, EHintedEntryClass)) + +G_BEGIN_DECLS + +typedef struct _EHintedEntry EHintedEntry; +typedef struct _EHintedEntryClass EHintedEntryClass; +typedef struct _EHintedEntryPrivate EHintedEntryPrivate; + +struct _EHintedEntry { + GtkEntry parent; + EHintedEntryPrivate *priv; +}; + +struct _EHintedEntryClass { + GtkEntryClass parent_class; +}; + +GType e_hinted_entry_get_type (void); +GtkWidget * e_hinted_entry_new (void); +const gchar * e_hinted_entry_get_hint (EHintedEntry *entry); +void e_hinted_entry_set_hint (EHintedEntry *entry, + const gchar *hint); +gboolean e_hinted_entry_get_hint_shown (EHintedEntry *entry); +const gchar * e_hinted_entry_get_text (EHintedEntry *entry); +void e_hinted_entry_set_text (EHintedEntry *entry, + const gchar *text); + +G_END_DECLS + +#endif /* E_HINTED_ENTRY_H */ diff --git a/widgets/misc/e-icon-entry.c b/widgets/misc/e-icon-entry.c deleted file mode 100644 index 87b89f61d5..0000000000 --- a/widgets/misc/e-icon-entry.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * e-icon-entry.c - * - * Author: Johnny Jacob <jjohnny@novell.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - * Copyright (C) 2003, 2004, 2005 Christian Persch - * - * This library 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) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * Adapted and modified from gtk+ code: - * - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * Modified by the GTK+ Team and others 1997-2005. See the AUTHORS - * file in the gtk+ distribution for a list of people on the GTK+ Team. - * See the ChangeLog in the gtk+ distribution files for a list of changes. - * These files are distributed with GTK+ at ftp://ftp.gtk.org/pub/gtk/. - * - */ - -#include "config.h" - -#include "e-icon-entry.h" - -#define E_ICON_ENTRY_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), E_TYPE_ICON_ENTRY, EIconEntryPrivate)) - -struct _EIconEntryPrivate -{ - GtkWidget *hbox; -}; - -static GtkWidgetClass *parent_class = NULL; - -/* private helper functions */ - -static gboolean -entry_focus_change_cb (GtkWidget *widget, - GdkEventFocus *event, - GtkWidget *entry) -{ - gtk_widget_queue_draw (entry); - - return FALSE; -} - -static void -e_icon_entry_get_borders (GtkWidget *widget, - GtkWidget *entry, - gint *xborder, - gint *yborder) -{ - gint focus_width; - gboolean interior_focus; - - g_return_if_fail (entry->style != NULL); - - gtk_widget_style_get (entry, - "focus-line-width", &focus_width, - "interior-focus", &interior_focus, - NULL); - - *xborder = entry->style->xthickness; - *yborder = entry->style->ythickness; - - if (!interior_focus) - { - *xborder += focus_width; - *yborder += focus_width; - } -} - -static void -e_icon_entry_paint (GtkWidget *widget, - GdkEventExpose *event) -{ - EIconEntry *entry = E_ICON_ENTRY (widget); - GtkWidget *entry_widget = entry->entry; - gint x = 0, y = 0, width, height, focus_width; - gboolean interior_focus; - - gtk_widget_style_get (entry_widget, - "interior-focus", &interior_focus, - "focus-line-width", &focus_width, - NULL); - - gdk_drawable_get_size (widget->window, &width, &height); - - if (GTK_WIDGET_HAS_FOCUS (entry_widget) && !interior_focus) - { - x += focus_width; - y += focus_width; - width -= 2 * focus_width; - height -= 2 * focus_width; - } - - gtk_paint_flat_box (entry_widget->style, widget->window, - GTK_WIDGET_STATE (entry_widget), GTK_SHADOW_NONE, - NULL, entry_widget, "entry_bg", - /* FIXME: was 0, 0 in gtk_entry_expose, but I think this is correct: */ - x, y, width, height); - - gtk_paint_shadow (entry_widget->style, widget->window, - GTK_STATE_NORMAL, GTK_SHADOW_IN, - NULL, entry_widget, "entry", - x, y, width, height); - - if (GTK_WIDGET_HAS_FOCUS (entry_widget) && !interior_focus) - { - x -= focus_width; - y -= focus_width; - width += 2 * focus_width; - height += 2 * focus_width; - - gtk_paint_focus (entry_widget->style, widget->window, - GTK_WIDGET_STATE (entry_widget), - NULL, entry_widget, "entry", - /* FIXME: was 0, 0 in gtk_entry_draw_frame, but I think this is correct: */ - x, y, width, height); - } -} - -/* Class implementation */ - -static void -e_icon_entry_init (EIconEntry *entry) -{ - EIconEntryPrivate *priv; - GtkWidget *widget = (GtkWidget *) entry; - - priv = entry->priv = E_ICON_ENTRY_GET_PRIVATE (entry); - - GTK_WIDGET_UNSET_FLAGS (widget, GTK_NO_WINDOW); - - priv->hbox = gtk_hbox_new (FALSE, /* FIXME */ 0); - gtk_container_add (GTK_CONTAINER (entry), priv->hbox); - - entry->entry = gtk_entry_new (); - gtk_entry_set_has_frame (GTK_ENTRY (entry->entry), FALSE); - gtk_box_pack_start (GTK_BOX (priv->hbox), entry->entry, TRUE, TRUE, /* FIXME */ 0); - - /* We need to queue a redraw when focus changes, to comply with themes - * (like Clearlooks) which draw focused and unfocused entries differently. - */ - g_signal_connect_after (entry->entry, "focus-in-event", - G_CALLBACK (entry_focus_change_cb), entry); - g_signal_connect_after (entry->entry, "focus-out-event", - G_CALLBACK (entry_focus_change_cb), entry); -} - -static void -e_icon_entry_realize (GtkWidget *widget) -{ - GdkWindowAttr attributes; - gint attributes_mask; - gint border_width; - - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); - - border_width = GTK_CONTAINER (widget)->border_width; - - attributes.x = widget->allocation.x + border_width; - attributes.y = widget->allocation.y + border_width; - attributes.width = widget->allocation.width - 2 * border_width; - attributes.height = widget->allocation.height - 2 * border_width; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events (widget) - | GDK_EXPOSURE_MASK; - - attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); - attributes.wclass = GDK_INPUT_OUTPUT; - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - - widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), - &attributes, attributes_mask); - gdk_window_set_user_data (widget->window, widget); - - widget->style = gtk_style_attach (widget->style, widget->window); - - gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); -} - -static void -e_icon_entry_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - EIconEntry *entry = E_ICON_ENTRY (widget); - GtkContainer *container = GTK_CONTAINER (widget); - GtkBin *bin = GTK_BIN (widget); - gint xborder, yborder; - - requisition->width = requisition->height = container->border_width * 2; - - gtk_widget_ensure_style (entry->entry); - e_icon_entry_get_borders (widget, entry->entry, &xborder, &yborder); - - if (GTK_WIDGET_VISIBLE (bin->child)) - { - GtkRequisition child_requisition; - - gtk_widget_size_request (bin->child, &child_requisition); - requisition->width += child_requisition.width; - requisition->height += child_requisition.height; - } - - requisition->width += 2 * xborder; - requisition->height += 2 * yborder; -} - -static void -e_icon_entry_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - EIconEntry *entry = E_ICON_ENTRY (widget); - GtkContainer *container = GTK_CONTAINER (widget); - GtkBin *bin = GTK_BIN (widget); - GtkAllocation child_allocation; - gint xborder, yborder; - - widget->allocation = *allocation; - - e_icon_entry_get_borders (widget, entry->entry, &xborder, &yborder); - - if (GTK_WIDGET_REALIZED (widget)) - { - child_allocation.x = container->border_width; - child_allocation.y = container->border_width; - child_allocation.width = MAX (allocation->width - container->border_width * 2, 0); - child_allocation.height = MAX (allocation->height - container->border_width * 2, 0); - - gdk_window_move_resize (widget->window, - allocation->x + child_allocation.x, - allocation->y + child_allocation.y, - child_allocation.width, - child_allocation.height); - } - - child_allocation.x = container->border_width + xborder; - child_allocation.y = container->border_width + yborder; - child_allocation.width = MAX (allocation->width - (container->border_width + xborder) * 2, 0); - child_allocation.height = MAX (allocation->height - (container->border_width + yborder) * 2, 0); - - gtk_widget_size_allocate (bin->child, &child_allocation); -} - -static gboolean -e_icon_entry_expose (GtkWidget *widget, - GdkEventExpose *event) -{ - if (GTK_WIDGET_DRAWABLE (widget) && - event->window == widget->window) - { - e_icon_entry_paint (widget, event); - } - - return parent_class->expose_event (widget, event); -} - -static void -e_icon_entry_class_init (EIconEntryClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - parent_class = GTK_WIDGET_CLASS (g_type_class_peek_parent (klass)); - - widget_class->realize = e_icon_entry_realize; - widget_class->size_request = e_icon_entry_size_request; - widget_class->size_allocate = e_icon_entry_size_allocate; - widget_class->expose_event = e_icon_entry_expose; - - g_type_class_add_private (object_class, sizeof (EIconEntryPrivate)); -} - -GType -e_icon_entry_get_type (void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) - { - static const GTypeInfo our_info = - { - sizeof (EIconEntryClass), - NULL, - NULL, - (GClassInitFunc) e_icon_entry_class_init, - NULL, - NULL, - sizeof (EIconEntry), - 0, - (GInstanceInitFunc) e_icon_entry_init - }; - - type = g_type_register_static (GTK_TYPE_BIN, - "EIconEntry", - &our_info, 0); - } - - return type; -} - -/* public functions */ - -GtkWidget * -e_icon_entry_new (void) -{ - return GTK_WIDGET (g_object_new (E_TYPE_ICON_ENTRY, NULL)); -} - -void -e_icon_entry_pack_widget (EIconEntry *entry, - GtkWidget *widget, - gboolean start) -{ - EIconEntryPrivate *priv; - - g_return_if_fail (E_IS_ICON_ENTRY (entry)); - - priv = entry->priv; - - if (start) - { - gtk_box_pack_start (GTK_BOX (priv->hbox), widget, FALSE, FALSE, /* FIXME */ 2); - gtk_box_reorder_child (GTK_BOX (priv->hbox), widget, 0); - } - else - { - gtk_box_pack_end (GTK_BOX (priv->hbox), widget, FALSE, FALSE, /* FIXME */ 2); - } -} - -static void -set_cursor (GtkWidget *widget, GdkEventCrossing *event, gpointer dummy) -{ - - if (event->type == GDK_ENTER_NOTIFY) - gdk_window_set_cursor (widget->window, gdk_cursor_new (GDK_HAND1)); - else - gdk_window_set_cursor (widget->window, gdk_cursor_new (GDK_LEFT_PTR)); - -} - -GtkWidget * -e_icon_entry_create_button (const gchar *stock) -{ - GtkWidget *eventbox; - GtkWidget *image; - - eventbox = gtk_event_box_new (); - gtk_container_set_border_width (GTK_CONTAINER (eventbox), 2); - gtk_event_box_set_visible_window (GTK_EVENT_BOX (eventbox), FALSE); - - image = gtk_image_new_from_stock (stock, GTK_ICON_SIZE_MENU); - gtk_container_add (GTK_CONTAINER (eventbox), image); - - g_signal_connect_after (eventbox, "enter-notify-event", (GCallback) set_cursor, NULL); - g_signal_connect_after (eventbox, "leave-notify-event", (GCallback) set_cursor, NULL); - - return eventbox; -} - -GtkWidget * -e_icon_entry_create_text (const gchar *text) -{ - GtkWidget *eventbox; - GtkWidget *image; - - eventbox = gtk_event_box_new (); - gtk_container_set_border_width (GTK_CONTAINER (eventbox), 2); - gtk_event_box_set_visible_window (GTK_EVENT_BOX (eventbox), FALSE); - - image = gtk_label_new (text); - gtk_container_add (GTK_CONTAINER (eventbox), image); - g_object_set_data ((GObject *)eventbox, "lbl", image); - g_signal_connect_after (eventbox, "enter-notify-event", (GCallback) set_cursor, NULL); - g_signal_connect_after (eventbox, "leave-notify-event", (GCallback) set_cursor, NULL); - - return eventbox; -} - -GtkWidget * -e_icon_entry_create_separator () -{ - GtkWidget *eventbox; - GtkWidget *image; - - eventbox = gtk_event_box_new (); - gtk_container_set_border_width (GTK_CONTAINER (eventbox), 0); - gtk_event_box_set_visible_window (GTK_EVENT_BOX (eventbox), FALSE); - - image = (GtkWidget *)gtk_separator_tool_item_new (); - gtk_container_add (GTK_CONTAINER (eventbox), image); - - return eventbox; -} - -GtkWidget * -e_icon_entry_get_entry (EIconEntry *entry) -{ - g_return_val_if_fail (E_IS_ICON_ENTRY (entry), NULL); - - return entry->entry; -} diff --git a/widgets/misc/e-icon-entry.h b/widgets/misc/e-icon-entry.h deleted file mode 100644 index cde735ba6f..0000000000 --- a/widgets/misc/e-icon-entry.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * e-icon-entry.h - * - * Authors: Johnny Jacob <jjohnny@novell.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - * Adapted and modified from Epiphany. - * - * Copyright (C) 2003, 2004, 2005 Christian Persch - * - * This library 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) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * Adapted and modified from gtk+ code: - * - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS - * file in the gtk+ distribution for a list of people on the GTK+ Team. - * See the ChangeLog in the gtk+ distribution files for a list of changes. - * These files are distributed with GTK+ at ftp://ftp.gtk.org/pub/gtk/. - * - */ - -#ifndef E_ICON_ENTRY_H -#define E_ICON_ENTRY_H - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define E_TYPE_ICON_ENTRY (e_icon_entry_get_type()) -#define E_ICON_ENTRY(object) (G_TYPE_CHECK_INSTANCE_CAST((object), E_TYPE_ICON_ENTRY, EIconEntry)) -#define E_ICON_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), E_TYPE_ICON_ENTRY, EIconEntryClass)) -#define E_IS_ICON_ENTRY(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), E_TYPE_ICON_ENTRY)) -#define E_IS_ICON_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), E_TYPE_ICON_ENTRY)) -#define E_ICON_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), E_TYPE_ICON_ENTRY, EIconEntryClass)) - -typedef struct _EIconEntryClass EIconEntryClass; -typedef struct _EIconEntry EIconEntry; -typedef struct _EIconEntryPrivate EIconEntryPrivate; - -struct _EIconEntryClass -{ - GtkBinClass parent_class; -}; - -struct _EIconEntry -{ - GtkBin parent_object; - - /*< public >*/ - GtkWidget *entry; - - /*< private >*/ - EIconEntryPrivate *priv; -}; - -GType e_icon_entry_get_type (void); - -GtkWidget *e_icon_entry_new (void); - -void e_icon_entry_pack_widget (EIconEntry *entry, - GtkWidget *widget, - gboolean start); - -GtkWidget *e_icon_entry_get_entry (EIconEntry *entry); - -GtkWidget *e_icon_entry_create_button (const gchar *stock); -GtkWidget * e_icon_entry_create_text (const gchar *text); -GtkWidget * e_icon_entry_create_separator (void); - -G_END_DECLS - -#endif diff --git a/widgets/misc/e-image-chooser.c b/widgets/misc/e-image-chooser.c index e5a20e5303..32a3f2a899 100644 --- a/widgets/misc/e-image-chooser.c +++ b/widgets/misc/e-image-chooser.c @@ -1,4 +1,6 @@ /* + * e-image-chooser.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 @@ -13,9 +15,6 @@ * 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) * */ @@ -28,23 +27,20 @@ #include <glib/gi18n.h> #include "e-image-chooser.h" -#include "e-util/e-icon-factory.h" #include "e-util/e-util.h" -#define d(x) +#define E_IMAGE_CHOOSER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_IMAGE_CHOOSER, EImageChooserPrivate)) struct _EImageChooserPrivate { - GtkWidget *frame; GtkWidget *image; - GtkWidget *browse_button; gchar *image_buf; - gint image_buf_size; - gint image_width; - gint image_height; - - gboolean editable; + gint image_buf_size; + gint image_width; + gint image_height; }; enum { @@ -52,182 +48,24 @@ enum { LAST_SIGNAL }; -static gint image_chooser_signals [LAST_SIGNAL] = { 0 }; - -static void e_image_chooser_init (EImageChooser *chooser); -static void e_image_chooser_class_init (EImageChooserClass *klass); -#if 0 -static void e_image_chooser_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void e_image_chooser_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); -#endif -static void e_image_chooser_dispose (GObject *object); - -static gboolean image_drag_motion_cb (GtkWidget *widget, - GdkDragContext *context, - gint x, gint y, guint time, EImageChooser *chooser); -static void image_drag_leave_cb (GtkWidget *widget, - GdkDragContext *context, - guint time, EImageChooser *chooser); -static gboolean image_drag_drop_cb (GtkWidget *widget, - GdkDragContext *context, - gint x, gint y, guint time, EImageChooser *chooser); -static void image_drag_data_received_cb (GtkWidget *widget, - GdkDragContext *context, - gint x, gint y, - GtkSelectionData *selection_data, - guint info, guint time, EImageChooser *chooser); - -static GtkObjectClass *parent_class = NULL; -#define PARENT_TYPE GTK_TYPE_VBOX - -enum DndTargetType { - DND_TARGET_TYPE_URI_LIST -}; -#define URI_LIST_TYPE "text/uri-list" - -static GtkTargetEntry image_drag_types[] = { - { (gchar *) URI_LIST_TYPE, 0, DND_TARGET_TYPE_URI_LIST }, -}; -static const gint num_image_drag_types = sizeof (image_drag_types) / sizeof (image_drag_types[0]); +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; -GtkWidget * -e_image_chooser_new (void) -{ - return g_object_new (E_TYPE_IMAGE_CHOOSER, NULL); -} - -GType -e_image_chooser_get_type (void) -{ - static GType eic_type = 0; - - if (!eic_type) { - static const GTypeInfo eic_info = { - sizeof (EImageChooserClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_image_chooser_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (EImageChooser), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_image_chooser_init, - }; - - eic_type = g_type_register_static (PARENT_TYPE, "EImageChooser", &eic_info, 0); - } - - return eic_type; -} - -static void -e_image_chooser_class_init (EImageChooserClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - parent_class = g_type_class_ref (PARENT_TYPE); - - image_chooser_signals [CHANGED] = - g_signal_new ("changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (EImageChooserClass, changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - /* - object_class->set_property = e_image_chooser_set_property; - object_class->get_property = e_image_chooser_get_property; - */ - object_class->dispose = e_image_chooser_dispose; -} - -#ifdef UI_CHANGE_OK -static void -browse_for_image_cb (GtkWidget *button, gpointer data) -{ -} -#endif - -static void -e_image_chooser_init (EImageChooser *chooser) -{ - EImageChooserPrivate *priv; - GtkWidget *alignment; - - priv = chooser->priv = g_new0 (EImageChooserPrivate, 1); - - alignment = gtk_alignment_new (0, 0, 0, 0); - priv->frame = gtk_frame_new (""); - priv->image = gtk_image_new (); - - gtk_container_add (GTK_CONTAINER (alignment), priv->image); - -#ifdef UI_CHANGE_OK - priv->browse_button = gtk_button_new_with_label (_("Choose Image")); -#endif - - gtk_frame_set_shadow_type (GTK_FRAME (priv->frame), GTK_SHADOW_NONE); - - gtk_container_add (GTK_CONTAINER (priv->frame), alignment); - gtk_box_set_homogeneous (GTK_BOX (chooser), FALSE); - gtk_box_pack_start (GTK_BOX (chooser), priv->frame, TRUE, TRUE, 0); -#ifdef UI_CHANGE_OK - gtk_box_pack_start (GTK_BOX (chooser), priv->browse_button, FALSE, FALSE, 0); - - g_signal_connect (priv->browse_button, "clicked", G_CALLBACK (browse_for_image_cb), NULL); -#endif - - gtk_drag_dest_set (priv->image, 0, image_drag_types, num_image_drag_types, GDK_ACTION_COPY); - g_signal_connect (priv->image, - "drag_motion", G_CALLBACK (image_drag_motion_cb), chooser); - g_signal_connect (priv->image, - "drag_leave", G_CALLBACK (image_drag_leave_cb), chooser); - g_signal_connect (priv->image, - "drag_drop", G_CALLBACK (image_drag_drop_cb), chooser); - g_signal_connect (priv->image, - "drag_data_received", G_CALLBACK (image_drag_data_received_cb), chooser); - - gtk_widget_show_all (priv->frame); -#ifdef UI_CHANGE_OK - gtk_widget_show (priv->browse_button); -#endif - - /* we default to being editable */ - priv->editable = TRUE; -} - -static void -e_image_chooser_dispose (GObject *object) -{ - EImageChooser *eic = E_IMAGE_CHOOSER (object); - - if (eic->priv) { - EImageChooserPrivate *priv = eic->priv; - - if (priv->image_buf) { - g_free (priv->image_buf); - priv->image_buf = NULL; - } - - g_free (eic->priv); - eic->priv = NULL; - } - - if (G_OBJECT_CLASS (parent_class)->dispose) - (* G_OBJECT_CLASS (parent_class)->dispose) (object); -} +#define URI_LIST_TYPE "text/uri-list" static gboolean set_image_from_data (EImageChooser *chooser, - gchar *data, gint length) + gchar *data, + gint length) { - gboolean rv = FALSE; - GdkPixbufLoader *loader = gdk_pixbuf_loader_new (); + GdkPixbufLoader *loader; GdkPixbuf *pixbuf; + gfloat scale; + gint new_height; + gint new_width; - gdk_pixbuf_loader_write (loader, (guchar *)data, length, NULL); + loader = gdk_pixbuf_loader_new (); + gdk_pixbuf_loader_write (loader, (guchar *) data, length, NULL); gdk_pixbuf_loader_close (loader, NULL); pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); @@ -236,98 +74,92 @@ set_image_from_data (EImageChooser *chooser, g_object_unref (loader); - if (pixbuf) { - GdkPixbuf *scaled; - GdkPixbuf *composite; - - gfloat scale; - gint new_height, new_width; - - new_height = gdk_pixbuf_get_height (pixbuf); - new_width = gdk_pixbuf_get_width (pixbuf); - - d (printf ("new dimensions = (%d,%d)\n", new_width, new_height)); - - if (chooser->priv->image_height == 0 - && chooser->priv->image_width == 0) { - d (printf ("initial setting of an image. no scaling\n")); - scale = 1.0; - } - else if (chooser->priv->image_height < new_height - || chooser->priv->image_width < new_width) { - /* we need to scale down */ - d (printf ("we need to scale down\n")); - if (new_height > new_width) - scale = (gfloat)chooser->priv->image_height / new_height; - else - scale = (gfloat)chooser->priv->image_width / new_width; - } - else { - /* we need to scale up */ - d (printf ("we need to scale up\n")); - if (new_height > new_width) - scale = (gfloat)new_height / chooser->priv->image_height; - else - scale = (gfloat)new_width / chooser->priv->image_width; - } - - d (printf ("scale = %g\n", scale)); + if (pixbuf == NULL) + return FALSE; - if (scale == 1.0) { - gtk_image_set_from_pixbuf (GTK_IMAGE (chooser->priv->image), pixbuf); + new_height = gdk_pixbuf_get_height (pixbuf); + new_width = gdk_pixbuf_get_width (pixbuf); + + if (chooser->priv->image_height == 0 + && chooser->priv->image_width == 0) { + scale = 1.0; + } else if (chooser->priv->image_height < new_height + || chooser->priv->image_width < new_width) { + /* we need to scale down */ + if (new_height > new_width) + scale = (gfloat)chooser->priv->image_height / new_height; + else + scale = (gfloat)chooser->priv->image_width / new_width; + } else { + /* we need to scale up */ + if (new_height > new_width) + scale = (gfloat)new_height / chooser->priv->image_height; + else + scale = (gfloat)new_width / chooser->priv->image_width; + } - chooser->priv->image_width = new_width; - chooser->priv->image_height = new_height; - } - else { - new_width *= scale; - new_height *= scale; - new_width = MIN (new_width, chooser->priv->image_width); - new_height = MIN (new_height, chooser->priv->image_height); + if (scale == 1.0) { + gtk_image_set_from_pixbuf ( + GTK_IMAGE (chooser->priv->image), pixbuf); + chooser->priv->image_width = new_width; + chooser->priv->image_height = new_height; + } else { + GdkPixbuf *scaled; + GdkPixbuf *composite; - d (printf ("new scaled dimensions = (%d,%d)\n", new_width, new_height)); + new_width *= scale; + new_height *= scale; + new_width = MIN (new_width, chooser->priv->image_width); + new_height = MIN (new_height, chooser->priv->image_height); - scaled = e_icon_factory_pixbuf_scale (pixbuf, new_width, new_height); + scaled = gdk_pixbuf_scale_simple ( + pixbuf, new_width, new_height, + GDK_INTERP_BILINEAR); - composite = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, gdk_pixbuf_get_bits_per_sample (pixbuf), - chooser->priv->image_width, chooser->priv->image_height); + composite = gdk_pixbuf_new ( + GDK_COLORSPACE_RGB, TRUE, + gdk_pixbuf_get_bits_per_sample (pixbuf), + chooser->priv->image_width, + chooser->priv->image_height); - gdk_pixbuf_fill (composite, 0x00000000); + gdk_pixbuf_fill (composite, 0x00000000); - gdk_pixbuf_copy_area (scaled, 0, 0, new_width, new_height, - composite, - chooser->priv->image_width / 2 - new_width / 2, - chooser->priv->image_height / 2 - new_height / 2); + gdk_pixbuf_copy_area ( + scaled, 0, 0, new_width, new_height, + composite, + chooser->priv->image_width / 2 - new_width / 2, + chooser->priv->image_height / 2 - new_height / 2); - gtk_image_set_from_pixbuf (GTK_IMAGE (chooser->priv->image), composite); - g_object_unref (scaled); - g_object_unref (composite); - } + gtk_image_set_from_pixbuf ( + GTK_IMAGE (chooser->priv->image), composite); - g_object_unref (pixbuf); + g_object_unref (scaled); + g_object_unref (composite); + } - g_free (chooser->priv->image_buf); - chooser->priv->image_buf = data; - chooser->priv->image_buf_size = length; + g_object_unref (pixbuf); - g_signal_emit (chooser, - image_chooser_signals [CHANGED], 0); + g_free (chooser->priv->image_buf); + chooser->priv->image_buf = data; + chooser->priv->image_buf_size = length; - rv = TRUE; - } + g_signal_emit (chooser, signals[CHANGED], 0); - return rv; + return TRUE; } static gboolean image_drag_motion_cb (GtkWidget *widget, - GdkDragContext *context, - gint x, gint y, guint time, EImageChooser *chooser) + GdkDragContext *context, + gint x, + gint y, + guint time, + EImageChooser *chooser) { + GtkFrame *frame; GList *p; - if (!chooser->priv->editable) - return FALSE; + frame = GTK_FRAME (chooser->priv->frame); for (p = context->targets; p != NULL; p = p->next) { gchar *possible_type; @@ -336,37 +168,45 @@ image_drag_motion_cb (GtkWidget *widget, if (!strcmp (possible_type, URI_LIST_TYPE)) { g_free (possible_type); gdk_drag_status (context, GDK_ACTION_COPY, time); - gtk_frame_set_shadow_type (GTK_FRAME (chooser->priv->frame), GTK_SHADOW_IN); + gtk_frame_set_shadow_type (frame, GTK_SHADOW_IN); return TRUE; } g_free (possible_type); } - gtk_frame_set_shadow_type (GTK_FRAME (chooser->priv->frame), GTK_SHADOW_NONE); + gtk_frame_set_shadow_type (frame, GTK_SHADOW_NONE); + return FALSE; } static void image_drag_leave_cb (GtkWidget *widget, - GdkDragContext *context, - guint time, EImageChooser *chooser) + GdkDragContext *context, + guint time, + EImageChooser *chooser) { - gtk_frame_set_shadow_type (GTK_FRAME (chooser->priv->frame), GTK_SHADOW_NONE); + GtkFrame *frame; + + frame = GTK_FRAME (chooser->priv->frame); + gtk_frame_set_shadow_type (frame, GTK_SHADOW_NONE); } static gboolean image_drag_drop_cb (GtkWidget *widget, - GdkDragContext *context, - gint x, gint y, guint time, EImageChooser *chooser) + GdkDragContext *context, + gint x, + gint y, + guint time, + EImageChooser *chooser) { + GtkFrame *frame; GList *p; - if (!chooser->priv->editable) - return FALSE; + frame = GTK_FRAME (chooser->priv->frame); if (context->targets == NULL) { - gtk_frame_set_shadow_type (GTK_FRAME (chooser->priv->frame), GTK_SHADOW_NONE); + gtk_frame_set_shadow_type (frame, GTK_SHADOW_NONE); return FALSE; } @@ -376,77 +216,205 @@ image_drag_drop_cb (GtkWidget *widget, possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data)); if (!strcmp (possible_type, URI_LIST_TYPE)) { g_free (possible_type); - gtk_drag_get_data (widget, context, - GDK_POINTER_TO_ATOM (p->data), - time); - gtk_frame_set_shadow_type (GTK_FRAME (chooser->priv->frame), GTK_SHADOW_NONE); + gtk_drag_get_data ( + widget, context, + GDK_POINTER_TO_ATOM (p->data), time); + gtk_frame_set_shadow_type (frame, GTK_SHADOW_NONE); return TRUE; } g_free (possible_type); } - gtk_frame_set_shadow_type (GTK_FRAME (chooser->priv->frame), GTK_SHADOW_NONE); + gtk_frame_set_shadow_type (frame, GTK_SHADOW_NONE); + return FALSE; } static void image_drag_data_received_cb (GtkWidget *widget, - GdkDragContext *context, - gint x, gint y, - GtkSelectionData *selection_data, - guint info, guint time, EImageChooser *chooser) + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time, + EImageChooser *chooser) { - gchar *target_type; gboolean handled = FALSE; + gchar **uris; + gchar *buf = NULL; + gsize read = 0; + GError *error = NULL; - target_type = gdk_atom_name (selection_data->target); + uris = gtk_selection_data_get_uris (selection_data); - if (!strcmp (target_type, URI_LIST_TYPE)) { - GError *error = NULL; - gchar *uri; - gchar *nl = strstr ((gchar *)selection_data->data, "\r\n"); - gchar *buf = NULL; - gsize read = 0; + if (uris == NULL) + goto exit; - if (nl) - uri = g_strndup ((gchar *)selection_data->data, nl - (gchar *)selection_data->data); - else - uri = g_strdup ((gchar *)selection_data->data); + if (e_util_read_file (uris[0], TRUE, &buf, &read, &error) && read > 0 && buf) + handled = set_image_from_data (chooser, buf, read); - if (e_util_read_file (uri, TRUE, &buf, &read, &error) && read > 0 && buf) { - if (set_image_from_data (chooser, buf, read)) { - handled = TRUE; - } - } + if (!handled) + g_free (buf); - if (!handled) - g_free (buf); - g_free (uri); + g_strfreev (uris); - if (error) { - g_warning ("%s", error->message); - g_error_free (error); - } + if (error) { + g_warning ("%s", error->message); + g_error_free (error); } +exit: gtk_drag_finish (context, handled, FALSE, time); } - +static void +image_chooser_dispose (GObject *object) +{ + EImageChooserPrivate *priv; + + priv = E_IMAGE_CHOOSER_GET_PRIVATE (object); + + if (priv->frame != NULL) { + g_object_unref (priv->frame); + priv->frame = NULL; + } + + if (priv->image != NULL) { + g_object_unref (priv->image); + priv->image = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +image_chooser_finalize (GObject *object) +{ + EImageChooserPrivate *priv; + + priv = E_IMAGE_CHOOSER_GET_PRIVATE (object); + + g_free (priv->image_buf); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +e_image_chooser_class_init (EImageChooserClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EImageChooserPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->dispose = image_chooser_dispose; + object_class->finalize = image_chooser_finalize; + + signals[CHANGED] = g_signal_new ( + "changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EImageChooserClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +e_image_chooser_init (EImageChooser *chooser) +{ + GtkWidget *container; + GtkWidget *widget; + + chooser->priv = E_IMAGE_CHOOSER_GET_PRIVATE (chooser); + + container = GTK_WIDGET (chooser); + + widget = gtk_frame_new (""); + gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_NONE); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + chooser->priv->frame = g_object_ref (widget); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_alignment_new (0, 0, 0, 0); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_image_new (); + gtk_container_add (GTK_CONTAINER (container), widget); + chooser->priv->image = g_object_ref (widget); + gtk_widget_show (widget); + + gtk_drag_dest_set (widget, 0, NULL, 0, GDK_ACTION_COPY); + gtk_drag_dest_add_uri_targets (widget); + + g_signal_connect ( + widget, "drag-motion", + G_CALLBACK (image_drag_motion_cb), chooser); + g_signal_connect ( + widget, "drag-leave", + G_CALLBACK (image_drag_leave_cb), chooser); + g_signal_connect ( + widget, "drag-drop", + G_CALLBACK (image_drag_drop_cb), chooser); + g_signal_connect ( + widget, "drag-data-received", + G_CALLBACK (image_drag_data_received_cb), chooser); +} + +GType +e_image_chooser_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EImageChooserClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) e_image_chooser_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EImageChooser), + 0, /* n_preallocs */ + (GInstanceInitFunc) e_image_chooser_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_VBOX, "EImageChooser", &type_info, 0); + } + + return type; +} + +GtkWidget * +e_image_chooser_new (void) +{ + return g_object_new (E_TYPE_IMAGE_CHOOSER, NULL); +} gboolean -e_image_chooser_set_from_file (EImageChooser *chooser, const gchar *filename) +e_image_chooser_set_from_file (EImageChooser *chooser, + const gchar *filename) { gchar *data; gsize data_length; g_return_val_if_fail (E_IS_IMAGE_CHOOSER (chooser), FALSE); - g_return_val_if_fail (filename, FALSE); + g_return_val_if_fail (filename != NULL, FALSE); - if (!g_file_get_contents (filename, &data, &data_length, NULL)) { + if (!g_file_get_contents (filename, &data, &data_length, NULL)) return FALSE; - } if (!set_image_from_data (chooser, data, data_length)) g_free (data); @@ -454,18 +422,10 @@ e_image_chooser_set_from_file (EImageChooser *chooser, const gchar *filename) return TRUE; } -void -e_image_chooser_set_editable (EImageChooser *chooser, gboolean editable) -{ - g_return_if_fail (E_IS_IMAGE_CHOOSER (chooser)); - - chooser->priv->editable = editable; - - gtk_widget_set_sensitive (chooser->priv->browse_button, editable); -} - gboolean -e_image_chooser_get_image_data (EImageChooser *chooser, gchar **data, gsize *data_length) +e_image_chooser_get_image_data (EImageChooser *chooser, + gchar **data, + gsize *data_length) { g_return_val_if_fail (E_IS_IMAGE_CHOOSER (chooser), FALSE); g_return_val_if_fail (data != NULL, FALSE); @@ -479,7 +439,9 @@ e_image_chooser_get_image_data (EImageChooser *chooser, gchar **data, gsize *dat } gboolean -e_image_chooser_set_image_data (EImageChooser *chooser, gchar *data, gsize data_length) +e_image_chooser_set_image_data (EImageChooser *chooser, + gchar *data, + gsize data_length) { gchar *buf; diff --git a/widgets/misc/e-image-chooser.h b/widgets/misc/e-image-chooser.h index ece1419633..7116500dc4 100644 --- a/widgets/misc/e-image-chooser.h +++ b/widgets/misc/e-image-chooser.h @@ -1,4 +1,5 @@ /* + * e-image-chooser.h * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -14,53 +15,61 @@ * 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 _E_IMAGE_CHOOSER_H_ -#define _E_IMAGE_CHOOSER_H_ +#ifndef E_IMAGE_CHOOSER_H +#define E_IMAGE_CHOOSER_H #include <gtk/gtk.h> -G_BEGIN_DECLS +/* Standard GObject macros */ +#define E_TYPE_IMAGE_CHOOSER \ + (e_image_chooser_get_type ()) +#define E_IMAGE_CHOOSER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_IMAGE_CHOOSER, EImageChooser)) +#define E_IMAGE_CHOOSER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_IMAGE_CHOOSER, EImageChooserClass)) +#define E_IS_IMAGE_CHOOSER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_IMAGE_CHOOSER)) +#define E_IS_IMAGE_CHOOSER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_IMAGE_CHOOSER)) +#define E_IMAGE_CHOOSER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_IMAGE_CHOOSER, EImageChooserClass)) -#define E_TYPE_IMAGE_CHOOSER (e_image_chooser_get_type ()) -#define E_IMAGE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_IMAGE_CHOOSER, EImageChooser)) -#define E_IMAGE_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_IMAGE_CHOOSER, EImageChooserClass)) -#define E_IS_IMAGE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_IMAGE_CHOOSER)) -#define E_IS_IMAGE_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_IMAGE_CHOOSER)) +G_BEGIN_DECLS -typedef struct _EImageChooser EImageChooser; -typedef struct _EImageChooserClass EImageChooserClass; +typedef struct _EImageChooser EImageChooser; +typedef struct _EImageChooserClass EImageChooserClass; typedef struct _EImageChooserPrivate EImageChooserPrivate; -struct _EImageChooser -{ +struct _EImageChooser { GtkVBox parent; - EImageChooserPrivate *priv; }; -struct _EImageChooserClass -{ +struct _EImageChooserClass { GtkVBoxClass parent_class; /* signals */ void (*changed) (EImageChooser *chooser); - }; -GtkWidget *e_image_chooser_new (void); -GType e_image_chooser_get_type (void); - -gboolean e_image_chooser_set_from_file (EImageChooser *chooser, const gchar *filename); -gboolean e_image_chooser_set_image_data (EImageChooser *chooser, gchar *data, gsize data_length); -void e_image_chooser_set_editable (EImageChooser *chooser, gboolean editable); - -gboolean e_image_chooser_get_image_data (EImageChooser *chooser, gchar **data, gsize *data_length); +GType e_image_chooser_get_type (void); +GtkWidget * e_image_chooser_new (void); +gboolean e_image_chooser_set_from_file (EImageChooser *chooser, + const gchar *filename); +gboolean e_image_chooser_set_image_data (EImageChooser *chooser, + gchar *data, + gsize data_length); +gboolean e_image_chooser_get_image_data (EImageChooser *chooser, + gchar **data, + gsize *data_length); -#endif /* _E_IMAGE_CHOOSER_H_ */ +#endif /* E_IMAGE_CHOOSER_H */ diff --git a/widgets/misc/e-info-label.c b/widgets/misc/e-info-label.c deleted file mode 100644 index 3333d47202..0000000000 --- a/widgets/misc/e-info-label.c +++ /dev/null @@ -1,246 +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 "e-info-label.h" - -static GtkHBoxClass *el_parent; - -static void -el_init(GObject *o) -{ - /*EInfoLabel *el = (EInfoLabel *)o;*/ -} - -static void -el_finalise(GObject *o) -{ - ((GObjectClass *)el_parent)->finalize(o); -} - -static void -el_destroy (GtkObject *o) -{ - ((EInfoLabel *)o)->location = NULL; - ((EInfoLabel *)o)->info = NULL; - - ((GtkObjectClass *)el_parent)->destroy(o); -} - -static gint -el_expose_event(GtkWidget *w, GdkEventExpose *event) -{ - gint x = ((GtkContainer *)w)->border_width; - - /* This seems a hack to me, but playing with styles wouldn't affect the background */ - gtk_paint_flat_box(w->style, w->window, - GTK_STATE_ACTIVE, GTK_SHADOW_NONE, - &event->area, w, "EInfoLabel", - w->allocation.x+x, w->allocation.y+x, - w->allocation.width-x*2, w->allocation.height-x*2); - - return ((GtkWidgetClass *)el_parent)->expose_event(w, event); -} - -static gint -get_text_full_width (GtkWidget *label) -{ - PangoLayout *layout; - PangoRectangle rect; - gint width; - - g_return_val_if_fail (GTK_IS_LABEL (label), 0); - - layout = gtk_label_get_layout (GTK_LABEL (label)); - - if (!layout) - return 0; - - width = pango_layout_get_width (layout); - pango_layout_set_width (layout, -1); - pango_layout_get_extents (layout, NULL, &rect); - pango_layout_set_width (layout, width); - - return PANGO_PIXELS (rect.width); -} - -static void -el_size_allocate (GtkWidget *widget, GtkAllocation *pallocation) -{ - EInfoLabel *el; - GtkAllocation allocation; - gint full_loc, full_nfo; - gint diff; - - /* let calculate parent class first, and then just make it not divide evenly */ - ((GtkWidgetClass *)el_parent)->size_allocate (widget, pallocation); - - g_return_if_fail (widget!= NULL); - - el = (EInfoLabel*) widget; - - if (!el->location) - return; - - full_loc = get_text_full_width (el->location) + 1; - full_nfo = get_text_full_width (el->info) + 1; - - /* do not know the width of text, thus return */ - if (full_loc == 1 && full_nfo == 1) - return; - - if (el->location->allocation.width + el->info->allocation.width >= full_loc + full_nfo) { - /* allocate for location only as many pixels as it requires to not ellipsize - and keep rest for the info part */ - diff = el->location->allocation.width - full_loc; - } else { - /* make both shorter, but based on the ratio of its full widths */ - gint total_have = el->location->allocation.width + el->info->allocation.width; - gint total_full = full_loc + full_nfo; - - diff = el->location->allocation.width - full_loc * total_have / total_full; - } - - if (!diff) - return; - - allocation = el->location->allocation; - allocation.width -= diff; - gtk_widget_size_allocate (el->location, &allocation); - - allocation = el->info->allocation; - allocation.x -= diff; - allocation.width += diff; - gtk_widget_size_allocate (el->info, &allocation); -} - -static void -el_class_init(GObjectClass *klass) -{ - klass->finalize = el_finalise; - - ((GtkObjectClass *)klass)->destroy = el_destroy; - ((GtkWidgetClass *)klass)->expose_event = el_expose_event; - ((GtkWidgetClass *)klass)->size_allocate = el_size_allocate; -} - -GType -e_info_label_get_type(void) -{ - static GType type = 0; - - if (type == 0) { - static const GTypeInfo info = { - sizeof(EInfoLabelClass), - NULL, NULL, - (GClassInitFunc)el_class_init, - NULL, NULL, - sizeof(EInfoLabel), 0, - (GInstanceInitFunc)el_init - }; - el_parent = g_type_class_ref(gtk_hbox_get_type()); - type = g_type_register_static(gtk_hbox_get_type(), "EInfoLabel", &info, 0); - } - - return type; -} - -/** - * e_info_label_new: - * @icon: - * - * Create a new info label widget. @icon is the name of the icon - * (from the icon theme) to use for the icon image. - * - * Return value: - **/ -GtkWidget * -e_info_label_new(const gchar *icon) -{ - EInfoLabel *el = g_object_new(e_info_label_get_type(), NULL); - GtkWidget *image; - - image = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU); - gtk_misc_set_padding((GtkMisc *)image, 6, 6); - gtk_box_pack_start((GtkBox *)el, image, FALSE, TRUE, 0); - gtk_widget_show(image); - - gtk_container_set_border_width((GtkContainer *)el, 3); - - return (GtkWidget *)el; -} - -/** - * e_info_label_set_info: - * @el: - * @location: - * @info: - * - * Set the information to show on the label. @location is some - * context about the current view. e.g. the folder name. If the - * label is too wide, this will be truncated. - * - * @info is some info about this location. - **/ -void -e_info_label_set_info(EInfoLabel *el, const gchar *location, const gchar *info) -{ - gchar *markup; - - if (el->location == NULL) { - el->location = gtk_label_new (NULL); - el->info = gtk_label_new (NULL); - - gtk_label_set_ellipsize (GTK_LABEL (el->location), PANGO_ELLIPSIZE_END); - gtk_misc_set_alignment (GTK_MISC (el->location), 0.0, 0.5); - gtk_misc_set_padding (GTK_MISC (el->location), 0, 6); - - gtk_label_set_ellipsize (GTK_LABEL (el->info), PANGO_ELLIPSIZE_MIDDLE); - gtk_misc_set_alignment (GTK_MISC (el->info), 1.0, 0.5); - gtk_misc_set_padding (GTK_MISC (el->info), 0, 6); - - gtk_widget_show (el->location); - gtk_widget_show (el->info); - - gtk_box_pack_start ( - GTK_BOX (el), GTK_WIDGET (el->location), - TRUE, TRUE, 0); - gtk_box_pack_end ( - GTK_BOX (el), GTK_WIDGET (el->info), - TRUE, TRUE, 6); - gtk_widget_set_state (GTK_WIDGET (el), GTK_STATE_ACTIVE); - } - - markup = g_markup_printf_escaped ("<b>%s</b>", location); - gtk_label_set_markup (GTK_LABEL (el->location), markup); - g_free (markup); - - markup = g_markup_printf_escaped ("<small>%s</small>", info); - gtk_label_set_markup (GTK_LABEL (el->info), markup); - g_free (markup); -} - diff --git a/widgets/misc/e-info-label.h b/widgets/misc/e-info-label.h deleted file mode 100644 index 977cc6ac4f..0000000000 --- a/widgets/misc/e-info-label.h +++ /dev/null @@ -1,54 +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 _E_INFO_LABEL_H -#define _E_INFO_LABEL_H - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define E_INFO_LABEL_GET_CLASS(emfv) ((EInfoLabelClass *) G_OBJECT_GET_CLASS (emfv)) - -typedef struct _EInfoLabel EInfoLabel; -typedef struct _EInfoLabelClass EInfoLabelClass; - -struct _EInfoLabel { - GtkHBox parent; - - GtkWidget *location; - GtkWidget *info; -}; - -struct _EInfoLabelClass { - GtkHBoxClass parent_class; -}; - -GType e_info_label_get_type(void); - -GtkWidget *e_info_label_new(const gchar *icon); -void e_info_label_set_info(EInfoLabel *, const gchar *loc, const gchar *info); - -G_END_DECLS - -#endif /* ! _E_INFO_LABEL_H */ diff --git a/widgets/misc/e-menu-tool-button.c b/widgets/misc/e-menu-tool-button.c new file mode 100644 index 0000000000..53778e6678 --- /dev/null +++ b/widgets/misc/e-menu-tool-button.c @@ -0,0 +1,157 @@ +/* + * e-menu-tool-button.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-menu-tool-button.h" + +static gpointer parent_class; + +static GtkWidget * +menu_tool_button_clone_image (GtkWidget *source) +{ + GtkIconSize size; + GtkImageType image_type; + const gchar *icon_name; + + /* XXX This isn't general purpose because it requires that the + * source image be using a named icon. Somewhat surprised + * GTK+ doesn't offer something like this. */ + image_type = gtk_image_get_storage_type (GTK_IMAGE (source)); + g_return_val_if_fail (image_type == GTK_IMAGE_ICON_NAME, NULL); + gtk_image_get_icon_name (GTK_IMAGE (source), &icon_name, &size); + + return gtk_image_new_from_icon_name (icon_name, size); +} + +static GtkMenuItem * +menu_tool_button_get_first_menu_item (GtkMenuToolButton *menu_tool_button) +{ + GtkWidget *menu; + GList *children; + + menu = gtk_menu_tool_button_get_menu (menu_tool_button); + if (!GTK_IS_MENU (menu)) + return NULL; + + /* XXX GTK+ 2.12 provides no accessor function. */ + children = GTK_MENU_SHELL (menu)->children; + if (children == NULL) + return NULL; + + return GTK_MENU_ITEM (children->data); +} + +static void +menu_tool_button_update_button (GtkToolButton *tool_button) +{ + GtkMenuItem *menu_item; + GtkMenuToolButton *menu_tool_button; + GtkImageMenuItem *image_menu_item; + GtkAction *action; + GtkWidget *image; + gchar *tooltip = NULL; + + menu_tool_button = GTK_MENU_TOOL_BUTTON (tool_button); + menu_item = menu_tool_button_get_first_menu_item (menu_tool_button); + if (!GTK_IS_IMAGE_MENU_ITEM (menu_item)) + return; + + image_menu_item = GTK_IMAGE_MENU_ITEM (menu_item); + image = gtk_image_menu_item_get_image (image_menu_item); + if (!GTK_IS_IMAGE (image)) + return; + + image = menu_tool_button_clone_image (image); + gtk_tool_button_set_icon_widget (tool_button, image); + gtk_widget_show (image); + + /* If the menu item is a proxy for a GtkAction, extract + * the action's tooltip and use it as our own tooltip. */ + action = gtk_widget_get_action (GTK_WIDGET (menu_item)); + if (action != NULL) + g_object_get (action, "tooltip", &tooltip, NULL); + gtk_widget_set_tooltip_text (GTK_WIDGET (tool_button), tooltip); + g_free (tooltip); +} + +static void +menu_tool_button_clicked (GtkToolButton *tool_button) +{ + GtkMenuItem *menu_item; + GtkMenuToolButton *menu_tool_button; + + menu_tool_button = GTK_MENU_TOOL_BUTTON (tool_button); + menu_item = menu_tool_button_get_first_menu_item (menu_tool_button); + + if (GTK_IS_MENU_ITEM (menu_item)) + gtk_menu_item_activate (menu_item); +} + +static void +menu_tool_button_class_init (EMenuToolButtonClass *class) +{ + GtkToolButtonClass *tool_button_class; + + parent_class = g_type_class_peek_parent (class); + + tool_button_class = GTK_TOOL_BUTTON_CLASS (class); + tool_button_class->clicked = menu_tool_button_clicked; +} + +static void +menu_tool_button_init (EMenuToolButton *button) +{ + g_signal_connect ( + button, "notify::menu", + G_CALLBACK (menu_tool_button_update_button), NULL); +} + +GType +e_menu_tool_button_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + const GTypeInfo type_info = { + sizeof (EMenuToolButtonClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) menu_tool_button_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EMenuToolButton), + 0, /* n_preallocs */ + (GInstanceInitFunc) menu_tool_button_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_MENU_TOOL_BUTTON, "EMenuToolButton", + &type_info, 0); + } + + return type; +} + +GtkToolItem * +e_menu_tool_button_new (const gchar *label) +{ + return g_object_new (E_TYPE_MENU_TOOL_BUTTON, "label", label, NULL); +} diff --git a/widgets/misc/e-menu-tool-button.h b/widgets/misc/e-menu-tool-button.h new file mode 100644 index 0000000000..214f5ab217 --- /dev/null +++ b/widgets/misc/e-menu-tool-button.h @@ -0,0 +1,68 @@ +/* + * e-menu-tool-button.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) + * + */ + +/* EMenuToolButton is a variation of GtkMenuToolButton where the + * button icon always reflects the first menu item, and clicking + * the button activates the first menu item. */ + +#ifndef E_MENU_TOOL_BUTTON_H +#define E_MENU_TOOL_BUTTON_H + +#include <gtk/gtk.h> + +/* Standard GObject macros */ +#define E_TYPE_MENU_TOOL_BUTTON \ + (e_menu_tool_button_get_type ()) +#define E_MENU_TOOL_BUTTON(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MENU_TOOL_BUTTON, EMenuToolButton)) +#define E_MENU_TOOL_BUTTON_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MENU_TOOL_BUTTON, EMenuToolButtonClass)) +#define E_IS_MENU_TOOL_BUTTON(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MENU_TOOL_BUTTON)) +#define E_IS_MENU_TOOL_BUTTON_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MENU_TOOL_BUTTON)) +#define E_MENU_TOOL_BUTTON_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MENU_TOOL_BUTTON, EMenuToolButtonClass)) + +G_BEGIN_DECLS + +typedef struct _EMenuToolButton EMenuToolButton; +typedef struct _EMenuToolButtonClass EMenuToolButtonClass; + +struct _EMenuToolButton { + GtkMenuToolButton parent; +}; + +struct _EMenuToolButtonClass { + GtkMenuToolButtonClass parent_class; +}; + +GType e_menu_tool_button_get_type (void); +GtkToolItem * e_menu_tool_button_new (const gchar *label); + +G_END_DECLS + +#endif /* E_MENU_TOOL_BUTTON_H */ diff --git a/widgets/misc/e-multi-config-dialog.c b/widgets/misc/e-multi-config-dialog.c deleted file mode 100644 index 1f31ff8cc4..0000000000 --- a/widgets/misc/e-multi-config-dialog.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: - * Ettore Perazzoli <ettore@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "e-multi-config-dialog.h" - -#include <e-util/e-util.h> -#include <table/e-table-scrolled.h> -#include <table/e-table-memory-store.h> -#include <table/e-cell-pixbuf.h> -#include <table/e-cell-vbox.h> -#include <table/e-cell-text.h> - -#define SWITCH_PAGE_INTERVAL 250 - -struct _EMultiConfigDialogPrivate { - GSList *pages; - - GtkWidget *list_e_table; - ETableModel *list_e_table_model; - - GtkWidget *notebook; - - gint set_page_timeout_id; - gint set_page_timeout_page; -}; - -G_DEFINE_TYPE (EMultiConfigDialog, e_multi_config_dialog, GTK_TYPE_DIALOG) - - -/* ETable stuff. */ - -static const gchar *list_e_table_spec = - "<ETableSpecification cursor-mode=\"line\"" - " selection-mode=\"browse\"" - " no-headers=\"true\"" - " alternating-row-colors=\"false\"" - " horizontal-resize=\"true\"" - ">" - " <ETableColumn model_col=\"0\"" - " expansion=\"1.0\"" - " cell=\"vbox\"" - " minimum_width=\"32\"" - " resizable=\"true\"" - " _title=\"Category\"" - " compare=\"string\"/>" - " <ETableState>" - " <column source=\"0\"/>" - " <grouping>" - " </grouping>" - " </ETableState>" - "</ETableSpecification>"; - -/* Page handling. */ - -static GtkWidget * -create_page_container (const gchar *description, - GtkWidget *widget) -{ - GtkWidget *vbox; - - vbox = gtk_vbox_new (FALSE, 0); - - gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0); - - gtk_widget_show (widget); - gtk_widget_show (vbox); - - return vbox; -} - -/* Timeout for switching pages (so it's more comfortable navigating with the - keyboard). */ - -static gint -set_page_timeout_callback (gpointer data) -{ - EMultiConfigDialog *multi_config_dialog; - EMultiConfigDialogPrivate *priv; - - multi_config_dialog = E_MULTI_CONFIG_DIALOG (data); - priv = multi_config_dialog->priv; - - gtk_notebook_set_current_page ( - GTK_NOTEBOOK (priv->notebook), priv->set_page_timeout_page); - - priv->set_page_timeout_id = 0; - gtk_widget_grab_focus(priv->list_e_table); - return FALSE; -} - -/* Button handling. */ - -static void -do_close (EMultiConfigDialog *dialog) -{ - gtk_widget_destroy (GTK_WIDGET (dialog)); -} - -/* ETable signals. */ - -static void -table_cursor_change_callback (ETable *etable, - gint row, - gpointer data) -{ - EMultiConfigDialog *dialog; - EMultiConfigDialogPrivate *priv; - - dialog = E_MULTI_CONFIG_DIALOG (data); - priv = dialog->priv; - - if (priv->set_page_timeout_id == 0) - priv->set_page_timeout_id = g_timeout_add (SWITCH_PAGE_INTERVAL, - set_page_timeout_callback, - dialog); - - priv->set_page_timeout_page = row; -} - -/* GObject methods. */ - -static void -impl_finalize (GObject *object) -{ - EMultiConfigDialog *dialog; - EMultiConfigDialogPrivate *priv; - - dialog = E_MULTI_CONFIG_DIALOG (object); - priv = dialog->priv; - - if (priv->set_page_timeout_id != 0) - g_source_remove (priv->set_page_timeout_id); - - g_slist_free (priv->pages); - - g_free (priv); - - (* G_OBJECT_CLASS (e_multi_config_dialog_parent_class)->finalize) (object); -} - -/* GtkDialog methods. */ - -static void -impl_response (GtkDialog *dialog, gint response_id) -{ - EMultiConfigDialog *multi_config_dialog; - - multi_config_dialog = E_MULTI_CONFIG_DIALOG (dialog); - - switch (response_id) { - case GTK_RESPONSE_HELP: - e_display_help (GTK_WINDOW (dialog), "config-prefs"); - break; - case GTK_RESPONSE_CLOSE: - default: - do_close (multi_config_dialog); - break; - } -} - - -/* GObject ctors. */ - -static void -e_multi_config_dialog_class_init (EMultiConfigDialogClass *class) -{ - GObjectClass *object_class; - GtkDialogClass *dialog_class; - - object_class = G_OBJECT_CLASS (class); - object_class->finalize = impl_finalize; - - dialog_class = GTK_DIALOG_CLASS (class); - dialog_class->response = impl_response; -} - -#define RGB_COLOR(color) (((color).red & 0xff00) << 8 | \ - ((color).green & 0xff00) | \ - ((color).blue & 0xff00) >> 8) - -static void -canvas_realize (GtkWidget *widget, EMultiConfigDialog *dialog) -{ -} - -static ETableMemoryStoreColumnInfo columns[] = { - E_TABLE_MEMORY_STORE_STRING, - E_TABLE_MEMORY_STORE_PIXBUF, - E_TABLE_MEMORY_STORE_PIXBUF, - E_TABLE_MEMORY_STORE_PIXBUF, - E_TABLE_MEMORY_STORE_PIXBUF, - E_TABLE_MEMORY_STORE_TERMINATOR -}; - -static void -e_multi_config_dialog_init (EMultiConfigDialog *multi_config_dialog) -{ - EMultiConfigDialogPrivate *priv; - ETableModel *list_e_table_model; - GtkWidget *dialog_vbox; - GtkWidget *hbox; - GtkWidget *notebook; - GtkWidget *list_e_table; - ETableExtras *extras; - ECell *pixbuf; - ECell *text; - ECell *vbox; - - gtk_dialog_set_has_separator (GTK_DIALOG (multi_config_dialog), FALSE); - gtk_widget_realize (GTK_WIDGET (multi_config_dialog)); - gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (multi_config_dialog)->vbox), 0); - gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (multi_config_dialog)->action_area), 12); - - hbox = gtk_hbox_new (FALSE, 6); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 12); - dialog_vbox = GTK_DIALOG (multi_config_dialog)->vbox; - - gtk_container_add (GTK_CONTAINER (dialog_vbox), hbox); - - list_e_table_model = e_table_memory_store_new (columns); - - vbox = e_cell_vbox_new (); - - pixbuf = e_cell_pixbuf_new(); - g_object_set (G_OBJECT (pixbuf), - "focused_column", 2, - "selected_column", 3, - "unselected_column", 4, - NULL); - e_cell_vbox_append (E_CELL_VBOX (vbox), pixbuf, 1); - g_object_unref (pixbuf); - - text = e_cell_text_new (NULL, GTK_JUSTIFY_CENTER); - e_cell_vbox_append (E_CELL_VBOX (vbox), text, 0); - g_object_unref (text); - - extras = e_table_extras_new (); - e_table_extras_add_cell (extras, "vbox", vbox); - - list_e_table = e_table_scrolled_new (list_e_table_model, extras, list_e_table_spec, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (list_e_table), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - g_signal_connect (e_table_scrolled_get_table (E_TABLE_SCROLLED (list_e_table)), - "cursor_change", G_CALLBACK (table_cursor_change_callback), multi_config_dialog); - - g_signal_connect (e_table_scrolled_get_table (E_TABLE_SCROLLED (list_e_table))->table_canvas, - "realize", G_CALLBACK (canvas_realize), multi_config_dialog); - - g_object_unref (extras); - - gtk_box_pack_start (GTK_BOX (hbox), list_e_table, FALSE, TRUE, 0); - - notebook = gtk_notebook_new (); - gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE); - gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE); - gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0); - - gtk_widget_show (hbox); - gtk_widget_show (notebook); - gtk_widget_show (list_e_table); - - gtk_dialog_add_buttons (GTK_DIALOG (multi_config_dialog), - GTK_STOCK_HELP, GTK_RESPONSE_HELP, - GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, - NULL); - gtk_dialog_set_default_response (GTK_DIALOG (multi_config_dialog), GTK_RESPONSE_OK); - - gtk_window_set_resizable (GTK_WINDOW (multi_config_dialog), TRUE); - - priv = g_new (EMultiConfigDialogPrivate, 1); - priv->pages = NULL; - priv->list_e_table = list_e_table; - priv->list_e_table_model = list_e_table_model; - priv->notebook = notebook; - priv->set_page_timeout_id = 0; - priv->set_page_timeout_page = 0; - - multi_config_dialog->priv = priv; -} - - -GtkWidget * -e_multi_config_dialog_new (void) -{ - return g_object_new (e_multi_config_dialog_get_type (), NULL); -} - -void -e_multi_config_dialog_add_page (EMultiConfigDialog *dialog, - const gchar *title, - const gchar *description, - GdkPixbuf *icon, - EConfigPage *page_widget) -{ - EMultiConfigDialogPrivate *priv; - AtkObject *a11y; - AtkObject *a11yPage; - gint page_no; - - g_return_if_fail (E_IS_MULTI_CONFIG_DIALOG (dialog)); - g_return_if_fail (title != NULL); - g_return_if_fail (description != NULL); - g_return_if_fail (E_IS_CONFIG_PAGE (page_widget)); - - priv = dialog->priv; - - priv->pages = g_slist_append (priv->pages, page_widget); - - e_table_memory_store_insert (E_TABLE_MEMORY_STORE (priv->list_e_table_model), -1, NULL, title, icon, NULL, NULL, NULL); - - page_no = gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), - create_page_container (description, GTK_WIDGET (page_widget)), - NULL); - - a11y = gtk_widget_get_accessible (GTK_WIDGET(priv->notebook)); - a11yPage = atk_object_ref_accessible_child (a11y, page_no); - if (a11yPage != NULL) { - if (atk_object_get_role (a11yPage) == ATK_ROLE_PAGE_TAB) - atk_object_set_name (a11yPage, title); - g_object_unref (a11yPage); - } - if (priv->pages->next == NULL) { - ETable *table; - - /* FIXME: This is supposed to select the first entry by default - but it doesn't seem to work at all. */ - table = e_table_scrolled_get_table (E_TABLE_SCROLLED (priv->list_e_table)); - e_table_set_cursor_row (table, 0); - e_selection_model_select_all (e_table_get_selection_model (table)); - } -} - -void -e_multi_config_dialog_show_page (EMultiConfigDialog *dialog, gint page) -{ - EMultiConfigDialogPrivate *priv; - - g_return_if_fail (dialog != NULL); - g_return_if_fail (E_IS_MULTI_CONFIG_DIALOG (dialog)); - - priv = dialog->priv; - - e_table_set_cursor_row (e_table_scrolled_get_table (E_TABLE_SCROLLED (priv->list_e_table)), page); - gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), page); -} - diff --git a/widgets/misc/e-multi-config-dialog.h b/widgets/misc/e-multi-config-dialog.h deleted file mode 100644 index 1bc310b888..0000000000 --- a/widgets/misc/e-multi-config-dialog.h +++ /dev/null @@ -1,71 +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 _E_MULTI_CONFIG_DIALOG_H_ -#define _E_MULTI_CONFIG_DIALOG_H_ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "e-config-page.h" - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define E_TYPE_MULTI_CONFIG_DIALOG (e_multi_config_dialog_get_type ()) -#define E_MULTI_CONFIG_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_MULTI_CONFIG_DIALOG, EMultiConfigDialog)) -#define E_MULTI_CONFIG_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_MULTI_CONFIG_DIALOG, EMultiConfigDialogClass)) -#define E_IS_MULTI_CONFIG_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_MULTI_CONFIG_DIALOG)) -#define E_IS_MULTI_CONFIG_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_MULTI_CONFIG_DIALOG)) - - -typedef struct _EMultiConfigDialog EMultiConfigDialog; -typedef struct _EMultiConfigDialogPrivate EMultiConfigDialogPrivate; -typedef struct _EMultiConfigDialogClass EMultiConfigDialogClass; - -struct _EMultiConfigDialog { - GtkDialog parent; - - EMultiConfigDialogPrivate *priv; -}; - -struct _EMultiConfigDialogClass { - GtkDialogClass parent_class; -}; - - -GType e_multi_config_dialog_get_type (void); -GtkWidget *e_multi_config_dialog_new (void); - -void e_multi_config_dialog_add_page (EMultiConfigDialog *dialog, - const gchar *title, - const gchar *description, - GdkPixbuf *icon, - EConfigPage *page); -void e_multi_config_dialog_show_page (EMultiConfigDialog *dialog, - gint page); - -G_END_DECLS - -#endif /* _E_MULTI_CONFIG_DIALOG_H_ */ diff --git a/widgets/misc/e-online-button.c b/widgets/misc/e-online-button.c index 114d76ac32..c14114b9c3 100644 --- a/widgets/misc/e-online-button.c +++ b/widgets/misc/e-online-button.c @@ -23,6 +23,12 @@ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), E_TYPE_ONLINE_BUTTON, EOnlineButtonPrivate)) +#define ONLINE_TOOLTIP \ + "Evolution is currently online. Click this button to work offline." + +#define OFFLINE_TOOLTIP \ + "Evolution is currently offline. Click this button to work online." + struct _EOnlineButtonPrivate { GtkWidget *image; gboolean online; @@ -175,6 +181,7 @@ e_online_button_set_online (EOnlineButton *button, GtkIconTheme *icon_theme; const gchar *filename; const gchar *icon_name; + const gchar *tooltip; g_return_if_fail (E_IS_ONLINE_BUTTON (button)); @@ -191,5 +198,8 @@ e_online_button_set_online (EOnlineButton *button, gtk_image_set_from_file (image, filename); gtk_icon_info_free (icon_info); + tooltip = _(online ? ONLINE_TOOLTIP : OFFLINE_TOOLTIP); + gtk_widget_set_tooltip_text (GTK_WIDGET (button), tooltip); + g_object_notify (G_OBJECT (button), "online"); } diff --git a/widgets/misc/e-popup-action.c b/widgets/misc/e-popup-action.c new file mode 100644 index 0000000000..e856a1fc24 --- /dev/null +++ b/widgets/misc/e-popup-action.c @@ -0,0 +1,285 @@ +/* + * e-popup-action.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-popup-action.h" + +#include <glib/gi18n.h> +#include "e-util/e-binding.h" + +#define E_POPUP_ACTION_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_POPUP_ACTION, EPopupActionPrivate)) + +enum { + PROP_0, + PROP_SOURCE +}; + +struct _EPopupActionPrivate { + GtkAction *source; +}; + +static gpointer parent_class; + +static void +popup_action_set_source (EPopupAction *popup_action, + GtkAction *source) +{ + g_return_if_fail (popup_action->priv->source == NULL); + g_return_if_fail (GTK_IS_ACTION (source)); + + popup_action->priv->source = g_object_ref (source); +} + +static void +popup_action_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SOURCE: + popup_action_set_source ( + E_POPUP_ACTION (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +popup_action_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SOURCE: + g_value_set_object ( + value, e_popup_action_get_source ( + E_POPUP_ACTION (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +popup_action_dispose (GObject *object) +{ + EPopupActionPrivate *priv; + + priv = E_POPUP_ACTION_GET_PRIVATE (object); + + if (priv->source != NULL) { + g_object_unref (priv->source); + priv->source = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +popup_action_constructed (GObject *object) +{ + EPopupActionPrivate *priv; + GObject *source; + gchar *icon_name; + gchar *label; + gchar *stock_id; + gchar *tooltip; + + priv = E_POPUP_ACTION_GET_PRIVATE (object); + + source = G_OBJECT (priv->source); + + g_object_get ( + object, "icon-name", &icon_name, "label", &label, + "stock-id", &stock_id, "tooltip", &tooltip, NULL); + + if (label == NULL) + e_binding_new (source, "label", object, "label"); + + if (tooltip == NULL) + e_binding_new (source, "tooltip", object, "tooltip"); + + if (icon_name == NULL && stock_id == NULL) { + g_free (icon_name); + g_free (stock_id); + + g_object_get ( + source, "icon-name", &icon_name, + "stock-id", &stock_id, NULL); + + if (icon_name == NULL) { + e_binding_new ( + source, "icon-name", object, "icon-name"); + e_binding_new ( + source, "stock-id", object, "stock-id"); + } else { + e_binding_new ( + source, "stock-id", object, "stock-id"); + e_binding_new ( + source, "icon-name", object, "icon-name"); + } + } + + e_binding_new (source, "sensitive", object, "visible"); + + g_free (icon_name); + g_free (label); + g_free (stock_id); + g_free (tooltip); +} + +static void +popup_action_class_init (EPopupActionClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EPopupActionPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = popup_action_set_property; + object_class->get_property = popup_action_get_property; + object_class->dispose = popup_action_dispose; + + g_object_class_install_property ( + object_class, + PROP_SOURCE, + g_param_spec_object ( + "source", + _("Source Action"), + _("The source action to proxy"), + GTK_TYPE_ACTION, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); +} + +static void +popup_action_init (EPopupAction *popup_action) +{ + popup_action->priv = E_POPUP_ACTION_GET_PRIVATE (popup_action); +} + +GType +e_popup_action_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EPopupActionClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) popup_action_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EPopupAction), + 0, /* n_preallocs */ + (GInstanceInitFunc) popup_action_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_ACTION, "EPopupAction", &type_info, 0); + } + + return type; +} + +EPopupAction * +e_popup_action_new (const gchar *name, + const gchar *label, + GtkAction *source) +{ + EPopupAction *popup_action; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (GTK_IS_ACTION (source), NULL); + + popup_action = g_object_new ( + E_TYPE_POPUP_ACTION, "name", name, + "label", label, "source", source, NULL); + + /* XXX This is a hack to work around the fact that GtkAction's + * "label" and "tooltip" properties are not constructor + * properties, even though they're supplied upfront. + * + * See: http://bugzilla.gnome.org/show_bug.cgi?id=568334 */ + popup_action_constructed (G_OBJECT (popup_action)); + + return popup_action; +} + +GtkAction * +e_popup_action_get_source (EPopupAction *popup_action) +{ + g_return_val_if_fail (E_IS_POPUP_ACTION (popup_action), NULL); + + return popup_action->priv->source; +} + +void +e_action_group_add_popup_actions (GtkActionGroup *action_group, + const EPopupActionEntry *entries, + guint n_entries) +{ + guint ii; + + g_return_if_fail (GTK_IS_ACTION_GROUP (action_group)); + + for (ii = 0; ii < n_entries; ii++) { + EPopupAction *popup_action; + GtkAction *source; + const gchar *label; + + label = gtk_action_group_translate_string ( + action_group, entries[ii].label); + + source = gtk_action_group_get_action ( + action_group, entries[ii].source); + + if (source == NULL) { + g_warning ( + "Source action '%s' not found in " + "action group '%s'", entries[ii].source, + gtk_action_group_get_name (action_group)); + continue; + } + + popup_action = e_popup_action_new ( + entries[ii].name, label, source); + + g_signal_connect_swapped ( + popup_action, "activate", + G_CALLBACK (gtk_action_activate), + popup_action->priv->source); + + gtk_action_group_add_action ( + action_group, GTK_ACTION (popup_action)); + + g_object_unref (popup_action); + } +} diff --git a/widgets/misc/e-popup-action.h b/widgets/misc/e-popup-action.h new file mode 100644 index 0000000000..d19971f303 --- /dev/null +++ b/widgets/misc/e-popup-action.h @@ -0,0 +1,95 @@ +/* + * e-popup-action.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) + * + */ + +/* A popup action is an action that lives in a popup menu. It proxies an + * equivalent action in the main menu, with two differences: + * + * 1) If the main menu action is insensitive, the popup action is invisible. + * 2) The popup action may have a different label than the main menu action. + * + * To use: + * + * Create an array of EPopupActionEntry structs. Add the main menu actions + * that serve as "sources" for the popup actions to an action group first. + * Then pass the same action group and the EPopupActionEntry array to + * e_action_group_add_popup_actions() to add popup actions. + */ + +#ifndef E_POPUP_ACTION_H +#define E_POPUP_ACTION_H + +#include <gtk/gtk.h> + +/* Standard GObject macros */ +#define E_TYPE_POPUP_ACTION \ + (e_popup_action_get_type ()) +#define E_POPUP_ACTION(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_POPUP_ACTION, EPopupAction)) +#define E_POPUP_ACTION_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_POPUP_ACTION, EPopupActionClass)) +#define E_IS_POPUP_ACTION(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_POPUP_ACTION)) +#define E_IS_POPUP_ACTION_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_POPUP_ACTION)) +#define E_POPUP_ACTION_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_POPUP_ACTION, EPopupActionClass)) + +G_BEGIN_DECLS + +typedef struct _EPopupAction EPopupAction; +typedef struct _EPopupActionClass EPopupActionClass; +typedef struct _EPopupActionPrivate EPopupActionPrivate; +typedef struct _EPopupActionEntry EPopupActionEntry; + +struct _EPopupAction { + GtkAction parent; + EPopupActionPrivate *priv; +}; + +struct _EPopupActionClass { + GtkActionClass parent_class; +}; + +struct _EPopupActionEntry { + const gchar *name; + const gchar *label; /* optional: overrides the source action */ + const gchar *source; /* name of the source action */ +}; + +GType e_popup_action_get_type (void); +EPopupAction * e_popup_action_new (const gchar *name, + const gchar *label, + GtkAction *source); +GtkAction * e_popup_action_get_source (EPopupAction *popup_action); + +void e_action_group_add_popup_actions + (GtkActionGroup *action_group, + const EPopupActionEntry *entries, + guint n_entries); + +G_END_DECLS + +#endif /* E_POPUP_ACTION_H */ diff --git a/widgets/misc/e-preferences-window.c b/widgets/misc/e-preferences-window.c new file mode 100644 index 0000000000..af2d07d871 --- /dev/null +++ b/widgets/misc/e-preferences-window.c @@ -0,0 +1,393 @@ +/* + * e-preferences-window.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-preferences-window.h" + +#include <glib/gi18n.h> +#include <e-util/e-util.h> + +#define SWITCH_PAGE_INTERVAL 250 + +#define E_PREFERENCES_WINDOW_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_PREFERENCES_WINDOW, EPreferencesWindowPrivate)) + +struct _EPreferencesWindowPrivate { + GtkWidget *icon_view; + GtkWidget *notebook; + GHashTable *index; +}; + +enum { + COLUMN_TEXT, /* G_TYPE_STRING */ + COLUMN_PIXBUF, /* GDK_TYPE_PIXBUF */ + COLUMN_PAGE, /* G_TYPE_INT */ + COLUMN_SORT /* G_TYPE_INT */ +}; + +static gpointer parent_class; + +static GdkPixbuf * +preferences_window_load_pixbuf (const gchar *icon_name) +{ + GtkIconTheme *icon_theme; + GtkIconInfo *icon_info; + GdkPixbuf *pixbuf; + const gchar *filename; + gint size; + GError *error = NULL; + + icon_theme = gtk_icon_theme_get_default (); + + if (!gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &size, 0)) + return NULL; + + icon_info = gtk_icon_theme_lookup_icon ( + icon_theme, icon_name, size, 0); + + if (icon_info == NULL) + return NULL; + + filename = gtk_icon_info_get_filename (icon_info); + + pixbuf = gdk_pixbuf_new_from_file (filename, &error); + + gtk_icon_info_free (icon_info); + + if (error != NULL) { + g_warning ("%s", error->message); + g_error_free (error); + } + + return pixbuf; +} + +static void +preferences_window_help_clicked_cb (GtkWindow *window) +{ + e_display_help (window, "config-prefs"); +} + +static void +preferences_window_selection_changed_cb (EPreferencesWindow *window) +{ + GtkIconView *icon_view; + GtkNotebook *notebook; + GtkTreeModel *model; + GtkTreeIter iter; + GList *list; + gint page; + + icon_view = GTK_ICON_VIEW (window->priv->icon_view); + list = gtk_icon_view_get_selected_items (icon_view); + if (list == NULL) + return; + + model = gtk_icon_view_get_model (icon_view); + gtk_tree_model_get_iter (model, &iter, list->data); + gtk_tree_model_get (model, &iter, COLUMN_PAGE, &page, -1); + + notebook = GTK_NOTEBOOK (window->priv->notebook); + gtk_notebook_set_current_page (notebook, page); + + g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL); + g_list_free (list); + + gtk_widget_grab_focus (GTK_WIDGET (icon_view)); +} + +static void +preferences_window_dispose (GObject *object) +{ + EPreferencesWindowPrivate *priv; + + priv = E_PREFERENCES_WINDOW_GET_PRIVATE (object); + + if (priv->icon_view != NULL) { + g_object_unref (priv->icon_view); + priv->icon_view = NULL; + } + + if (priv->notebook != NULL) { + g_object_unref (priv->notebook); + priv->notebook = NULL; + } + + g_hash_table_remove_all (priv->index); + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +preferences_window_finalize (GObject *object) +{ + EPreferencesWindowPrivate *priv; + + priv = E_PREFERENCES_WINDOW_GET_PRIVATE (object); + + g_hash_table_destroy (priv->index); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +preferences_window_show (GtkWidget *widget) +{ + EPreferencesWindowPrivate *priv; + GtkIconView *icon_view; + GtkTreePath *path; + + priv = E_PREFERENCES_WINDOW_GET_PRIVATE (widget); + + icon_view = GTK_ICON_VIEW (priv->icon_view); + + path = gtk_tree_path_new_first (); + gtk_icon_view_select_path (icon_view, path); + gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.0, 0.0); + gtk_tree_path_free (path); + + gtk_widget_grab_focus (priv->icon_view); + + /* Chain up to parent's show() method. */ + GTK_WIDGET_CLASS (parent_class)->show (widget); +} + +static void +preferences_window_class_init (EPreferencesWindowClass *class) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EPreferencesWindowPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->dispose = preferences_window_dispose; + object_class->finalize = preferences_window_finalize; + + widget_class = GTK_WIDGET_CLASS (class); + widget_class->show = preferences_window_show; +} + +static void +preferences_window_init (EPreferencesWindow *window) +{ + GtkListStore *store; + GtkWidget *container; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *widget; + GHashTable *index; + const gchar *title; + + index = g_hash_table_new_full ( + g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) gtk_tree_row_reference_free); + + window->priv = E_PREFERENCES_WINDOW_GET_PRIVATE (window); + window->priv->index = index; + + store = gtk_list_store_new ( + 4, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_INT, G_TYPE_INT); + gtk_tree_sortable_set_sort_column_id ( + GTK_TREE_SORTABLE (store), COLUMN_SORT, GTK_SORT_ASCENDING); + + title = _("Evolution Preferences"); + gtk_window_set_title (GTK_WINDOW (window), title); + gtk_window_set_resizable (GTK_WINDOW (window), TRUE); + gtk_container_set_border_width (GTK_CONTAINER (window), 12); + + g_signal_connect ( + window, "delete-event", + G_CALLBACK (gtk_widget_hide_on_delete), NULL); + + widget = gtk_vbox_new (FALSE, 12); + gtk_container_add (GTK_CONTAINER (window), widget); + gtk_widget_show (widget); + + vbox = widget; + + widget = gtk_hbox_new (FALSE, 12); + gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0); + gtk_widget_show (widget); + + hbox = widget; + + widget = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy ( + GTK_SCROLLED_WINDOW (widget), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type ( + GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, TRUE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_icon_view_new_with_model (GTK_TREE_MODEL (store)); + gtk_icon_view_set_columns (GTK_ICON_VIEW (widget), 1); + gtk_icon_view_set_text_column (GTK_ICON_VIEW (widget), COLUMN_TEXT); + gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (widget), COLUMN_PIXBUF); + g_signal_connect_swapped ( + widget, "selection-changed", + G_CALLBACK (preferences_window_selection_changed_cb), window); + gtk_container_add (GTK_CONTAINER (container), widget); + window->priv->icon_view = g_object_ref (widget); + gtk_widget_show (widget); + g_object_unref (store); + + widget = gtk_notebook_new (); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE); + gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE); + gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0); + window->priv->notebook = g_object_ref (widget); + gtk_widget_show (widget); + + widget = gtk_hbutton_box_new (); + gtk_button_box_set_layout ( + GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_END); + gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_button_new_from_stock (GTK_STOCK_HELP); + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (preferences_window_help_clicked_cb), window); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_button_box_set_child_secondary ( + GTK_BUTTON_BOX (container), widget, TRUE); + gtk_widget_show (widget); + + widget = gtk_button_new_from_stock (GTK_STOCK_CLOSE); + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (gtk_widget_hide), window); + GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_grab_default (widget); + gtk_widget_show (widget); +} + +GType +e_preferences_window_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + const GTypeInfo type_info = { + sizeof (EPreferencesWindowClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) preferences_window_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EPreferencesWindow), + 0, /* n_preallocs */ + (GInstanceInitFunc) preferences_window_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_WINDOW, "EPreferencesWindow", &type_info, 0); + } + + return type; +} + +GtkWidget * +e_preferences_window_new (void) +{ + return g_object_new (E_TYPE_PREFERENCES_WINDOW, NULL); +} + +void +e_preferences_window_add_page (EPreferencesWindow *window, + const gchar *page_name, + const gchar *icon_name, + const gchar *caption, + GtkWidget *widget, + gint sort_order) +{ + GtkTreeRowReference *reference; + GtkIconView *icon_view; + GtkNotebook *notebook; + GtkTreeModel *model; + GtkTreePath *path; + GHashTable *index; + GdkPixbuf *pixbuf; + GtkTreeIter iter; + gint page; + + g_return_if_fail (E_IS_PREFERENCES_WINDOW (window)); + g_return_if_fail (page_name != NULL); + g_return_if_fail (icon_name != NULL); + g_return_if_fail (caption != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + icon_view = GTK_ICON_VIEW (window->priv->icon_view); + notebook = GTK_NOTEBOOK (window->priv->notebook); + + page = gtk_notebook_get_n_pages (notebook); + model = gtk_icon_view_get_model (icon_view); + pixbuf = preferences_window_load_pixbuf (icon_name); + + gtk_list_store_append (GTK_LIST_STORE (model), &iter); + + gtk_list_store_set ( + GTK_LIST_STORE (model), &iter, + COLUMN_TEXT, caption, COLUMN_PIXBUF, pixbuf, + COLUMN_PAGE, page, COLUMN_SORT, sort_order, -1); + + index = window->priv->index; + path = gtk_tree_model_get_path (model, &iter); + reference = gtk_tree_row_reference_new (model, path); + g_hash_table_insert (index, g_strdup (page_name), reference); + gtk_tree_path_free (path); + + gtk_widget_show (widget); + gtk_notebook_append_page (notebook, widget, NULL); +} + +void +e_preferences_window_show_page (EPreferencesWindow *window, + const gchar *page_name) +{ + GtkTreeRowReference *reference; + GtkIconView *icon_view; + GtkTreePath *path; + + g_return_if_fail (E_IS_PREFERENCES_WINDOW (window)); + g_return_if_fail (page_name != NULL); + + icon_view = GTK_ICON_VIEW (window->priv->icon_view); + reference = g_hash_table_lookup (window->priv->index, page_name); + g_return_if_fail (reference != NULL); + + path = gtk_tree_row_reference_get_path (reference); + gtk_icon_view_select_path (icon_view, path); + gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.0, 0.0); + gtk_tree_path_free (path); +} diff --git a/widgets/misc/e-preferences-window.h b/widgets/misc/e-preferences-window.h new file mode 100644 index 0000000000..4944a89e58 --- /dev/null +++ b/widgets/misc/e-preferences-window.h @@ -0,0 +1,74 @@ +/* + * e-preferences-window.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_PREFERENCES_WINDOW_H +#define E_PREFERENCES_WINDOW_H + +#include <gtk/gtk.h> + +/* Standard GObject macros */ +#define E_TYPE_PREFERENCES_WINDOW \ + (e_preferences_window_get_type ()) +#define E_PREFERENCES_WINDOW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_PREFERENCES_WINDOW, EPreferencesWindow)) +#define E_PREFERENCES_WINDOW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_PREFERENCES_WINDOW, EPreferencesWindowClass)) +#define E_IS_PREFERENCES_WINDOW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_PREFERENCES_WINDOW)) +#define E_IS_PREFERENCES_WINDOW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((obj), E_TYPE_PREFERENCES_WINDOW)) +#define E_PREFERENCES_WINDOW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_TYPE \ + ((obj), E_TYPE_PREFERENCES_WINDOW, EPreferencesWindowClass)) + +G_BEGIN_DECLS + +typedef struct _EPreferencesWindow EPreferencesWindow; +typedef struct _EPreferencesWindowClass EPreferencesWindowClass; +typedef struct _EPreferencesWindowPrivate EPreferencesWindowPrivate; + +struct _EPreferencesWindow { + GtkWindow parent; + EPreferencesWindowPrivate *priv; +}; + +struct _EPreferencesWindowClass { + GtkWindowClass parent_class; +}; + +GType e_preferences_window_get_type (void); +GtkWidget * e_preferences_window_new (void); +void e_preferences_window_add_page (EPreferencesWindow *window, + const gchar *page_name, + const gchar *icon_name, + const gchar *caption, + GtkWidget *widget, + gint sort_order); +void e_preferences_window_show_page (EPreferencesWindow *window, + const gchar *page_name); + +G_END_DECLS + +#endif /* E_PREFERENCES_WINDOW_H */ diff --git a/widgets/misc/e-search-bar.c b/widgets/misc/e-search-bar.c deleted file mode 100644 index 0a778531b7..0000000000 --- a/widgets/misc/e-search-bar.c +++ /dev/null @@ -1,1683 +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> - * Ettore Perazzoli <ettore@ximian.com> - * Jon Trowbridge <trow@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <gdk/gdkkeysyms.h> - -#include <misc/e-unicode.h> -#include <misc/e-gui-utils.h> - -#include <glib/gi18n.h> - -#include <bonobo/bonobo-ui-util.h> - -#include <stdlib.h> -#include <string.h> - -#include "e-icon-entry.h" -#include "e-search-bar.h" -#include "e-util/e-util.h" - - -enum { - QUERY_CHANGED, - MENU_ACTIVATED, - SEARCH_ACTIVATED, - SEARCH_CLEARED, - LAST_SIGNAL -}; - -static gint esb_signals [LAST_SIGNAL] = { 0, }; - -static GtkHBoxClass *parent_class = NULL; - -/* The arguments we take */ -enum { - PROP_0, - PROP_ITEM_ID, - PROP_SUBITEM_ID, - PROP_TEXT -}; - - -/* Forward decls. */ - -static gint find_id (GtkWidget *menu, gint idin, const gchar *type, GtkWidget **widget); - -static void emit_search_activated (ESearchBar *esb); -static void emit_query_changed (ESearchBar *esb); - - -/* Utility functions. */ - -static void -esb_paint_label (GtkWidget *label, gboolean active) -{ - static gchar *sens = NULL; - static gchar *insens = NULL; - gchar *text; - - if (!label) - return; - - if (!sens) { - GtkStyle *default_style = gtk_widget_get_default_style (); - sens = gdk_color_to_string (&default_style->text[GTK_STATE_SELECTED]); - insens = gdk_color_to_string (&default_style->text[GTK_STATE_NORMAL]); - } - text = g_strdup_printf("<span foreground=\"%s\">%s</span>", active ? sens : insens, _("Search")); - gtk_label_set_markup ((GtkLabel *)label, text); - g_free(text); -} - -static void -set_find_now_sensitive (ESearchBar *search_bar, - gboolean sensitive) -{ - if (search_bar->ui_component != NULL) - bonobo_ui_component_set_prop (search_bar->ui_component, - "/commands/ESearchBar:FindNow", - "sensitive", sensitive ? "1" : "0", NULL); -} - -static void -update_clear_menuitem_sensitive (ESearchBar *search_bar) -{ - if (search_bar->ui_component != NULL) { - gboolean sensitive = GTK_WIDGET_SENSITIVE (search_bar->clear_button) || search_bar->viewitem_id != 0; - - bonobo_ui_component_set_prop (search_bar->ui_component, - "/commands/ESearchBar:Clear", - "sensitive", sensitive ? "1" : "0", NULL); - } -} - -static void -clear_button_state_changed (GtkWidget *clear_button, GtkStateType state, ESearchBar *search_bar) -{ - g_return_if_fail (clear_button != NULL && search_bar != NULL); - - if (!search_bar->lite) - update_clear_menuitem_sensitive (search_bar); -} - -static gchar * -verb_name_from_id (gint id) -{ - return g_strdup_printf ("ESearchBar:Activate:%d", id); -} - -/* This implements the "clear" action, i.e. clears the text and then emits - * ::search_activated. */ - -static void -clear_search (ESearchBar *esb) -{ - e_search_bar_set_text (esb, ""); - esb->block_search = TRUE; - if (esb->item_id < 0) - e_search_bar_set_item_id (esb, esb->last_search_option); - e_search_bar_set_viewitem_id (esb, 0); - esb->block_search = FALSE; - emit_search_activated (esb); -} - -static void -free_menu_items (ESearchBar *esb) -{ - GSList *p; - - if (esb->menu_items == NULL) - return; - - for (p = esb->menu_items; p != NULL; p = p->next) { - ESearchBarItem *item; - - item = (ESearchBarItem *) p->data; - - /* (No submitems for the menu_items, so no need to free that - member.) */ - - g_free (item->text); - g_free (item); - } - - g_slist_free (esb->menu_items); - esb->menu_items = NULL; -} - - -/* Signals. */ - -static void -emit_query_changed (ESearchBar *esb) -{ - g_signal_emit (esb, esb_signals [QUERY_CHANGED], 0); - if (!esb->lite) - update_clear_menuitem_sensitive (esb); -} - -static void -emit_search_activated(ESearchBar *esb) -{ - if (esb->pending_activate) { - g_source_remove (esb->pending_activate); - esb->pending_activate = 0; - } - - g_signal_emit (esb, esb_signals [SEARCH_ACTIVATED], 0); - - if (!esb->lite) { - set_find_now_sensitive (esb, FALSE); - update_clear_menuitem_sensitive (esb); - } -} - -static void -emit_menu_activated (ESearchBar *esb, gint item) -{ - g_signal_emit (esb, - esb_signals [MENU_ACTIVATED], 0, - item); -} - - -/* Callbacks -- Standard verbs. */ - -static void -search_now_verb_cb (BonoboUIComponent *ui_component, - gpointer data, - const gchar *verb_name) -{ - ESearchBar *esb; - GtkStyle *style = gtk_widget_get_default_style (); - gchar *text; - - esb = E_SEARCH_BAR (data); - text = e_search_bar_get_text (esb); - - if (text && *text) { - gtk_widget_modify_base (esb->entry, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - gtk_widget_modify_text (esb->entry, GTK_STATE_NORMAL, &(style->text[GTK_STATE_SELECTED])); - gtk_widget_modify_base (esb->icon_entry, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - gtk_widget_modify_base (esb->viewoption, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - } else { - gtk_widget_modify_base (esb->entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_text (esb->entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_base (esb->icon_entry, GTK_STATE_NORMAL, NULL); - gtk_widget_set_sensitive (esb->clear_button, FALSE); - } - - g_free (text); - emit_search_activated (esb); -} - -static void -clear_verb_cb (BonoboUIComponent *ui_component, - gpointer data, - const gchar *verb_name) -{ - ESearchBar *esb; - esb = E_SEARCH_BAR (data); - - gtk_widget_modify_base (esb->entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_text (esb->entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_base (esb->icon_entry, GTK_STATE_NORMAL, NULL); - gtk_widget_set_sensitive (esb->clear_button, FALSE); - - clear_search (esb); - gtk_entry_set_text (GTK_ENTRY (esb->entry), ""); - gtk_widget_grab_focus (esb->entry); -} - -static void -setup_standard_verbs (ESearchBar *search_bar) -{ - bonobo_ui_component_add_verb (search_bar->ui_component, "ESearchBar:Clear", - clear_verb_cb, search_bar); - bonobo_ui_component_add_verb (search_bar->ui_component, "ESearchBar:FindNow", - search_now_verb_cb, search_bar); - - bonobo_ui_component_set (search_bar->ui_component, "/", - ("<commands>" - " <cmd name=\"ESearchBar:Clear\"/>" - " <cmd name=\"ESearchBar:FindNow\"/>" - "</commands>"), - NULL); - - /* Make sure the entries are created with the correct sensitivity. */ - set_find_now_sensitive (search_bar, FALSE); - update_clear_menuitem_sensitive (search_bar); -} - -/* Callbacks -- The verbs for all the definable items. */ - -static void -search_verb_cb (BonoboUIComponent *ui_component, - gpointer data, - const gchar *verb_name) -{ - ESearchBar *esb; - const gchar *p; - gint id; - - esb = E_SEARCH_BAR (data); - - p = strrchr (verb_name, ':'); - g_return_if_fail (p != NULL); - - id = atoi (p + 1); - - emit_menu_activated (esb, id); -} - -/* Get the selected menu item's label */ -static const gchar * -get_selected_item_label (GtkWidget *menu) -{ - GtkWidget *label, *item; - const gchar *text = NULL; - - item = gtk_menu_get_active ((GtkMenu *)menu); - label = gtk_bin_get_child ((GtkBin *)item); - - if (GTK_IS_LABEL (label)) - text = gtk_label_get_text ((GtkLabel *)label); - - return text; -} - -static gboolean -entry_focus_in_cb (GtkWidget *widget, - GdkEventFocus *event, - ESearchBar *esb) -{ - GtkStyle *entry_style, *default_style; - - entry_style = gtk_widget_get_style (esb->entry); - default_style = gtk_widget_get_default_style (); - - if (gdk_color_equal (&(entry_style->text[GTK_STATE_NORMAL]), &(default_style->text[GTK_STATE_INSENSITIVE]))) { - gtk_entry_set_text (GTK_ENTRY (esb->entry), ""); - gtk_widget_modify_text (esb->entry, GTK_STATE_NORMAL, NULL); - } - - return FALSE; -} - -static gboolean -paint_search_text (GtkWidget *widget, ESearchBar *esb) -{ - GtkStyle *style = gtk_widget_get_default_style (); - const gchar *text = NULL; - GtkWidget *menu_widget = esb->option_menu; - - text = gtk_entry_get_text (GTK_ENTRY (widget)); - if (text && *text) - return FALSE; - - if (!GTK_WIDGET_SENSITIVE (esb->option_button)) { - menu_widget = esb->scopeoption_menu; - text = g_object_get_data (G_OBJECT(gtk_menu_get_active ( GTK_MENU (esb->scopeoption_menu))),"string"); - } else if (!GTK_IS_RADIO_MENU_ITEM (gtk_menu_get_active ( GTK_MENU (esb->option_menu)))) - return FALSE; - else /* no query in search entry .. so set the current option */ - text = get_selected_item_label (menu_widget); - - if (text && *text) { - gchar *t; - - if (!GTK_WIDGET_HAS_FOCUS(esb->entry)) { - gtk_entry_set_text (GTK_ENTRY (esb->entry), text); - gtk_widget_modify_text (esb->entry, GTK_STATE_NORMAL, &(style->text[GTK_STATE_INSENSITIVE])); - } - - t = g_strdup_printf ("%s: %s\n%s", _("Search"), text, _("Click here to change the search type")); - gtk_widget_set_tooltip_text (esb->option_button, t); - g_free (t); - - gtk_widget_set_sensitive (esb->clear_button, FALSE); - } - - return FALSE; -} - -void -e_search_bar_paint (ESearchBar *search_bar) -{ - paint_search_text (search_bar->entry, search_bar); -} - -static gboolean -entry_focus_out_cb (GtkWidget *widget, - GdkEventFocus *event, - ESearchBar *esb) -{ - return paint_search_text (widget, esb); -} - -static void -entry_activated_cb (GtkWidget *widget, - ESearchBar *esb) -{ - const gchar *text = gtk_entry_get_text (GTK_ENTRY (esb->entry)); - GtkStyle *style = gtk_widget_get_default_style (); - - if (text && *text) { - gtk_widget_modify_base (esb->entry, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - gtk_widget_modify_text (esb->entry, GTK_STATE_NORMAL, &(style->text[GTK_STATE_SELECTED])); - gtk_widget_modify_base (esb->icon_entry, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - esb_paint_label (esb->label, TRUE); - if (!esb->lite) - gtk_widget_modify_base (esb->viewoption, GTK_STATE_NORMAL, &(style->base[GTK_STATE_SELECTED])); - } else { - gtk_widget_modify_base (esb->entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_text (esb->entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_base (esb->icon_entry, GTK_STATE_NORMAL, NULL); - esb_paint_label (esb->label, FALSE); - if (!esb->lite) - gtk_widget_set_sensitive (esb->clear_button, FALSE); - } - - emit_search_activated (esb); -} - -static void -search_entry_press_cb (GtkWidget *w, GdkEventButton *event, ESearchBar *esb) -{ - if (event->button == 1) - entry_activated_cb (w, esb); -} - -static void -entry_changed_cb (GtkWidget *widget, - ESearchBar *esb) -{ - const gchar *text = gtk_entry_get_text (GTK_ENTRY (esb->entry)); - GtkStyle *entry_style, *default_style; - - entry_style = gtk_widget_get_style (esb->entry); - default_style = gtk_widget_get_default_style (); - - if (text && *text) { - if (gdk_color_equal (&(entry_style->text[GTK_STATE_NORMAL]), &(default_style->text[GTK_STATE_INSENSITIVE]))) - gtk_widget_set_sensitive (esb->clear_button, FALSE); - else - gtk_widget_set_sensitive (esb->clear_button, TRUE); - } else { - /* selected color means some search text is active */ - gtk_widget_set_sensitive (esb->clear_button, gdk_color_equal (&(entry_style->base[GTK_STATE_NORMAL]), &(default_style->base[GTK_STATE_SELECTED]))); - } -} - -static void -viewitem_activated_cb(GtkWidget *widget, ESearchBar *esb) -{ - gint viewid; - GtkStyle *entry_style, *default_style; - - widget = gtk_menu_get_active (GTK_MENU (esb->viewoption_menu)); - - viewid = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "EsbItemId")); - esb->viewitem_id = viewid; - - entry_style = gtk_widget_get_style (esb->entry); - default_style = gtk_widget_get_default_style (); - - /* If the text is grayed, Its not the query string */ - if (gdk_color_equal (&(entry_style->text[GTK_STATE_NORMAL]), &(default_style->text[GTK_STATE_INSENSITIVE]))) { - gtk_entry_set_text (GTK_ENTRY (esb->entry), ""); - gtk_widget_modify_text (esb->entry, GTK_STATE_NORMAL, NULL); - } - - esb->block_search = TRUE; - emit_search_activated (esb); - esb->block_search = FALSE; -} - -static void -scopeitem_activated_cb(GtkWidget *widget, ESearchBar *esb) -{ - gint scopeid; - GtkStyle *entry_style, *default_style; - - widget = gtk_menu_get_active (GTK_MENU (esb->scopeoption_menu)); - - scopeid = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "EsbItemId")); - esb->scopeitem_id = scopeid; - - entry_style = gtk_widget_get_style (esb->entry); - default_style = gtk_widget_get_default_style (); - - /* If the text is grayed, Its not the query string */ - if (gdk_color_equal (&(entry_style->text[GTK_STATE_NORMAL]), &(default_style->text[GTK_STATE_INSENSITIVE]))) { - gtk_widget_grab_focus (esb->entry); - gtk_entry_set_text (GTK_ENTRY (esb->entry), ""); - gtk_widget_modify_text (esb->entry, GTK_STATE_NORMAL, NULL); - } - - esb->block_search = TRUE; - emit_search_activated (esb); - esb->block_search = FALSE; -} - -static void -option_activated_cb (GtkWidget *widget, - ESearchBar *esb) -{ - gint id; - const gchar *text; - - id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "EsbItemId")); - - e_search_bar_set_item_id (esb, id); - - if (GTK_IS_RADIO_MENU_ITEM (gtk_menu_get_active ( GTK_MENU (esb->option_menu)))) { - gchar *t; - text = get_selected_item_label (esb->option_menu); - if (text && *text) - t = g_strdup_printf ("%s: %s\n%s", _("Search"), text, _("Click here to change the search type")); - else - t = g_strdup_printf ("%s: %s", _("Search"), _("Click here to change the search type")); - - gtk_widget_set_tooltip_text (esb->option_button, t); - g_free (t); - } - - if (!esb->block_search) { - emit_query_changed (esb); - } - if (!esb->block_search && id > 0) { - emit_search_activated (esb); - } -} - -static void -option_button_clicked_cb (GtkWidget *widget, GdkEventButton *event, - ESearchBar *esb) -{ - gtk_menu_popup (GTK_MENU (esb->option_menu), NULL, NULL, NULL, NULL,1,gtk_get_current_event_time()); - - gtk_widget_grab_focus (esb->entry); -} - -static void -clear_button_clicked_cb (GtkWidget *widget, GdkEventButton *event, - ESearchBar *esb) -{ - gtk_widget_modify_base (esb->entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_text (esb->entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_base (esb->icon_entry, GTK_STATE_NORMAL, NULL); - gtk_widget_set_sensitive (esb->clear_button, FALSE); - esb_paint_label (esb->label, FALSE); - - clear_search (esb); - gtk_entry_set_text (GTK_ENTRY (esb->entry), ""); - gtk_widget_grab_focus (esb->entry); -} - -static gboolean -entry_key_press_cb (GtkWidget *widget, - GdkEventKey *key_event, - ESearchBar *esb) -{ - if (((key_event->state & gtk_accelerator_get_default_mod_mask ()) == - GDK_MOD1_MASK) && (key_event->keyval == GDK_Down)) { - option_button_clicked_cb (NULL, NULL, esb); - return TRUE; - } - - return FALSE; -} - -#if 0 -static void -scopeoption_changed_cb (GtkWidget *option_menu, ESearchBar *search_bar) -{ - gchar *text = NULL; - - text = e_search_bar_get_text (search_bar); - if (!(text && *text)) - gtk_widget_grab_focus (search_bar->entry); - - if (!search_bar->block_search) - emit_query_changed (search_bar); - - g_free (text); -} -#endif - -/* Widgetry creation. */ - -#if 0 -/* This function exists to fix the irreparable GtkOptionMenu stupidity. In - fact, this lame-ass widget adds a 1-pixel-wide empty border around the - button for no reason. So we have add a 1-pixel-wide border around the the - buttons we have in the search bar to make things look right. This is done - through an event box. */ -static GtkWidget * -put_in_spacer_widget (GtkWidget *widget) -{ - GtkWidget *holder; - - holder = gtk_event_box_new (); - gtk_container_set_border_width (GTK_CONTAINER (holder), 1); - gtk_container_add (GTK_CONTAINER (holder), widget); - - return holder; -} -#endif - -static void -append_xml_menu_item (GString *xml, - const gchar *name, - const gchar *label, - const gchar *stock, - const gchar *verb, - const gchar *accelerator) -{ - gchar *encoded_label; - - encoded_label = bonobo_ui_util_encode_str (label); - g_string_append_printf (xml, "<menuitem name=\"%s\" verb=\"%s\" label=\"%s\"", - name, verb, encoded_label); - g_free (encoded_label); - - if (accelerator != NULL) - g_string_append_printf (xml, " accel=\"%s\"", accelerator); - if (stock != NULL) - g_string_append_printf (xml, " pixtype=\"stock\" pixname=\"%s\"", stock); - - g_string_append (xml, "/>"); -} - -static void -remove_bonobo_menus (ESearchBar *esb) -{ - if (bonobo_ui_component_get_container (esb->ui_component) == CORBA_OBJECT_NIL) - return; - - bonobo_ui_component_rm (esb->ui_component, "/menu/SearchPlaceholder", NULL); -} - -static void -setup_bonobo_menus (ESearchBar *esb) -{ - GString *xml; - GSList *p; - gchar *verb_name; - gchar *encoded_title; - - xml = g_string_new (""); - - encoded_title = bonobo_ui_util_encode_str (_("_Search")); - g_string_append_printf (xml, "<submenu name=\"Search\" label=\"%s\">", encoded_title); - g_free (encoded_title); - - g_string_append (xml, "<placeholder name=\"SearchBar\">"); - - append_xml_menu_item (xml, "FindNow", _("_Find Now"), "gtk-find", "ESearchBar:FindNow", NULL); - append_xml_menu_item (xml, "Clear", _("_Clear"), "gtk-clear", "ESearchBar:Clear", "*Control**Shift*q"); - - for (p = esb->menu_items; p != NULL; p = p->next) { - const ESearchBarItem *item; - - item = (const ESearchBarItem *) p->data; - - verb_name = verb_name_from_id (item->id); - bonobo_ui_component_add_verb (esb->ui_component, verb_name, search_verb_cb, esb); - - if (item->text == NULL) - g_string_append (xml, "<separator/>"); - else - append_xml_menu_item (xml, verb_name, item->text, NULL, verb_name, NULL); - - g_free (verb_name); - } - - g_string_append (xml, "</placeholder>"); - g_string_append (xml, "</submenu>"); - - remove_bonobo_menus (esb); - bonobo_ui_component_set (esb->ui_component, "/menu/SearchPlaceholder", xml->str, NULL); - - g_string_free (xml, TRUE); - - if (esb->clear_button) { - g_signal_connect (esb->clear_button, "state-changed", G_CALLBACK (clear_button_state_changed), esb); - } -} - -static void -update_bonobo_menus (ESearchBar *esb) -{ - setup_bonobo_menus (esb); -} - -static void -set_menu (ESearchBar *esb, - ESearchBarItem *items) -{ - gint i; - - free_menu_items (esb); - - if (items == NULL) - return; - - for (i = 0; items[i].id != -1; i++) { - ESearchBarItem *new_item; - - new_item = g_new (ESearchBarItem, 1); - new_item->text = items[i].text ? g_strdup (_(items[i].text)) : NULL; - new_item->id = items[i].id; - new_item->type = items[i].type; - - esb->menu_items = g_slist_append (esb->menu_items, new_item); - } - - if (!esb->lite && esb->ui_component != NULL) - update_bonobo_menus (esb); -} - -/* /\* Callback used when an option item is destroyed. We have to destroy its */ -/* * suboption items. */ -/* *\/ */ -/* static gpointer */ -/* option_item_destroy_cb (GtkObject *object, gpointer data) */ -/* { */ -/* /\* ESearchBarSubitem *subitems; *\/ */ - -/* /\* subitems = data; *\/ */ - -/* /\* g_assert (subitems != NULL); *\/ */ -/* /\* free_subitems (subitems); *\/ */ -/* /\* g_object_set_data (G_OBJECT (object), "EsbChoiceSubitems", NULL); *\/ */ -/* } */ - -static void -set_option (ESearchBar *esb, ESearchBarItem *items) -{ - GtkWidget *menu; - GSList *group = NULL; - gint i; - - if (esb->option_menu) - gtk_widget_destroy (esb->option_menu); - - esb->option_menu = menu = gtk_menu_new (); - for (i = 0; items[i].id != -1; i++) { - GtkWidget *item; - - /* Create a new group */ - if (items[i].id == 0) - group = NULL; - - if (items[i].text) { - gchar *str; - str = e_str_without_underscores (_(items[i].text)); - switch (items[i].type) { - case ESB_ITEMTYPE_NORMAL: - item = gtk_menu_item_new_with_label (str); - break; - case ESB_ITEMTYPE_CHECK: - item = gtk_check_menu_item_new_with_label (str); - break; - case ESB_ITEMTYPE_RADIO: - item = gtk_radio_menu_item_new_with_label (group, str); - group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM (item)); - break; - default: - /* Fixme : this should be a normal item */ - item = gtk_radio_menu_item_new_with_label (group, str); - group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM (item)); - break; - } - g_free (str); - } else { - item = gtk_menu_item_new (); - gtk_widget_set_sensitive (item, FALSE); - } - - gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - - g_object_set_data (G_OBJECT (item), "EsbItemId", GINT_TO_POINTER(items[i].id)); - - g_signal_connect (item, "activate", - G_CALLBACK (option_activated_cb), - esb); - } - - gtk_widget_show_all (menu); - g_object_set_data (G_OBJECT(esb->option_menu), "group", group); - entry_focus_out_cb (esb->entry, NULL, esb); -} - -static gint -find_id (GtkWidget *menu, gint idin, const gchar *type, GtkWidget **widget) -{ - GList *l = GTK_MENU_SHELL (menu)->children; - gint row = -1, i = 0, id; - - if (widget) - *widget = NULL; - while (l) { - id = GPOINTER_TO_INT (g_object_get_data (l->data, type)); - if (id == idin) { - row = i; - if (widget) - *widget = l->data; - break; - } - i++; - l = l->next; - } - return row; -} - - -/* GtkObject methods. */ - -static void -impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - ESearchBar *esb = E_SEARCH_BAR (object); - - switch (prop_id) { - case PROP_ITEM_ID: - g_value_set_int (value, e_search_bar_get_item_id (esb)); - break; - - case PROP_TEXT: - g_value_take_string (value, e_search_bar_get_text (esb)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - ESearchBar *esb = E_SEARCH_BAR(object); - - switch (prop_id) { - case PROP_ITEM_ID: - e_search_bar_set_item_id (esb, g_value_get_int (value)); - break; - - case PROP_TEXT: - e_search_bar_set_text (esb, g_value_get_string (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -impl_dispose (GObject *object) -{ - ESearchBar *esb = E_SEARCH_BAR (object); - - g_return_if_fail (object != NULL); - g_return_if_fail (E_IS_SEARCH_BAR (object)); - - /* These three we do need to unref, because we explicitly hold - references to them. */ - - if (!esb->lite && esb->ui_component != NULL) { - bonobo_object_unref (BONOBO_OBJECT (esb->ui_component)); - esb->ui_component = NULL; - } -/* if (esb->entry) { */ -/* g_object_unref (esb->entry); */ -/* esb->entry = NULL; */ -/* } */ - if (esb->suboption) { - g_object_unref (esb->suboption); - esb->suboption = NULL; - } - - if (esb->pending_activate) { - g_source_remove (esb->pending_activate); - esb->pending_activate = 0; - } - - free_menu_items (esb); - - if (G_OBJECT_CLASS (parent_class)->dispose) - G_OBJECT_CLASS (parent_class)->dispose (object); -} - - -static void -class_init (ESearchBarClass *klass) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (klass); - - parent_class = g_type_class_ref (gtk_hbox_get_type ()); - - object_class->set_property = impl_set_property; - object_class->get_property = impl_get_property; - object_class->dispose = impl_dispose; - - klass->set_menu = set_menu; - klass->set_option = set_option; - - g_object_class_install_property (object_class, PROP_ITEM_ID, - g_param_spec_int ("item_id", - _("Item ID"), - /*_( */"XXX blurb" /*)*/, - 0, 0, 0, - G_PARAM_READWRITE | G_PARAM_LAX_VALIDATION)); - - g_object_class_install_property (object_class, PROP_TEXT, - g_param_spec_string ("text", - _("Text"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - esb_signals [QUERY_CHANGED] = - g_signal_new ("query_changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ESearchBarClass, query_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - esb_signals [MENU_ACTIVATED] = - g_signal_new ("menu_activated", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ESearchBarClass, menu_activated), - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); - - esb_signals [SEARCH_ACTIVATED] = - g_signal_new ("search_activated", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ESearchBarClass, search_activated), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - esb_signals [SEARCH_CLEARED] = - g_signal_new ("search_cleared", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ESearchBarClass, search_cleared), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -static void -init (ESearchBar *esb) -{ - esb->ui_component = NULL; - esb->menu_items = NULL; - - esb->option = NULL; - esb->entry = NULL; - esb->suboption = NULL; - - esb->option_menu = NULL; - esb->suboption_menu = NULL; - esb->option_button = NULL; - esb->clear_button = NULL; - esb->entry_box = NULL; - - esb->scopeoption_menu = NULL; - esb->scopeoption = NULL; - esb->scopeoption_box = NULL; - - esb->pending_activate = 0; - - esb->item_id = 0; - esb->scopeitem_id = 0; - esb->last_search_option = 0; - esb->block_search = FALSE; -} - - -/* Object construction. */ - -static gint -idle_activate_hack (gpointer ptr) -{ - ESearchBar *esb = E_SEARCH_BAR (ptr); - esb->pending_activate = 0; - emit_search_activated (esb); - return FALSE; -} - -void -e_search_bar_construct (ESearchBar *search_bar, - ESearchBarItem *menu_items, - ESearchBarItem *option_items) -{ - GtkWidget *label, *hbox, *bighbox; - - g_return_if_fail (search_bar != NULL); - g_return_if_fail (E_IS_SEARCH_BAR (search_bar)); - g_return_if_fail (option_items != NULL); - - gtk_box_set_spacing (GTK_BOX (search_bar), 3); - - gtk_box_set_homogeneous (GTK_BOX (search_bar), FALSE); - - bighbox = gtk_hbox_new (FALSE, 0); - search_bar->entry_box = gtk_hbox_new (0, FALSE); - search_bar->icon_entry = e_icon_entry_new (); - search_bar->entry = e_icon_entry_get_entry (E_ICON_ENTRY (search_bar->icon_entry)); - - g_signal_connect (search_bar->entry, "changed", - G_CALLBACK (entry_changed_cb), search_bar); - g_signal_connect (search_bar->entry, "activate", - G_CALLBACK (entry_activated_cb), search_bar); - g_signal_connect (search_bar->entry, "focus-in-event", - G_CALLBACK (entry_focus_in_cb), search_bar); - g_signal_connect (search_bar->entry, "focus-out-event", - G_CALLBACK (entry_focus_out_cb), search_bar); - g_signal_connect (search_bar->entry, "key-press-event", - G_CALLBACK (entry_key_press_cb), search_bar); - - search_bar->label = NULL; - if (search_bar->lite) { - label = e_icon_entry_create_text (_("Search")); - g_signal_connect (G_OBJECT (label), "button-press-event", G_CALLBACK(search_entry_press_cb), search_bar); - e_icon_entry_pack_widget (E_ICON_ENTRY (search_bar->icon_entry), label, FALSE); - search_bar->label = g_object_get_data ((GObject *)label, "lbl"); - esb_paint_label (search_bar->label, FALSE); - - label = e_icon_entry_create_separator (); - e_icon_entry_pack_widget (E_ICON_ENTRY (search_bar->icon_entry), label, FALSE); - } - - search_bar->clear_button = e_icon_entry_create_button ("gtk-clear"); - g_signal_connect (G_OBJECT (search_bar->clear_button), "button-press-event", G_CALLBACK(clear_button_clicked_cb), search_bar); - e_icon_entry_pack_widget (E_ICON_ENTRY (search_bar->icon_entry), search_bar->clear_button, FALSE); - - search_bar->option_button = e_icon_entry_create_button ("gtk-find"); - g_signal_connect (G_OBJECT (search_bar->option_button), "button-press-event", G_CALLBACK(option_button_clicked_cb), search_bar); - e_icon_entry_pack_widget (E_ICON_ENTRY (search_bar->icon_entry), search_bar->option_button, TRUE); - - if (!search_bar->lite) - gtk_box_pack_start (GTK_BOX(search_bar->entry_box), search_bar->icon_entry, FALSE, FALSE, 0); - else - gtk_box_pack_start (GTK_BOX(search_bar->entry_box), search_bar->icon_entry, TRUE, TRUE, 0); - - gtk_widget_show_all (search_bar->entry_box); - gtk_widget_set_sensitive (search_bar->clear_button, FALSE); - - if (!search_bar->lite) { - /* Current View filter */ - search_bar->viewoption_box = gtk_hbox_new (0, FALSE); - - /* To Translators: The "Show: " label is followed by the Quick Search Dropdown Menu where you can choose - to display "All Messages", "Unread Messages", "Message with 'Important' Label" and so on... */ - label = gtk_label_new_with_mnemonic (_("Sho_w: ")); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX(search_bar->viewoption_box), label, FALSE, FALSE, 0); - - search_bar->viewoption = gtk_option_menu_new (); - gtk_label_set_mnemonic_widget ((GtkLabel *)label, search_bar->viewoption); - gtk_box_pack_start (GTK_BOX(search_bar->viewoption_box), search_bar->viewoption, FALSE, TRUE, 0); - gtk_widget_show_all (search_bar->viewoption_box); - gtk_box_pack_start (GTK_BOX(search_bar), search_bar->viewoption_box, FALSE, FALSE, 0); - - hbox = gtk_hbox_new (FALSE, 0); - gtk_box_pack_start (GTK_BOX(search_bar), hbox, FALSE, FALSE, 0); - } - - /* Search entry */ - hbox = gtk_hbox_new (FALSE, 0); - /* To Translators: The "Show: " label is followed by the Quick Search Text input field where one enters - the term to search for */ - if (!search_bar->lite) { - label = gtk_label_new_with_mnemonic (_("Sear_ch: ")); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX(hbox), search_bar->entry_box, FALSE, FALSE, 0); - gtk_label_set_mnemonic_widget ((GtkLabel *)label, search_bar->entry); - } else { - gtk_box_pack_start (GTK_BOX(hbox), search_bar->entry_box, TRUE, TRUE, 0); - } - gtk_widget_show (search_bar->entry_box); - - if (!search_bar->lite) { - /* Search Scope Widgets */ - search_bar->scopeoption_box = gtk_hbox_new (0, FALSE); - gtk_box_set_spacing (GTK_BOX (search_bar->scopeoption_box), 3); - /* To Translators: The " in " label is part of the Quick Search Bar, example: - Search: | <user's_search_term> | in | Current Folder/All Accounts/Current Account */ - label = gtk_label_new_with_mnemonic (_(" i_n ")); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX(search_bar->scopeoption_box), label, FALSE, FALSE, 0); - - search_bar->scopeoption = gtk_option_menu_new (); - /* g_signal_connect (GTK_OPTION_MENU (search_bar->scopeoption), "changed", scopeoption_changed_cb, search_bar); */ - gtk_box_pack_start (GTK_BOX(search_bar->scopeoption_box), search_bar->scopeoption, FALSE, FALSE, 0); - gtk_widget_show_all (search_bar->scopeoption_box); - gtk_widget_hide (hbox); - gtk_label_set_mnemonic_widget ((GtkLabel *)label, search_bar->scopeoption); - - gtk_box_pack_end (GTK_BOX(hbox), search_bar->scopeoption_box, FALSE, FALSE, 0); - gtk_widget_hide (search_bar->scopeoption_box); - - } - if (!search_bar->lite) - gtk_box_pack_end (GTK_BOX(search_bar), hbox, FALSE, FALSE, 0); - else - gtk_box_pack_end (GTK_BOX(search_bar), hbox, TRUE, TRUE, 0); - - gtk_widget_show (hbox); - - /* Set the menu */ - e_search_bar_set_menu (search_bar, menu_items); - e_search_bar_set_option (search_bar, option_items); - - /* - * If the default choice for the option menu has subitems, then we need to - * activate the search immediately. However, the developer won't have - * connected to the activated signal until after the object is constructed, - * so we can't emit here. Thus we launch a one-shot idle function that will - * emit the changed signal, so that the proper callback will get invoked. - */ - if (!search_bar->lite) - search_bar->pending_activate = g_idle_add (idle_activate_hack, search_bar); -} - -void -e_search_bar_set_menu (ESearchBar *search_bar, ESearchBarItem *menu_items) -{ - g_return_if_fail (search_bar != NULL); - g_return_if_fail (E_IS_SEARCH_BAR (search_bar)); - - ((ESearchBarClass *) GTK_OBJECT_GET_CLASS (search_bar))->set_menu (search_bar, menu_items); -} - -void -e_search_bar_add_menu (ESearchBar *search_bar, ESearchBarItem *menu_item) -{ - g_return_if_fail (search_bar != NULL); - g_return_if_fail (E_IS_SEARCH_BAR (search_bar)); - - set_menu (search_bar, menu_item); -} - -void -e_search_bar_set_option (ESearchBar *search_bar, ESearchBarItem *option_items) -{ - g_return_if_fail (search_bar != NULL); - g_return_if_fail (E_IS_SEARCH_BAR (search_bar)); - g_return_if_fail (option_items != NULL); - - ((ESearchBarClass *) GTK_OBJECT_GET_CLASS (search_bar))->set_option (search_bar, option_items); -} - -void -e_search_bar_set_viewoption_menufunc (ESearchBar *search_bar, ESearchBarMenuFunc *menu_gen_func, gpointer data) -{ - g_signal_connect (search_bar->viewoption, "button_press_event", G_CALLBACK (menu_gen_func), data); -} - -/** - * e_search_bar_set_viewoption_menu: - * @search_bar: A search bar. - * @option_id: Identifier of the main option menu item under which the subitems - * are to be set. - * @subitems: Array of subitem information. - * - * Sets the items for the secondary option menu of a search bar. - **/ -void -e_search_bar_set_viewoption_menu (ESearchBar *search_bar, GtkWidget *menu) -{ - - if (search_bar->viewoption_menu != NULL) - gtk_option_menu_remove_menu (GTK_OPTION_MENU (search_bar->viewoption)); - - search_bar->viewoption_menu = menu; - gtk_option_menu_set_menu (GTK_OPTION_MENU (search_bar->viewoption), search_bar->viewoption_menu); - - g_signal_connect (search_bar->viewoption_menu, - "selection-done", - G_CALLBACK (viewitem_activated_cb), - search_bar); -} - -GtkWidget * -e_search_bar_get_selected_viewitem (ESearchBar *search_bar) -{ - GtkWidget *widget = NULL; - - widget = gtk_menu_get_active (GTK_MENU (search_bar->viewoption_menu)); - - return widget; -} - -/** - * e_search_bar_set_viewoption: - * @search_bar: A search bar. - * @option_id: Identifier of the main option menu item under which the subitems - * are to be set. - * @subitems: Array of subitem information. - * - * Sets the items for the secondary option menu of a search bar. - **/ -void -e_search_bar_set_viewoption (ESearchBar *search_bar, gint option_id, ESearchBarItem *subitems) -{ - GtkWidget *menu; - GtkWidget *menu_item; - gint i; - - /* Create the menu if it is not there. right scenario ????*/ - - if (search_bar->viewoption_menu == NULL) { - search_bar->viewoption_menu = menu = gtk_menu_new (); - } else { - gtk_option_menu_remove_menu (GTK_OPTION_MENU (search_bar->viewoption)); - search_bar->viewoption_menu = menu = gtk_menu_new (); - } - - /* Create the items */ - - for (i = 0; subitems[i].id != -1; ++i) { - if (subitems[i].text) { - gchar *str = NULL; - str = e_str_without_underscores (subitems[i].text); - menu_item = gtk_menu_item_new_with_label (str); - g_free (str); - } else { - menu_item = gtk_menu_item_new (); - gtk_widget_set_sensitive (menu_item, FALSE); - } - - g_object_set_data (G_OBJECT (menu_item), "EsbItemId", - GINT_TO_POINTER (subitems[i].id)); - - g_signal_connect (menu_item, - "activate", - G_CALLBACK (viewitem_activated_cb), - search_bar); - - gtk_widget_show (menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); - } - gtk_option_menu_set_menu (GTK_OPTION_MENU (search_bar->viewoption), menu); - -} - -/** - * e_search_bar_set_scopeoption: - * @search_bar: A search bar. - * are to be set. - * @scopeitems: Array of scope information. - * - * Sets the items for the search scope option menu of a search bar. - **/ -void -e_search_bar_set_scopeoption (ESearchBar *search_bar, ESearchBarItem *scopeitems) -{ - GtkWidget *menu; - GtkWidget *menu_item; - gint i; - - gtk_widget_show (search_bar->scopeoption_box); - if (search_bar->scopeoption_menu != NULL) { - gtk_option_menu_remove_menu (GTK_OPTION_MENU (search_bar->scopeoption)); - } - - search_bar->scopeoption_menu = menu = gtk_menu_new (); - - /* Generate items */ - for (i = 0; scopeitems[i].id != -1; ++i) { - if (scopeitems[i].text) { - gchar *str; - str = e_str_without_underscores (_(scopeitems[i].text)); - menu_item = gtk_menu_item_new_with_label (str); - g_object_set_data_full (G_OBJECT (menu_item), "string",str, g_free); - } else { - menu_item = gtk_menu_item_new (); - gtk_widget_set_sensitive (menu_item, FALSE); - } - - g_object_set_data (G_OBJECT (menu_item), "EsbItemId", - GINT_TO_POINTER (scopeitems[i].id)); - - g_signal_connect (menu_item, - "activate", - G_CALLBACK (scopeitem_activated_cb), - search_bar); - - gtk_widget_show (menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); - } - gtk_option_menu_set_menu (GTK_OPTION_MENU (search_bar->scopeoption), menu); -} - -/** - * e_search_bar_set_scopeoption_menu: - * @search_bar: A search bar. - * @menu: the scope option menu - * - * Sets the items for the secondary option menu of a search bar. - **/ -void -e_search_bar_set_scopeoption_menu (ESearchBar *search_bar, GtkMenu *menu) -{ - - if (search_bar->scopeoption_menu != NULL) - gtk_option_menu_remove_menu (GTK_OPTION_MENU (search_bar->scopeoption)); - - search_bar->scopeoption_menu = GTK_WIDGET (menu); - gtk_option_menu_set_menu (GTK_OPTION_MENU (search_bar->scopeoption), search_bar->scopeoption_menu); - - g_signal_connect (search_bar->scopeoption_menu, - "selection-done", - G_CALLBACK (scopeitem_activated_cb), - search_bar); -} - -GtkWidget * -e_search_bar_new (ESearchBarItem *menu_items, - ESearchBarItem *option_items) -{ - GtkWidget *widget; - - g_return_val_if_fail (option_items != NULL, NULL); - - widget = g_object_new (e_search_bar_get_type (), NULL); - - e_search_bar_construct (E_SEARCH_BAR (widget), menu_items, option_items); - - return widget; -} - -GtkWidget * -e_search_bar_lite_new (ESearchBarItem *menu_items, - ESearchBarItem *option_items) -{ - GtkWidget *widget; - - g_return_val_if_fail (option_items != NULL, NULL); - - widget = g_object_new (e_search_bar_get_type (), NULL); - E_SEARCH_BAR(widget)->lite = TRUE; - - e_search_bar_construct (E_SEARCH_BAR (widget), menu_items, option_items); - - return widget; -} - -void -e_search_bar_set_ui_component (ESearchBar *search_bar, - BonoboUIComponent *ui_component) -{ - g_return_if_fail (E_IS_SEARCH_BAR (search_bar)); - - if (search_bar->lite) - return; - - if (search_bar->ui_component != NULL) { - remove_bonobo_menus (search_bar); - bonobo_object_unref (BONOBO_OBJECT (search_bar->ui_component)); - } - - search_bar->ui_component = ui_component; - if (ui_component != NULL) { - bonobo_object_ref (BONOBO_OBJECT (ui_component)); - setup_standard_verbs (search_bar); - setup_bonobo_menus (search_bar); - } -} - -void -e_search_bar_set_menu_sensitive (ESearchBar *search_bar, gint id, gboolean state) -{ - gchar *verb_name; - gchar *path; - - if (search_bar->lite) - return; - - verb_name = verb_name_from_id (id); - path = g_strconcat ("/commands/", verb_name, NULL); - g_free (verb_name); - - bonobo_ui_component_set_prop (search_bar->ui_component, path, - "sensitive", state ? "1" : "0", - NULL); - - g_free (path); -} - -GType -e_search_bar_get_type (void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof (ESearchBarClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (ESearchBar), - 0, /* n_preallocs */ - (GInstanceInitFunc) init, - }; - - type = g_type_register_static (gtk_hbox_get_type (), "ESearchBar", &info, 0); - } - - return type; -} - -void -e_search_bar_set_viewitem_id (ESearchBar *search_bar, gint id) -{ - gint row; - - g_return_if_fail (E_IS_SEARCH_BAR (search_bar)); - if (!search_bar->viewoption_menu) - return; - - row = find_id (search_bar->viewoption_menu, id, "EsbItemId", NULL); - if (row == -1) - return; - search_bar->viewitem_id = id; - gtk_option_menu_set_history (GTK_OPTION_MENU (search_bar->viewoption), row); - - emit_query_changed (search_bar); -} - -/** - * e_search_bar_set_item_id: - * @search_bar: A search bar. - * @id: Identifier of the item to set. - * - * Sets the active item in the options menu of a search bar. - **/ -void -e_search_bar_set_item_id (ESearchBar *search_bar, gint id) -{ - gint row; - - g_return_if_fail (E_IS_SEARCH_BAR (search_bar)); - - if (!search_bar->option_menu) - return; - row = find_id (search_bar->option_menu, id, "EsbItemId", NULL); - if (row == -1) - return; - - if (id>=0) - search_bar->last_search_option = id; - search_bar->item_id = id; - gtk_menu_set_active ((GtkMenu *)search_bar->option_menu, row); - - if (!search_bar->block_search) - emit_query_changed (search_bar); - - if (!search_bar->lite) - update_clear_menuitem_sensitive (search_bar); -} - -void -e_search_bar_set_item_menu (ESearchBar *search_bar, gint id) -{ - gint row; - GtkWidget *item; - g_return_if_fail (E_IS_SEARCH_BAR (search_bar)); - - row = find_id (search_bar->option_menu, id, "EsbItemId", &item); - if (row == -1) - return; - - gtk_menu_set_active ((GtkMenu *)search_bar->option_menu, row); - if (id>=0) - gtk_check_menu_item_set_active ((GtkCheckMenuItem *)item, TRUE); -} - -/** - * e_search_bar_set_search_scope: - * @search_bar: A search bar. - * @id: Identifier of the item to set. - * - * Sets the active item in the options menu of a search bar. - **/ -void -e_search_bar_set_search_scope (ESearchBar *search_bar, gint id) -{ - gint row; - - g_return_if_fail (E_IS_SEARCH_BAR (search_bar)); - - if (!search_bar->scopeoption_menu) - return; - row = find_id (search_bar->scopeoption_menu, id, "EsbItemId", NULL); - if (row == -1) - return; - - search_bar->scopeitem_id = id; - gtk_option_menu_set_history (GTK_OPTION_MENU (search_bar->scopeoption), row); - - if (!search_bar->block_search) - emit_query_changed (search_bar); -} - -/** - * e_search_bar_get_item_id: - * @search_bar: A search bar. - * - * Queries the currently selected item in the options menu of a search bar. - * - * Return value: Identifier of the selected item in the options menu. - **/ -gint -e_search_bar_get_item_id (ESearchBar *search_bar) -{ - GtkWidget *menu_item; - gint item_id; - - g_return_val_if_fail (search_bar != NULL, -1); - g_return_val_if_fail (E_IS_SEARCH_BAR (search_bar), -1); - - menu_item = gtk_menu_get_active (GTK_MENU (search_bar->option_menu)); - item_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item), "EsbItemId")); - search_bar->item_id = item_id; - - return search_bar->item_id; -} - -/** - * e_search_bar_get_search_scope: - * @search_bar: A search bar. - * - * Queries the currently selected search type in the options menu of a search bar. - * - * Return value: Identifier of the selected item in the options menu. - **/ -gint -e_search_bar_get_search_scope (ESearchBar *search_bar) -{ - GtkWidget *menu_item; - gint scopeitem_id; - - g_return_val_if_fail (search_bar != NULL, -1); - g_return_val_if_fail (E_IS_SEARCH_BAR (search_bar), -1); - - if (!search_bar->scopeoption_menu) - return -7 /*Current folder hack */; - - menu_item = gtk_menu_get_active (GTK_MENU (search_bar->scopeoption_menu)); - scopeitem_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item), "EsbItemId")); - - search_bar->scopeitem_id = scopeitem_id; - - return search_bar->scopeitem_id; -} - -/** - * e_search_bar_get_viewitem_id: - * @search_bar: A search bar. - * - * Queries the currently selected item in the viewoptions menu of a search bar. - * - * Return value: Identifier of the selected item in the viewoptions menu. - * If the search bar currently contains an entry rather than a a viewoption menu, - * a value less than zero is returned. - **/ -gint -e_search_bar_get_viewitem_id (ESearchBar *search_bar) -{ - GtkWidget *menu_item; - gint viewitem_id; - - g_return_val_if_fail (search_bar != NULL, -1); - g_return_val_if_fail (E_IS_SEARCH_BAR (search_bar), -1); - - if (!search_bar->viewoption_menu) - return -1; - - menu_item = gtk_menu_get_active (GTK_MENU (search_bar->viewoption_menu)); - viewitem_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item), "EsbItemId")); - - search_bar->viewitem_id = viewitem_id; - - return search_bar->viewitem_id; -} - -/** - * e_search_bar_set_ids: - * @search_bar: A search bar. - * @item_id: Identifier of the item to set. - * @subitem_id: Identifier of the subitem to set. - * - * Sets the item and subitem ids for a search bar. This is intended to switch - * to an item that has subitems. - **/ -void -e_search_bar_set_ids (ESearchBar *search_bar, gint item_id, gint subitem_id) -{ - gint item_row; - GtkWidget *item_widget; - - g_return_if_fail (search_bar != NULL); - g_return_if_fail (E_IS_SEARCH_BAR (search_bar)); - - item_row = find_id (search_bar->option_menu, item_id, "EsbChoiceId", &item_widget); - if (item_row == -1 || !item_widget) - return; - - search_bar->item_id = item_id; - gtk_option_menu_set_history (GTK_OPTION_MENU (search_bar->option), item_row); - -} - -/** - * e_search_bar_set_text: - * @search_bar: A search bar. - * @text: Text to set in the search bar's entry line. - * - * Sets the text string inside the entry line of a search bar. - **/ -void -e_search_bar_set_text (ESearchBar *search_bar, const gchar *text) -{ - g_return_if_fail (E_IS_SEARCH_BAR (search_bar)); - gtk_entry_set_text (GTK_ENTRY (search_bar->entry), text); -} - -/** - * e_search_bar_get_text: - * @search_bar: A search bar. - * - * Queries the text of the entry line in a search bar. - * - * Return value: The text string that is in the entry line of the search bar. - * This must be freed using g_free(). If a suboption menu is active instead - * of an entry, NULL is returned. - **/ -gchar * -e_search_bar_get_text (ESearchBar *search_bar) -{ - GtkStyle *entry_style, *default_style; - - g_return_val_if_fail (search_bar != NULL, NULL); - g_return_val_if_fail (E_IS_SEARCH_BAR (search_bar), NULL); - - entry_style = gtk_widget_get_style (search_bar->entry); - default_style = gtk_widget_get_default_style (); - - if (gdk_color_equal (&(entry_style->text[GTK_STATE_NORMAL]), &(default_style->text[GTK_STATE_INSENSITIVE]))) - return g_strdup (""); - - return g_strdup (gtk_entry_get_text (GTK_ENTRY (search_bar->entry))); -} - -void e_search_bar_scope_enable (ESearchBar *esb, gint did, gboolean state) -{ - GtkWidget *widget=NULL; - GList *l; - gint id; - gpointer *pointer; - - g_return_if_fail (esb != NULL); - g_return_if_fail (E_IS_SEARCH_BAR (esb)); - - l = GTK_MENU_SHELL (esb->scopeoption_menu)->children; - while (l) { - pointer = g_object_get_data (l->data, "EsbItemId"); - if (pointer) { - id = GPOINTER_TO_INT (pointer); - if (id == did) { - widget = l->data; - break; - } - } - l = l->next; - } - - if (widget) - gtk_widget_set_sensitive (widget, state); -} diff --git a/widgets/misc/e-search-bar.h b/widgets/misc/e-search-bar.h deleted file mode 100644 index 5385ebf66a..0000000000 --- a/widgets/misc/e-search-bar.h +++ /dev/null @@ -1,194 +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) - * - */ - -#ifndef __E_SEARCH_BAR_H__ -#define __E_SEARCH_BAR_H__ - -#include <gtk/gtk.h> - -#include <bonobo/bonobo-ui-component.h> - -G_BEGIN_DECLS - -/* ESearchBar - A card displaying information about a contact. - * - * The following arguments are available: - * - * name type read/write description - * --------------------------------------------------------------------------------- - * item_id gint RW Which option item is currently selected. - * subitem_id gint RW Which option subitem is currently selected. - * text string RW Text in the entry box. - */ - -#define E_SEARCH_BAR_TYPE (e_search_bar_get_type ()) -#define E_SEARCH_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_SEARCH_BAR_TYPE, ESearchBar)) -#define E_SEARCH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_SEARCH_BAR_TYPE, ESearchBarClass)) -#define E_IS_SEARCH_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_SEARCH_BAR_TYPE)) -#define E_IS_SEARCH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_SEARCH_BAR_TYPE)) - -enum _ESearchBarItemType { - ESB_ITEMTYPE_NORMAL, - ESB_ITEMTYPE_CHECK, - ESB_ITEMTYPE_RADIO -}; -typedef enum _ESearchBarItemType ESearchBarItemType; - -typedef struct { - gchar *text; - gint id; - gint type; -} ESearchBarItem; - -typedef struct _ESearchBar ESearchBar; -typedef struct _ESearchBarClass ESearchBarClass; - -typedef void (*ESearchBarMenuFunc)(ESearchBar *esb, ESearchBarItem *menu_items); - -struct _ESearchBar -{ - GtkHBox parent; - - BonoboUIComponent *ui_component; - - GSList *menu_items; - - /* item specific fields */ - GtkWidget *option; - GtkWidget *entry; - GtkWidget *suboption; /* an option menu for the choices associated with some options */ - - /* PRIVATE */ - GtkWidget *dropdown_holder; /* holds the dropdown */ - GtkWidget *option_menu; - GtkWidget *suboption_menu; - GtkWidget *option_button; - GtkWidget *clear_button; - GtkWidget *entry_box; - GtkWidget *icon_entry; - GtkWidget *label; - - /* show option widgets */ - GtkWidget *viewoption_box; - GtkWidget *viewoption; /* an option menu for the choices associated with some search options */ - GtkWidget *viewoption_menu; - - /* search scope widgets */ - GtkWidget *scopeoption_box; - GtkWidget *scopeoption; /* an option menu for the choices associated with scope search */ - GtkWidget *scopeoption_menu; - - guint pending_activate; - - /* The currently-selected item & subitem */ - gint item_id; - gint viewitem_id; /* Current View Id */ - gint scopeitem_id; /* Scope of search */ - gint last_search_option; - - gboolean block_search; - gboolean lite; -}; - -struct _ESearchBarClass -{ - GtkHBoxClass parent_class; - - void (*set_menu) (ESearchBar *, ESearchBarItem *); - void (*set_option) (ESearchBar *, ESearchBarItem *); - - /* signals */ - void (*search_activated) (ESearchBar *search); - void (*search_cleared) (ESearchBar *search); - void (*query_changed) (ESearchBar *search); - void (*menu_activated) (ESearchBar *search, gint item); -}; - -enum { - E_SEARCHBAR_FIND_NOW_ID = -1, - E_SEARCHBAR_CLEAR_ID = -2 -}; - - -GType e_search_bar_get_type (void); -void e_search_bar_construct (ESearchBar *search_bar, - ESearchBarItem *menu_items, - ESearchBarItem *option_items); -GtkWidget *e_search_bar_new (ESearchBarItem *menu_items, - ESearchBarItem *option_items); -GtkWidget *e_search_bar_lite_new (ESearchBarItem *menu_items, - ESearchBarItem *option_items); - -void e_search_bar_set_ui_component (ESearchBar *search_bar, - BonoboUIComponent *ui_component); - -void e_search_bar_set_menu (ESearchBar *search_bar, - ESearchBarItem *menu_items); -void e_search_bar_add_menu (ESearchBar *search_bar, - ESearchBarItem *menu_item); - -void e_search_bar_set_option (ESearchBar *search_bar, - ESearchBarItem *option_items); -void e_search_bar_paint (ESearchBar *search_bar); -void e_search_bar_set_viewoption (ESearchBar *search_bar, - gint option_id, - ESearchBarItem *subitems); - -void e_search_bar_set_menu_sensitive (ESearchBar *search_bar, - gint id, - gboolean state); - -void e_search_bar_set_item_id (ESearchBar *search_bar, - gint id); -void e_search_bar_set_item_menu (ESearchBar *search_bar, - gint id); -gint e_search_bar_get_item_id (ESearchBar *search_bar); - -gint e_search_bar_get_viewitem_id (ESearchBar *search_bar); - -void e_search_bar_set_viewitem_id (ESearchBar *search_bar, gint id); - -void e_search_bar_set_ids (ESearchBar *search_bar, - gint item_id, - gint subitem_id); - -void e_search_bar_set_scopeoption (ESearchBar *search_bar, ESearchBarItem *scopeitems); - -void e_search_bar_set_scopeoption_menu (ESearchBar *search_bar, GtkMenu *menu); - -void e_search_bar_set_search_scope (ESearchBar *search_bar, gint id); - -void e_search_bar_set_viewoption_menu (ESearchBar *search_bar, GtkWidget *menu); - -void e_search_bar_set_viewoption_menufunc (ESearchBar *search_bar, ESearchBarMenuFunc *menu_gen_func, gpointer data); - -GtkWidget *e_search_bar_get_selected_viewitem (ESearchBar *search_bar); - -gint e_search_bar_get_search_scope (ESearchBar *search_bar); - -void e_search_bar_set_text (ESearchBar *search_bar, - const gchar *text); -gchar *e_search_bar_get_text (ESearchBar *search_bar); -void e_search_bar_scope_enable (ESearchBar *search_bar, gint did, gboolean state); -G_END_DECLS - -#endif /* __E_SEARCH_BAR_H__ */ diff --git a/widgets/misc/e-signature-combo-box.c b/widgets/misc/e-signature-combo-box.c index cb11ba632f..d447cccb8e 100644 --- a/widgets/misc/e-signature-combo-box.c +++ b/widgets/misc/e-signature-combo-box.c @@ -1,4 +1,5 @@ /* + * e-signature-combo-box.c * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/widgets/misc/e-signature-combo-box.h b/widgets/misc/e-signature-combo-box.h index fac47518e1..dd81eb55c3 100644 --- a/widgets/misc/e-signature-combo-box.h +++ b/widgets/misc/e-signature-combo-box.h @@ -1,4 +1,5 @@ /* + * e-signature-combo-box.h * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/widgets/misc/e-signature-editor.c b/widgets/misc/e-signature-editor.c new file mode 100644 index 0000000000..53cb34906b --- /dev/null +++ b/widgets/misc/e-signature-editor.c @@ -0,0 +1,503 @@ +/* + * e-signature-editor.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-signature-editor.h" + +#include <string.h> +#include <glib/gi18n.h> + +#include <e-util/e-error.h> +#include <e-util/e-signature-utils.h> + +#define E_SIGNATURE_EDITOR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_SIGNATURE_EDITOR, ESignatureEditorPrivate)) + +enum { + PROP_0, + PROP_SIGNATURE +}; + +struct _ESignatureEditorPrivate { + GtkActionGroup *action_group; + ESignature *signature; + GtkWidget *entry; + gchar *original_name; +}; + +static const gchar *ui = +"<ui>\n" +" <menubar name='main-menu'>\n" +" <placeholder name='pre-edit-menu'>\n" +" <menu action='file-menu'>\n" +" <menuitem action='save-and-close'/>\n" +" <separator/>" +" <menuitem action='close'/>\n" +" </menu>\n" +" </placeholder>\n" +" </menubar>\n" +" <toolbar name='main-toolbar'>\n" +" <placeholder name='pre-main-toolbar'>\n" +" <toolitem action='save-and-close'/>\n" +" </placeholder>\n" +" </toolbar>\n" +"</ui>"; + +static gpointer parent_class = NULL; + +static void +handle_error (GError **error) +{ + if (*error != NULL) { + g_warning ("%s", (*error)->message); + g_clear_error (error); + } +} + +static void +action_close_cb (GtkAction *action, + ESignatureEditor *editor) +{ + gboolean something_changed = FALSE; + const gchar *original_name; + const gchar *signature_name; + + original_name = editor->priv->original_name; + signature_name = gtk_entry_get_text (GTK_ENTRY (editor->priv->entry)); + + something_changed |= gtkhtml_editor_has_undo (GTKHTML_EDITOR (editor)); + something_changed |= (strcmp (signature_name, original_name) != 0); + + if (something_changed) { + gint response; + + response = e_error_run ( + GTK_WINDOW (editor), + "mail:ask-signature-changed", NULL); + if (response == GTK_RESPONSE_YES) { + GtkActionGroup *action_group; + + action_group = editor->priv->action_group; + action = gtk_action_group_get_action ( + action_group, "save-and-close"); + gtk_action_activate (action); + return; + } else if (response == GTK_RESPONSE_CANCEL) + return; + } + + gtk_widget_destroy (GTK_WIDGET (editor)); +} + +static void +action_save_and_close_cb (GtkAction *action, + ESignatureEditor *editor) +{ + GtkWidget *entry; + ESignatureList *signature_list; + ESignature *signature; + ESignature *same_name; + const gchar *filename; + gchar *signature_name; + gboolean html; + GError *error = NULL; + + entry = editor->priv->entry; + html = gtkhtml_editor_get_html_mode (GTKHTML_EDITOR (editor)); + + if (editor->priv->signature == NULL) { + signature = e_signature_new (); + signature->name = g_strdup (_("Unnamed")); + signature->script = FALSE; + signature->html = html; + + /* FIXME Pass a GError and deal with it. */ + signature->filename = e_create_signature_file (NULL); + } else { + signature = g_object_ref (editor->priv->signature); + signature->html = html; + } + + filename = signature->filename; + gtkhtml_editor_save (GTKHTML_EDITOR (editor), filename, html, &error); + + if (error != NULL) { + e_error_run ( + GTK_WINDOW (editor), + "mail:no-save-signature", + error->message, NULL); + g_clear_error (&error); + return; + } + + signature_list = e_get_signature_list (); + + signature_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry))); + g_strstrip (signature_name); + + /* Make sure the signature name is not blank. */ + if (*signature_name == '\0') { + e_error_run ( + GTK_WINDOW (editor), + "mail:blank-signature", NULL); + gtk_widget_grab_focus (entry); + g_free (signature_name); + return; + } + + /* Don't overwrite an existing signature of the same name. + * XXX ESignatureList misuses const. */ + same_name = (ESignature *) e_signature_list_find ( + signature_list, E_SIGNATURE_FIND_NAME, signature_name); + if (same_name != NULL && strcmp (signature->uid, same_name->uid) != 0) { + e_error_run ( + GTK_WINDOW (editor), + "mail:signature-already-exists", + signature_name, NULL); + gtk_widget_grab_focus (entry); + g_free (signature_name); + return; + } + + g_free (signature->name); + signature->name = signature_name; + + if (editor->priv->signature != NULL) + e_signature_list_change (signature_list, signature); + else + e_signature_list_add (signature_list, signature); + e_signature_list_save (signature_list); + + gtk_widget_destroy (GTK_WIDGET (editor)); +} + +static GtkActionEntry entries[] = { + + { "close", + GTK_STOCK_CLOSE, + N_("_Close"), + "<Control>w", + NULL, + G_CALLBACK (action_close_cb) }, + + { "save-and-close", + GTK_STOCK_SAVE, + N_("_Save and Close"), + "<Control>Return", + NULL, + G_CALLBACK (action_save_and_close_cb) }, + + { "file-menu", + NULL, + N_("_File"), + NULL, + NULL, + NULL } +}; + +static gboolean +signature_editor_delete_event_cb (ESignatureEditor *editor, + GdkEvent *event) +{ + GtkActionGroup *action_group; + GtkAction *action; + + action_group = editor->priv->action_group; + action = gtk_action_group_get_action (action_group, "close"); + gtk_action_activate (action); + + return TRUE; +} + +static void +signature_editor_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SIGNATURE: + e_signature_editor_set_signature ( + E_SIGNATURE_EDITOR (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +signature_editor_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SIGNATURE: + g_value_set_object ( + value, e_signature_editor_get_signature ( + E_SIGNATURE_EDITOR (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +signature_editor_dispose (GObject *object) +{ + ESignatureEditorPrivate *priv; + + priv = E_SIGNATURE_EDITOR_GET_PRIVATE (object); + + if (priv->action_group != NULL) { + g_object_unref (priv->action_group); + priv->action_group = NULL; + } + + if (priv->signature != NULL) { + g_object_unref (priv->signature); + priv->signature = NULL; + } + + if (priv->entry != NULL) { + g_object_unref (priv->entry); + priv->entry = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +signature_editor_finalize (GObject *object) +{ + ESignatureEditorPrivate *priv; + + priv = E_SIGNATURE_EDITOR_GET_PRIVATE (object); + + g_free (priv->original_name); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +signature_editor_class_init (ESignatureEditorClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (ESignatureEditorPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = signature_editor_set_property; + object_class->get_property = signature_editor_get_property; + object_class->dispose = signature_editor_dispose; + object_class->finalize = signature_editor_finalize; + + g_object_class_install_property ( + object_class, + PROP_SIGNATURE, + g_param_spec_object ( + "signature", + NULL, + NULL, + E_TYPE_SIGNATURE, + G_PARAM_READWRITE)); +} + +static void +signature_editor_init (ESignatureEditor *editor) +{ + GtkActionGroup *action_group; + GtkUIManager *ui_manager; + GtkWidget *container; + GtkWidget *widget; + GtkWidget *vbox; + GError *error = NULL; + + editor->priv = E_SIGNATURE_EDITOR_GET_PRIVATE (editor); + vbox = GTKHTML_EDITOR (editor)->vbox; + + ui_manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (editor)); + + gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); + handle_error (&error); + + action_group = gtk_action_group_new ("signature"); + gtk_action_group_set_translation_domain ( + action_group, GETTEXT_PACKAGE); + gtk_action_group_add_actions ( + action_group, entries, + G_N_ELEMENTS (entries), editor); + gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); + editor->priv->action_group = g_object_ref (action_group); + + gtk_ui_manager_ensure_update (ui_manager); + + gtk_window_set_title (GTK_WINDOW (editor), _("Edit Signature")); + + widget = gtk_hbox_new (FALSE, 6); + gtk_container_set_border_width (GTK_CONTAINER (widget), 6); + gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); + /* Position 2 should be between the main and style toolbars. */ + gtk_box_reorder_child (GTK_BOX (vbox), widget, 2); + gtk_widget_show (widget); + container = widget; + + widget = gtk_entry_new (); + gtk_box_pack_end (GTK_BOX (container), widget, TRUE, TRUE, 0); + editor->priv->entry = g_object_ref_sink (widget); + gtk_widget_show (widget); + + widget = gtk_label_new_with_mnemonic (_("_Signature Name:")); + gtk_label_set_mnemonic_widget (GTK_LABEL (widget), editor->priv->entry); + gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + g_signal_connect ( + editor, "delete-event", + G_CALLBACK (signature_editor_delete_event_cb), NULL); + + e_signature_editor_set_signature (editor, NULL); +} + +GType +e_signature_editor_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (ESignatureEditorClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) signature_editor_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (ESignatureEditor), + 0, /* n_preallocs */ + (GInstanceInitFunc) signature_editor_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTKHTML_TYPE_EDITOR, "ESignatureEditor", + &type_info, 0); + } + + return type; +} + +GtkWidget * +e_signature_editor_new (void) +{ + return g_object_new (E_TYPE_SIGNATURE_EDITOR, NULL); +} + +ESignature * +e_signature_editor_get_signature (ESignatureEditor *editor) +{ + g_return_val_if_fail (E_IS_SIGNATURE_EDITOR (editor), NULL); + + return editor->priv->signature; +} + +void +e_signature_editor_set_signature (ESignatureEditor *editor, + ESignature *signature) +{ + const gchar *filename; + const gchar *signature_name; + gchar *contents; + gsize length; + GError *error = NULL; + + g_return_if_fail (E_IS_SIGNATURE_EDITOR (editor)); + + if (signature != NULL) + g_return_if_fail (E_SIGNATURE (signature)); + + if (editor->priv->signature != NULL) { + g_object_unref (editor->priv->signature); + editor->priv->signature = NULL; + } + + if (signature == NULL) + goto exit; + + editor->priv->signature = g_object_ref (signature); + + /* Load signature content. */ + + filename = signature->filename; + + if (signature->html) + g_file_get_contents (filename, &contents, &length, &error); + else { + gchar *data; + + data = e_read_signature_file (signature, FALSE, &error); + if (data != NULL) + contents = g_strdup_printf ("<PRE>\n%s", data); + else + contents = NULL; + length = -1; + g_free (data); + } + + if (error == NULL) { + gtkhtml_editor_set_html_mode ( + GTKHTML_EDITOR (editor), signature->html); + gtkhtml_editor_set_text_html ( + GTKHTML_EDITOR (editor), contents, length); + g_free (contents); + } else { + g_warning ("%s", error->message); + g_error_free (error); + } + +exit: + if (signature != NULL) + signature_name = signature->name; + else + signature_name = _("Unnamed"); + + /* Set the entry text before we grab focus. */ + g_free (editor->priv->original_name); + editor->priv->original_name = g_strdup (signature_name); + gtk_entry_set_text (GTK_ENTRY (editor->priv->entry), signature_name); + + /* Set the focus appropriately. If this is a new signature, draw + * the user's attention to the signature name entry. Otherwise go + * straight to the editing area. */ + if (signature == NULL) + gtk_widget_grab_focus (editor->priv->entry); + else { + GtkHTML *html; + + html = gtkhtml_editor_get_html (GTKHTML_EDITOR (editor)); + gtk_widget_grab_focus (GTK_WIDGET (html)); + } + + g_object_notify (G_OBJECT (editor), "signature"); +} diff --git a/widgets/misc/e-signature-editor.h b/widgets/misc/e-signature-editor.h new file mode 100644 index 0000000000..1e8b88a909 --- /dev/null +++ b/widgets/misc/e-signature-editor.h @@ -0,0 +1,70 @@ +/* + * e-signature-editor.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_SIGNATURE_EDITOR_H +#define E_SIGNATURE_EDITOR_H + +#include <gtkhtml-editor.h> +#include <e-util/e-signature.h> + +/* Standard GObject macros */ +#define E_TYPE_SIGNATURE_EDITOR \ + (e_signature_editor_get_type ()) +#define E_SIGNATURE_EDITOR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_SIGNATURE_EDITOR, ESignatureEditor)) +#define E_SIGNATURE_EDITOR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_SIGNATURE_EDITOR, ESignatureEditorClass)) +#define E_IS_SIGNATURE_EDITOR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_SIGNATURE_EDITOR)) +#define E_IS_SIGNATURE_EDITOR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_SIGNATURE_EDITOR)) +#define E_SIGNATURE_EDITOR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_SIGNATURE_EDITOR, ESignatureEditorClass)) + +G_BEGIN_DECLS + +typedef struct _ESignatureEditor ESignatureEditor; +typedef struct _ESignatureEditorClass ESignatureEditorClass; +typedef struct _ESignatureEditorPrivate ESignatureEditorPrivate; + +struct _ESignatureEditor { + GtkhtmlEditor parent; + ESignatureEditorPrivate *priv; +}; + +struct _ESignatureEditorClass { + GtkhtmlEditorClass parent_class; +}; + +GType e_signature_editor_get_type (void); +GtkWidget * e_signature_editor_new (void); +ESignature * e_signature_editor_get_signature (ESignatureEditor *editor); +void e_signature_editor_set_signature (ESignatureEditor *editor, + ESignature *signature); + +G_END_DECLS + +#endif /* E_SIGNATURE_EDITOR_H */ diff --git a/widgets/misc/e-signature-manager.c b/widgets/misc/e-signature-manager.c new file mode 100644 index 0000000000..a70bc1dc60 --- /dev/null +++ b/widgets/misc/e-signature-manager.c @@ -0,0 +1,746 @@ +/* + * e-signature-manager.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-signature-manager.h" + +#include <glib/gi18n.h> +#include <glib/gstdio.h> +#include <gdk/gdkkeysyms.h> +#include "e-util/e-binding.h" +#include "e-signature-tree-view.h" +#include "e-signature-script-dialog.h" + +#define E_SIGNATURE_MANAGER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_SIGNATURE_MANAGER, ESignatureManagerPrivate)) + +struct _ESignatureManagerPrivate { + ESignatureList *signature_list; + + GtkWidget *tree_view; + GtkWidget *add_button; + GtkWidget *add_script_button; + GtkWidget *edit_button; + GtkWidget *remove_button; + + guint allow_scripts : 1; + guint prefer_html : 1; +}; + +enum { + PROP_0, + PROP_ALLOW_SCRIPTS, + PROP_PREFER_HTML, + PROP_SIGNATURE_LIST +}; + +enum { + ADD_SIGNATURE, + ADD_SIGNATURE_SCRIPT, + EDITOR_CREATED, + EDIT_SIGNATURE, + REMOVE_SIGNATURE, + LAST_SIGNAL +}; + +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; + +static void +signature_manager_emit_editor_created (ESignatureManager *manager, + GtkWidget *editor) +{ + g_return_if_fail (E_IS_SIGNATURE_EDITOR (editor)); + + g_signal_emit (manager, signals[EDITOR_CREATED], 0, editor); +} + +static gboolean +signature_manager_key_press_event_cb (ESignatureManager *manager, + GdkEventKey *event) +{ + if (event->keyval == GDK_Delete) { + e_signature_manager_remove_signature (manager); + return TRUE; + } + + return FALSE; +} + +static gboolean +signature_manager_run_script_dialog (ESignatureManager *manager, + ESignature *signature, + const gchar *title) +{ + GtkWidget *dialog; + GFile *script_file; + const gchar *script_name; + gboolean success = FALSE; + gpointer parent; + + parent = gtk_widget_get_toplevel (GTK_WIDGET (manager)); + parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; + + dialog = e_signature_script_dialog_new (parent); + gtk_window_set_title (GTK_WINDOW (dialog), title); + + if (signature->filename != NULL && signature->name != NULL) { + + script_file = g_file_new_for_path (signature->filename); + script_name = signature->name; + + e_signature_script_dialog_set_script_file ( + E_SIGNATURE_SCRIPT_DIALOG (dialog), script_file); + e_signature_script_dialog_set_script_name ( + E_SIGNATURE_SCRIPT_DIALOG (dialog), script_name); + + g_object_unref (script_file); + } + + if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK) + goto exit; + + script_file = e_signature_script_dialog_get_script_file ( + E_SIGNATURE_SCRIPT_DIALOG (dialog)); + script_name = e_signature_script_dialog_get_script_name ( + E_SIGNATURE_SCRIPT_DIALOG (dialog)); + + g_free (signature->filename); + signature->filename = g_file_get_path (script_file); + + g_free (signature->name); + signature->name = g_strdup (script_name); + + g_object_unref (script_file); + + success = TRUE; + +exit: + gtk_widget_destroy (dialog); + + return success; +} + +static void +signature_manager_selection_changed_cb (ESignatureManager *manager, + GtkTreeSelection *selection) +{ + ESignatureTreeView *tree_view; + ESignature *signature; + GtkWidget *edit_button; + GtkWidget *remove_button; + gboolean sensitive; + + edit_button = manager->priv->edit_button; + remove_button = manager->priv->remove_button; + + tree_view = e_signature_manager_get_tree_view (manager); + signature = e_signature_tree_view_get_selected (tree_view); + sensitive = (signature != NULL); + + gtk_widget_set_sensitive (edit_button, sensitive); + gtk_widget_set_sensitive (remove_button, sensitive); +} + +static void +signature_manager_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ALLOW_SCRIPTS: + e_signature_manager_set_allow_scripts ( + E_SIGNATURE_MANAGER (object), + g_value_get_boolean (value)); + return; + + case PROP_PREFER_HTML: + e_signature_manager_set_prefer_html ( + E_SIGNATURE_MANAGER (object), + g_value_get_boolean (value)); + return; + + case PROP_SIGNATURE_LIST: + e_signature_manager_set_signature_list ( + E_SIGNATURE_MANAGER (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +signature_manager_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ALLOW_SCRIPTS: + g_value_set_boolean ( + value, + e_signature_manager_get_allow_scripts ( + E_SIGNATURE_MANAGER (object))); + return; + + case PROP_PREFER_HTML: + g_value_set_boolean ( + value, + e_signature_manager_get_prefer_html ( + E_SIGNATURE_MANAGER (object))); + return; + + case PROP_SIGNATURE_LIST: + g_value_set_object ( + value, + e_signature_manager_get_signature_list ( + E_SIGNATURE_MANAGER (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +signature_manager_dispose (GObject *object) +{ + ESignatureManagerPrivate *priv; + + priv = E_SIGNATURE_MANAGER_GET_PRIVATE (object); + + if (priv->signature_list != NULL) { + g_object_unref (priv->signature_list); + priv->signature_list = NULL; + } + + if (priv->tree_view != NULL) { + g_object_unref (priv->tree_view); + priv->tree_view = NULL; + } + + if (priv->add_button != NULL) { + g_object_unref (priv->add_button); + priv->add_button = NULL; + } + + if (priv->add_script_button != NULL) { + g_object_unref (priv->add_script_button); + priv->add_script_button = NULL; + } + + if (priv->edit_button != NULL) { + g_object_unref (priv->edit_button); + priv->edit_button = NULL; + } + + if (priv->remove_button != NULL) { + g_object_unref (priv->remove_button); + priv->remove_button = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +signature_manager_add_signature (ESignatureManager *manager) +{ + ESignatureTreeView *tree_view; + GtkWidget *editor; + + tree_view = e_signature_manager_get_tree_view (manager); + + editor = e_signature_editor_new (); + gtkhtml_editor_set_html_mode ( + GTKHTML_EDITOR (editor), manager->priv->prefer_html); + signature_manager_emit_editor_created (manager, editor); + + gtk_widget_grab_focus (GTK_WIDGET (tree_view)); +} + +static void +signature_manager_add_signature_script (ESignatureManager *manager) +{ + ESignatureTreeView *tree_view; + ESignatureList *signature_list; + ESignature *signature; + const gchar *title; + + title = _("Add Signature Script"); + tree_view = e_signature_manager_get_tree_view (manager); + signature_list = e_signature_manager_get_signature_list (manager); + + signature = e_signature_new (); + signature->script = TRUE; + signature->html = TRUE; + + if (signature_manager_run_script_dialog (manager, signature, title)) + e_signature_list_add (signature_list, signature); + + e_signature_list_save (signature_list); + g_object_unref (signature); + + gtk_widget_grab_focus (GTK_WIDGET (tree_view)); +} + +static void +signature_manager_editor_created (ESignatureManager *manager, + ESignatureEditor *editor) +{ + GtkWindowPosition position; + gpointer parent; + + position = GTK_WIN_POS_CENTER_ON_PARENT; + parent = gtk_widget_get_toplevel (GTK_WIDGET (manager)); + parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; + + gtk_window_set_transient_for (GTK_WINDOW (editor), parent); + gtk_window_set_position (GTK_WINDOW (editor), position); + gtk_widget_show (GTK_WIDGET (editor)); +} + +static void +signature_manager_edit_signature (ESignatureManager *manager) +{ + ESignatureTreeView *tree_view; + ESignatureList *signature_list; + ESignature *signature; + GtkWidget *editor; + const gchar *title; + gchar *filename; + + tree_view = e_signature_manager_get_tree_view (manager); + signature = e_signature_tree_view_get_selected (tree_view); + signature_list = e_signature_manager_get_signature_list (manager); + + if (signature == NULL) + return; + + if (signature->script) + goto script; + + filename = signature->filename; + if (filename == NULL || *filename == '\0') { + g_free (filename); + filename = g_strdup (_("Unnamed")); + signature->filename = filename; + } + + editor = e_signature_editor_new (); + e_signature_editor_set_signature ( + E_SIGNATURE_EDITOR (editor), signature); + signature_manager_emit_editor_created (manager, editor); + + goto exit; + +script: + title = _("Edit Signature Script"); + + if (signature_manager_run_script_dialog (manager, signature, title)) + e_signature_list_change (signature_list, signature); + + e_signature_list_save (signature_list); + +exit: + gtk_widget_grab_focus (GTK_WIDGET (tree_view)); + + g_object_unref (signature); +} + +static void +signature_manager_remove_signature (ESignatureManager *manager) +{ + ESignatureTreeView *tree_view; + ESignatureList *signature_list; + ESignature *signature; + + tree_view = e_signature_manager_get_tree_view (manager); + signature = e_signature_tree_view_get_selected (tree_view); + signature_list = e_signature_tree_view_get_signature_list (tree_view); + + if (signature == NULL) + return; + + if (signature->filename != NULL && !signature->script) + g_unlink (signature->filename); + + e_signature_list_remove (signature_list, signature); + e_signature_list_save (signature_list); + + gtk_widget_grab_focus (GTK_WIDGET (tree_view)); +} + +static void +signature_manager_class_init (ESignatureManagerClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (ESignatureManagerPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = signature_manager_set_property; + object_class->get_property = signature_manager_get_property; + object_class->dispose = signature_manager_dispose; + + class->add_signature = signature_manager_add_signature; + class->add_signature_script = signature_manager_add_signature_script; + class->editor_created = signature_manager_editor_created; + class->edit_signature = signature_manager_edit_signature; + class->remove_signature = signature_manager_remove_signature; + + g_object_class_install_property ( + object_class, + PROP_ALLOW_SCRIPTS, + g_param_spec_boolean ( + "allow-scripts", + "Allow Scripts", + NULL, + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_PREFER_HTML, + g_param_spec_boolean ( + "prefer-html", + "Prefer HTML", + NULL, + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_SIGNATURE_LIST, + g_param_spec_object ( + "signature-list", + "Signature List", + NULL, + E_TYPE_SIGNATURE_LIST, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + signals[ADD_SIGNATURE] = g_signal_new ( + "add-signature", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (ESignatureManagerClass, add_signature), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[ADD_SIGNATURE_SCRIPT] = g_signal_new ( + "add-signature-script", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (ESignatureManagerClass, add_signature_script), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[EDITOR_CREATED] = g_signal_new ( + "editor-created", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ESignatureManagerClass, editor_created), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + E_TYPE_SIGNATURE_EDITOR); + + signals[EDIT_SIGNATURE] = g_signal_new ( + "edit-signature", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (ESignatureManagerClass, edit_signature), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[REMOVE_SIGNATURE] = g_signal_new ( + "remove-signature", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (ESignatureManagerClass, remove_signature), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +signature_manager_init (ESignatureManager *manager) +{ + GtkTreeSelection *selection; + GtkWidget *container; + GtkWidget *widget; + + manager->priv = E_SIGNATURE_MANAGER_GET_PRIVATE (manager); + + gtk_table_resize (GTK_TABLE (manager), 1, 2); + gtk_table_set_col_spacings (GTK_TABLE (manager), 6); + gtk_table_set_row_spacings (GTK_TABLE (manager), 12); + + container = GTK_WIDGET (manager); + + 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_table_attach ( + GTK_TABLE (container), widget, 0, 1, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (widget); + + container = widget; + + widget = e_signature_tree_view_new (); + gtk_container_add (GTK_CONTAINER (container), widget); + manager->priv->tree_view = g_object_ref (widget); + gtk_widget_show (widget); + + e_mutual_binding_new ( + G_OBJECT (manager), "signature-list", + G_OBJECT (widget), "signature-list"); + + g_signal_connect_swapped ( + widget, "key-press-event", + G_CALLBACK (signature_manager_key_press_event_cb), + manager); + + g_signal_connect_swapped ( + widget, "row-activated", + G_CALLBACK (e_signature_manager_edit_signature), + manager); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + + g_signal_connect_swapped ( + selection, "changed", + G_CALLBACK (signature_manager_selection_changed_cb), + manager); + + container = GTK_WIDGET (manager); + + widget = gtk_vbutton_box_new (); + gtk_button_box_set_layout ( + GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_START); + gtk_box_set_spacing (GTK_BOX (widget), 6); + gtk_table_attach ( + GTK_TABLE (container), widget, + 1, 2, 0, 2, 0, GTK_FILL, 0, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_button_new_from_stock (GTK_STOCK_ADD); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + manager->priv->add_button = g_object_ref (widget); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (e_signature_manager_add_signature), + manager); + + widget = gtk_button_new_with_mnemonic (_("Add _Script")); + gtk_button_set_image ( + GTK_BUTTON (widget), gtk_image_new_from_stock ( + GTK_STOCK_EXECUTE, GTK_ICON_SIZE_BUTTON)); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + manager->priv->add_script_button = g_object_ref (widget); + gtk_widget_show (widget); + + e_binding_new ( + G_OBJECT (manager), "allow-scripts", + G_OBJECT (widget), "sensitive"); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (e_signature_manager_add_signature_script), + manager); + + widget = gtk_button_new_from_stock (GTK_STOCK_EDIT); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + manager->priv->edit_button = g_object_ref (widget); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (e_signature_manager_edit_signature), + manager); + + widget = gtk_button_new_from_stock (GTK_STOCK_REMOVE); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + manager->priv->remove_button = g_object_ref (widget); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (e_signature_manager_remove_signature), + manager); +} + +GType +e_signature_manager_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (ESignatureManagerClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) signature_manager_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_init */ + sizeof (ESignatureManager), + 0, /* n_preallocs */ + (GInstanceInitFunc) signature_manager_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_TABLE, "ESignatureManager", &type_info, 0); + } + + return type; +} + +GtkWidget * +e_signature_manager_new (ESignatureList *signature_list) +{ + g_return_val_if_fail (E_IS_SIGNATURE_LIST (signature_list), NULL); + + return g_object_new ( + E_TYPE_SIGNATURE_MANAGER, + "signature-list", signature_list, NULL); +} + +void +e_signature_manager_add_signature (ESignatureManager *manager) +{ + g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager)); + + g_signal_emit (manager, signals[ADD_SIGNATURE], 0); +} + +void +e_signature_manager_add_signature_script (ESignatureManager *manager) +{ + g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager)); + + g_signal_emit (manager, signals[ADD_SIGNATURE_SCRIPT], 0); +} + +void +e_signature_manager_edit_signature (ESignatureManager *manager) +{ + g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager)); + + g_signal_emit (manager, signals[EDIT_SIGNATURE], 0); +} + +void +e_signature_manager_remove_signature (ESignatureManager *manager) +{ + g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager)); + + g_signal_emit (manager, signals[REMOVE_SIGNATURE], 0); +} + +gboolean +e_signature_manager_get_allow_scripts (ESignatureManager *manager) +{ + g_return_val_if_fail (E_IS_SIGNATURE_MANAGER (manager), FALSE); + + return manager->priv->allow_scripts; +} + +void +e_signature_manager_set_allow_scripts (ESignatureManager *manager, + gboolean allow_scripts) +{ + g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager)); + + manager->priv->allow_scripts = allow_scripts; + + g_object_notify (G_OBJECT (manager), "allow-scripts"); +} + +gboolean +e_signature_manager_get_prefer_html (ESignatureManager *manager) +{ + g_return_val_if_fail (E_IS_SIGNATURE_MANAGER (manager), FALSE); + + return manager->priv->prefer_html; +} + +void +e_signature_manager_set_prefer_html (ESignatureManager *manager, + gboolean prefer_html) +{ + g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager)); + + manager->priv->prefer_html = prefer_html; + + g_object_notify (G_OBJECT (manager), "prefer-html"); +} + +ESignatureList * +e_signature_manager_get_signature_list (ESignatureManager *manager) +{ + g_return_val_if_fail (E_IS_SIGNATURE_MANAGER (manager), NULL); + + return manager->priv->signature_list; +} + +void +e_signature_manager_set_signature_list (ESignatureManager *manager, + ESignatureList *signature_list) +{ + g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager)); + + if (signature_list != NULL) { + g_return_if_fail (E_IS_SIGNATURE_LIST (signature_list)); + g_object_ref (signature_list); + } + + if (manager->priv->signature_list != NULL) + g_object_unref (manager->priv->signature_list); + + manager->priv->signature_list = signature_list; + + g_object_notify (G_OBJECT (manager), "signature-list"); +} + +ESignatureTreeView * +e_signature_manager_get_tree_view (ESignatureManager *manager) +{ + g_return_val_if_fail (E_IS_SIGNATURE_MANAGER (manager), NULL); + + return E_SIGNATURE_TREE_VIEW (manager->priv->tree_view); +} diff --git a/widgets/misc/e-signature-manager.h b/widgets/misc/e-signature-manager.h new file mode 100644 index 0000000000..662836e4ef --- /dev/null +++ b/widgets/misc/e-signature-manager.h @@ -0,0 +1,100 @@ +/* + * e-signature-manager.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_SIGNATURE_MANAGER_H +#define E_SIGNATURE_MANAGER_H + +#include <gtk/gtk.h> +#include <e-util/e-signature-list.h> +#include <misc/e-signature-editor.h> +#include <misc/e-signature-tree-view.h> + +/* Standard GObject macros */ +#define E_TYPE_SIGNATURE_MANAGER \ + (e_signature_manager_get_type ()) +#define E_SIGNATURE_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_SIGNATURE_MANAGER, ESignatureManager)) +#define E_SIGNATURE_MANAGER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_SIGNATURE_MANAGER, ESignatureManagerClass)) +#define E_IS_SIGNATURE_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_SIGNATURE_MANAGER)) +#define E_IS_SIGNATURE_MANAGER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_SIGNATURE_MANAGER)) +#define E_SIGNATURE_MANAGER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_SIGNATURE_MANAGER, ESignatureManagerClass)) + +G_BEGIN_DECLS + +typedef struct _ESignatureManager ESignatureManager; +typedef struct _ESignatureManagerClass ESignatureManagerClass; +typedef struct _ESignatureManagerPrivate ESignatureManagerPrivate; + +struct _ESignatureManager { + GtkTable parent; + ESignatureManagerPrivate *priv; +}; + +struct _ESignatureManagerClass { + GtkTableClass parent_class; + + void (*add_signature) (ESignatureManager *manager); + void (*add_signature_script) (ESignatureManager *manager); + void (*editor_created) (ESignatureManager *manager, + ESignatureEditor *editor); + void (*edit_signature) (ESignatureManager *manager); + void (*remove_signature) (ESignatureManager *manager); +}; + +GType e_signature_manager_get_type (void); +GtkWidget * e_signature_manager_new (ESignatureList *signature_list); +void e_signature_manager_add_signature + (ESignatureManager *manager); +void e_signature_manager_add_signature_script + (ESignatureManager *manager); +void e_signature_manager_edit_signature + (ESignatureManager *manager); +void e_signature_manager_remove_signature + (ESignatureManager *manager); +gboolean e_signature_manager_get_allow_scripts + (ESignatureManager *manager); +void e_signature_manager_set_allow_scripts + (ESignatureManager *manager, + gboolean allow_scripts); +gboolean e_signature_manager_get_prefer_html + (ESignatureManager *manager); +void e_signature_manager_set_prefer_html + (ESignatureManager *manager, + gboolean prefer_html); +ESignatureList *e_signature_manager_get_signature_list + (ESignatureManager *manager); +void e_signature_manager_set_signature_list + (ESignatureManager *manager, + ESignatureList *signature_list); +ESignatureTreeView * + e_signature_manager_get_tree_view + (ESignatureManager *manager); + +#endif /* E_SIGNATURE_MANAGER_H */ diff --git a/widgets/misc/e-signature-preview.c b/widgets/misc/e-signature-preview.c new file mode 100644 index 0000000000..f8e168cd5a --- /dev/null +++ b/widgets/misc/e-signature-preview.c @@ -0,0 +1,344 @@ +/* + * e-signature-preview.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-signature-preview.h" + +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <glib/gstdio.h> +#include "e-util/e-signature-utils.h" + +#define E_SIGNATURE_PREVIEW_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreviewPrivate)) + +enum { + PROP_0, + PROP_ALLOW_SCRIPTS, + PROP_SIGNATURE +}; + +enum { + REFRESH, + LAST_SIGNAL +}; + +struct _ESignaturePreviewPrivate { + ESignature *signature; + guint allow_scripts : 1; +}; + +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; + +static void +signature_preview_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ALLOW_SCRIPTS: + e_signature_preview_set_allow_scripts ( + E_SIGNATURE_PREVIEW (object), + g_value_get_boolean (value)); + return; + + case PROP_SIGNATURE: + e_signature_preview_set_signature ( + E_SIGNATURE_PREVIEW (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +signature_preview_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ALLOW_SCRIPTS: + g_value_set_boolean ( + value, e_signature_preview_get_allow_scripts ( + E_SIGNATURE_PREVIEW (object))); + return; + + case PROP_SIGNATURE: + g_value_set_object ( + value, e_signature_preview_get_signature ( + E_SIGNATURE_PREVIEW (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +signature_preview_dispose (GObject *object) +{ + ESignaturePreviewPrivate *priv; + + priv = E_SIGNATURE_PREVIEW_GET_PRIVATE (object); + + if (priv->signature != NULL) { + g_object_unref (priv->signature); + priv->signature = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +signature_preview_url_requested (GtkHTML *html, + const gchar *url, + GtkHTMLStream *handle) +{ + GtkHTMLStreamStatus status; + gchar buffer[128]; + gchar *filename; + gssize size; + gint fd; + + /* FIXME Use GInputStream for this. */ + + if (g_str_has_prefix (url, "file:")) + filename = g_filename_from_uri (url, NULL, NULL); + else + filename = g_strdup (url); + fd = g_open (filename, O_RDONLY, 0); + g_free (filename); + + status = GTK_HTML_STREAM_OK; + if (fd != -1) { + while ((size = read (fd, buffer, sizeof (buffer)))) { + if (size == -1) { + status = GTK_HTML_STREAM_ERROR; + break; + } else + gtk_html_write (html, handle, buffer, size); + } + } else + status = GTK_HTML_STREAM_ERROR; + + gtk_html_end (html, handle, status); + + if (fd > 0) + close (fd); +} + +static void +signature_preview_refresh (ESignaturePreview *preview) +{ + GtkHTML *html; + ESignature *signature; + gchar *content = NULL; + gsize length; + + /* XXX We should show error messages in the preview. */ + + html = GTK_HTML (preview); + signature = e_signature_preview_get_signature (preview); + + if (signature == NULL) + goto clear; + + if (signature->script && !preview->priv->allow_scripts) + goto clear; + + if (signature->script) + content = e_run_signature_script (signature->filename); + else + content = e_read_signature_file (signature, FALSE, NULL); + + if (content == NULL || *content == '\0') + goto clear; + + length = strlen (content); + + if (signature->html) + gtk_html_load_from_string (html, content, length); + else { + GtkHTMLStream *stream; + + stream = gtk_html_begin_content ( + html, "text/html; charset=utf-8"); + gtk_html_write (html, stream, "<PRE>", 5); + if (length > 0) + gtk_html_write (html, stream, content, length); + gtk_html_write (html, stream, "</PRE>", 6); + gtk_html_end (html, stream, GTK_HTML_STREAM_OK); + } + + g_free (content); + return; + +clear: + gtk_html_load_from_string (html, " ", 1); + g_free (content); +} + +static void +signature_preview_class_init (ESignaturePreviewClass *class) +{ + GObjectClass *object_class; + GtkHTMLClass *html_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (ESignaturePreviewPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = signature_preview_set_property; + object_class->get_property = signature_preview_get_property; + object_class->dispose = signature_preview_dispose; + + html_class = GTK_HTML_CLASS (class); + html_class->url_requested = signature_preview_url_requested; + + class->refresh = signature_preview_refresh; + + g_object_class_install_property ( + object_class, + PROP_ALLOW_SCRIPTS, + g_param_spec_boolean ( + "allow-scripts", + "Allow Scripts", + NULL, + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_SIGNATURE, + g_param_spec_object ( + "signature", + "Signature", + NULL, + E_TYPE_SIGNATURE, + G_PARAM_READWRITE)); + + signals[REFRESH] = g_signal_new ( + "refresh", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (ESignaturePreviewClass, refresh), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +signature_preview_init (ESignaturePreview *preview) +{ + preview->priv = E_SIGNATURE_PREVIEW_GET_PRIVATE (preview); +} + +GType +e_signature_preview_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (ESignaturePreviewClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) signature_preview_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (ESignaturePreview), + 0, /* n_preallocs */ + (GInstanceInitFunc) signature_preview_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_HTML, "ESignaturePreview", &type_info, 0); + } + + return type; +} + +GtkWidget * +e_signature_preview_new (void) +{ + return g_object_new (E_TYPE_SIGNATURE_PREVIEW, NULL); +} + +void +e_signature_preview_refresh (ESignaturePreview *preview) +{ + g_return_if_fail (E_IS_SIGNATURE_PREVIEW (preview)); + + g_signal_emit (preview, signals[REFRESH], 0); +} + +gboolean +e_signature_preview_get_allow_scripts (ESignaturePreview *preview) +{ + g_return_val_if_fail (E_IS_SIGNATURE_PREVIEW (preview), FALSE); + + return preview->priv->allow_scripts; +} + +void +e_signature_preview_set_allow_scripts (ESignaturePreview *preview, + gboolean allow_scripts) +{ + g_return_if_fail (E_IS_SIGNATURE_PREVIEW (preview)); + + preview->priv->allow_scripts = allow_scripts; + g_object_notify (G_OBJECT (preview), "allow-scripts"); +} + +ESignature * +e_signature_preview_get_signature (ESignaturePreview *preview) +{ + g_return_val_if_fail (E_IS_SIGNATURE_PREVIEW (preview), NULL); + + return preview->priv->signature; +} + +void +e_signature_preview_set_signature (ESignaturePreview *preview, + ESignature *signature) +{ + g_return_if_fail (E_IS_SIGNATURE_PREVIEW (preview)); + + if (signature != NULL) { + g_return_if_fail (E_IS_SIGNATURE (signature)); + g_object_ref (signature); + } + + if (preview->priv->signature != NULL) + g_object_unref (preview->priv->signature); + + preview->priv->signature = signature; + g_object_notify (G_OBJECT (preview), "signature"); + + e_signature_preview_refresh (preview); +} diff --git a/widgets/misc/e-signature-preview.h b/widgets/misc/e-signature-preview.h new file mode 100644 index 0000000000..a4221832c2 --- /dev/null +++ b/widgets/misc/e-signature-preview.h @@ -0,0 +1,81 @@ +/* + * e-signature-preview.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_SIGNATURE_PREVIEW_H +#define E_SIGNATURE_PREVIEW_H + +#include <gtkhtml/gtkhtml.h> +#include <e-util/e-signature.h> + +/* Standard GObject macros */ +#define E_TYPE_SIGNATURE_PREVIEW \ + (e_signature_preview_get_type ()) +#define E_SIGNATURE_PREVIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreview)) +#define E_SIGNATURE_PREVIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreviewClass)) +#define E_IS_SIGNATURE_PREVIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_SIGNATURE_PREVIEW)) +#define E_IS_SIGNATURE_PREVIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_SIGNATURE_PREVIEW)) +#define E_SIGNATURE_PREVIEW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreview)) + +G_BEGIN_DECLS + +typedef struct _ESignaturePreview ESignaturePreview; +typedef struct _ESignaturePreviewClass ESignaturePreviewClass; +typedef struct _ESignaturePreviewPrivate ESignaturePreviewPrivate; + +struct _ESignaturePreview { + GtkHTML parent; + ESignaturePreviewPrivate *priv; +}; + +struct _ESignaturePreviewClass { + GtkHTMLClass parent_class; + + /* Signals */ + void (*refresh) (ESignaturePreview *preview); +}; + +GType e_signature_preview_get_type (void); +GtkWidget * e_signature_preview_new (void); +void e_signature_preview_refresh (ESignaturePreview *preview); +gboolean e_signature_preview_get_allow_scripts + (ESignaturePreview *preview); +void e_signature_preview_set_allow_scripts + (ESignaturePreview *preview, + gboolean allow_scripts); +ESignature * e_signature_preview_get_signature + (ESignaturePreview *preview); +void e_signature_preview_set_signature + (ESignaturePreview *preview, + ESignature *signature); + +G_END_DECLS + +#endif /* E_SIGNATURE_PREVIEW_H */ diff --git a/widgets/misc/e-signature-script-dialog.c b/widgets/misc/e-signature-script-dialog.c new file mode 100644 index 0000000000..777d064f09 --- /dev/null +++ b/widgets/misc/e-signature-script-dialog.c @@ -0,0 +1,463 @@ +/* + * e-signature-script-dialog.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-signature-script-dialog.h" + +#include <glib/gi18n.h> +#include "e-util/e-binding.h" + +#define E_SIGNATURE_SCRIPT_DIALOG_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_SIGNATURE_SCRIPT_DIALOG, ESignatureScriptDialogPrivate)) + +struct _ESignatureScriptDialogPrivate { + GtkWidget *entry; + GtkWidget *file_chooser; + GtkWidget *alert; +}; + +enum { + PROP_0, + PROP_SCRIPT_FILE, + PROP_SCRIPT_NAME +}; + +static gpointer parent_class; + +static gboolean +signature_script_dialog_filter_cb (const GtkFileFilterInfo *filter_info) +{ + const gchar *filename = filter_info->filename; + + return g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE); +} + +static void +signature_script_dialog_update_status (ESignatureScriptDialog *dialog) +{ + GFile *script_file; + const gchar *script_name; + gboolean show_alert; + gboolean sensitive; + + script_file = e_signature_script_dialog_get_script_file (dialog); + script_name = e_signature_script_dialog_get_script_name (dialog); + + sensitive = (script_name != NULL && *script_name != '\0'); + + if (script_file != NULL) { + gboolean executable; + gchar *filename; + + filename = g_file_get_path (script_file); + executable = g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE); + g_free (filename); + + show_alert = !executable; + sensitive &= executable; + + g_object_unref (script_file); + } else { + sensitive = FALSE; + show_alert = FALSE; + } + + if (show_alert) + gtk_widget_show (dialog->priv->alert); + else + gtk_widget_hide (dialog->priv->alert); + + gtk_dialog_set_response_sensitive ( + GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive); +} + +static void +signature_script_dialog_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SCRIPT_FILE: + e_signature_script_dialog_set_script_file ( + E_SIGNATURE_SCRIPT_DIALOG (object), + g_value_get_object (value)); + return; + + case PROP_SCRIPT_NAME: + e_signature_script_dialog_set_script_name ( + E_SIGNATURE_SCRIPT_DIALOG (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +signature_script_dialog_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SCRIPT_FILE: + g_value_set_object ( + value, + e_signature_script_dialog_get_script_file ( + E_SIGNATURE_SCRIPT_DIALOG (object))); + return; + + case PROP_SCRIPT_NAME: + g_value_set_string ( + value, + e_signature_script_dialog_get_script_name ( + E_SIGNATURE_SCRIPT_DIALOG (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +signature_script_dialog_dispose (GObject *object) +{ + ESignatureScriptDialogPrivate *priv; + + priv = E_SIGNATURE_SCRIPT_DIALOG_GET_PRIVATE (object); + + if (priv->entry != NULL) { + g_object_unref (priv->entry); + priv->entry = NULL; + } + + if (priv->file_chooser != NULL) { + g_object_unref (priv->file_chooser); + priv->file_chooser = NULL; + } + + if (priv->alert != NULL) { + g_object_unref (priv->alert); + priv->alert = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +signature_script_dialog_map (GtkWidget *widget) +{ + GtkWidget *action_area; + GtkWidget *content_area; + + /* Chain up to parent's map() method. */ + GTK_WIDGET_CLASS (parent_class)->map (widget); + + /* XXX Override GtkDialog's broken style property defaults. */ + action_area = gtk_dialog_get_action_area (GTK_DIALOG (widget)); + content_area = gtk_dialog_get_content_area (GTK_DIALOG (widget)); + + gtk_box_set_spacing (GTK_BOX (content_area), 12); + gtk_container_set_border_width (GTK_CONTAINER (action_area), 0); + gtk_container_set_border_width (GTK_CONTAINER (content_area), 12); +} + +static void +signature_script_dialog_class_init (ESignatureScriptDialogClass *class) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (ESignatureScriptDialogPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = signature_script_dialog_set_property; + object_class->get_property = signature_script_dialog_get_property; + object_class->dispose = signature_script_dialog_dispose; + + widget_class = GTK_WIDGET_CLASS (class); + widget_class->map = signature_script_dialog_map; + + g_object_class_install_property ( + object_class, + PROP_SCRIPT_FILE, + g_param_spec_object ( + "script-file", + "Script File", + NULL, + G_TYPE_FILE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_SCRIPT_NAME, + g_param_spec_string ( + "script-name", + "Script Name", + NULL, + _("Unnamed"), + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +signature_script_dialog_init (ESignatureScriptDialog *dialog) +{ + GtkFileFilter *filter; + GtkWidget *content_area; + GtkWidget *container; + GtkWidget *widget; + gchar *markup; + + dialog->priv = E_SIGNATURE_SCRIPT_DIALOG_GET_PRIVATE (dialog); + + content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); + + gtk_dialog_add_button ( + GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + + gtk_dialog_add_button ( + GTK_DIALOG (dialog), + GTK_STOCK_SAVE, GTK_RESPONSE_OK); + + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); + + container = content_area; + + widget = gtk_table_new (4, 2, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (widget), 6); + gtk_table_set_row_spacings (GTK_TABLE (widget), 6); + gtk_table_set_row_spacing (GTK_TABLE (widget), 0, 12); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_image_new_from_stock ( + GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG); + gtk_table_attach ( + GTK_TABLE (container), widget, + 0, 1, 0, 1, 0, 0, 0, 0); + gtk_widget_show (widget); + + widget = gtk_label_new (_( + "The output of this script will be used as your\n" + "signature. The name you specify will be used\n" + "for display purposes only.")); + gtk_table_attach ( + GTK_TABLE (container), widget, + 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0); + gtk_widget_show (widget); + + widget = gtk_entry_new (); + gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE); + gtk_table_attach ( + GTK_TABLE (container), widget, + 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0); + dialog->priv->entry = g_object_ref (widget); + gtk_widget_show (widget); + + widget = gtk_label_new_with_mnemonic (_("_Name:")); + gtk_label_set_mnemonic_widget ( + GTK_LABEL (widget), dialog->priv->entry); + gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5); + gtk_table_attach ( + GTK_TABLE (container), widget, + 0, 1, 1, 2, GTK_FILL, 0, 0, 0); + gtk_widget_show (widget); + + widget = gtk_file_chooser_button_new ( + NULL, GTK_FILE_CHOOSER_ACTION_OPEN); + gtk_table_attach ( + GTK_TABLE (container), widget, + 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 0); + dialog->priv->file_chooser = g_object_ref (widget); + gtk_widget_show (widget); + + /* Restrict file selection to executable files. */ + filter = gtk_file_filter_new (); + gtk_file_filter_add_custom ( + filter, GTK_FILE_FILTER_FILENAME, + (GtkFileFilterFunc) signature_script_dialog_filter_cb, + NULL, NULL); + gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (widget), filter); + + /* XXX ESignature stores a filename instead of a URI, + * so we have to restrict it to local files only. */ + gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (widget), TRUE); + + widget = gtk_label_new_with_mnemonic (_("S_cript:")); + gtk_label_set_mnemonic_widget ( + GTK_LABEL (widget), dialog->priv->file_chooser); + gtk_table_attach ( + GTK_TABLE (container), widget, + 0, 1, 2, 3, GTK_FILL, 0, 0, 0); + gtk_widget_show (widget); + + /* This is just a placeholder. */ + widget = gtk_label_new (NULL); + gtk_table_attach ( + GTK_TABLE (container), widget, + 0, 1, 3, 4, GTK_FILL, 0, 0, 0); + gtk_widget_show (widget); + + widget = gtk_hbox_new (FALSE, 6); + gtk_table_attach ( + GTK_TABLE (container), widget, + 1, 2, 3, 4, 0, 0, 0, 0); + dialog->priv->alert = g_object_ref (widget); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_image_new_from_stock ( + GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + markup = g_markup_printf_escaped ( + "<small>%s</small>", + _("Script file must be executable.")); + widget = gtk_label_new (markup); + gtk_label_set_use_markup (GTK_LABEL (widget), TRUE); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + gtk_widget_show (widget); + g_free (markup); + + g_signal_connect ( + dialog, "notify::script-file", + G_CALLBACK (signature_script_dialog_update_status), NULL); + + g_signal_connect ( + dialog, "notify::script-name", + G_CALLBACK (signature_script_dialog_update_status), NULL); + + g_signal_connect_swapped ( + dialog->priv->entry, "changed", + G_CALLBACK (signature_script_dialog_update_status), dialog); + + g_signal_connect_swapped ( + dialog->priv->file_chooser, "file-set", + G_CALLBACK (signature_script_dialog_update_status), dialog); + + signature_script_dialog_update_status (dialog); +} + +GType +e_signature_script_dialog_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (ESignatureScriptDialogClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) signature_script_dialog_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (ESignatureScriptDialog), + 0, /* n_preallocs */ + (GInstanceInitFunc) signature_script_dialog_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_DIALOG, "ESignatureScriptDialog", + &type_info, 0); + } + + return type; +} + +GtkWidget * +e_signature_script_dialog_new (GtkWindow *parent) +{ + return g_object_new ( + E_TYPE_SIGNATURE_SCRIPT_DIALOG, + "transient-for", parent, NULL); +} + +GFile * +e_signature_script_dialog_get_script_file (ESignatureScriptDialog *dialog) +{ + GtkFileChooser *file_chooser; + + g_return_val_if_fail (E_IS_SIGNATURE_SCRIPT_DIALOG (dialog), NULL); + + file_chooser = GTK_FILE_CHOOSER (dialog->priv->file_chooser); + + return gtk_file_chooser_get_file (file_chooser); +} + +void +e_signature_script_dialog_set_script_file (ESignatureScriptDialog *dialog, + GFile *script_file) +{ + GtkFileChooser *file_chooser; + GError *error = NULL; + + g_return_if_fail (E_IS_SIGNATURE_SCRIPT_DIALOG (dialog)); + g_return_if_fail (G_IS_FILE (script_file)); + + file_chooser = GTK_FILE_CHOOSER (dialog->priv->file_chooser); + + if (gtk_file_chooser_set_file (file_chooser, script_file, &error)) + g_object_notify (G_OBJECT (dialog), "script-file"); + else { + g_warning ("%s", error->message); + g_error_free (error); + } +} + +const gchar * +e_signature_script_dialog_get_script_name (ESignatureScriptDialog *dialog) +{ + GtkEntry *entry; + + g_return_val_if_fail (E_IS_SIGNATURE_SCRIPT_DIALOG (dialog), NULL); + + entry = GTK_ENTRY (dialog->priv->entry); + + return gtk_entry_get_text (entry); +} + +void +e_signature_script_dialog_set_script_name (ESignatureScriptDialog *dialog, + const gchar *script_name) +{ + GtkEntry *entry; + + g_return_if_fail (E_IS_SIGNATURE_SCRIPT_DIALOG (dialog)); + + if (script_name == NULL) + script_name = ""; + + entry = GTK_ENTRY (dialog->priv->entry); + gtk_entry_set_text (entry, script_name); + + g_object_notify (G_OBJECT (dialog), "script-name"); +} diff --git a/widgets/misc/e-signature-script-dialog.h b/widgets/misc/e-signature-script-dialog.h new file mode 100644 index 0000000000..3967ae60c3 --- /dev/null +++ b/widgets/misc/e-signature-script-dialog.h @@ -0,0 +1,76 @@ +/* + * e-signature-script-dialog.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_SIGNATURE_SCRIPT_DIALOG_H +#define E_SIGNATURE_SCRIPT_DIALOG_H + +#include <gtk/gtk.h> + +/* Standard GObject macros */ +#define E_TYPE_SIGNATURE_SCRIPT_DIALOG \ + (e_signature_script_dialog_get_type ()) +#define E_SIGNATURE_SCRIPT_DIALOG(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_SIGNATURE_SCRIPT_DIALOG, ESignatureScriptDialog)) +#define E_SIGNATURE_SCRIPT_DIALOG_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_SIGNATURE_SCRIPT_DIALOG, ESignatureScriptDialogClass)) +#define E_IS_SIGNATURE_SCRIPT_DIALOG(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_SIGNATURE_SCRIPT_DIALOG)) +#define E_IS_SIGNATURE_SCRIPT_DIALOG_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_SIGNATURE_SCRIPT_DIALOG)) +#define E_SIGNATURE_SCRIPT_DIALOG_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_SIGNATURE_SCRIPT_DIALOG, ESignatureScriptDialogClass)) + +G_BEGIN_DECLS + +typedef struct _ESignatureScriptDialog ESignatureScriptDialog; +typedef struct _ESignatureScriptDialogClass ESignatureScriptDialogClass; +typedef struct _ESignatureScriptDialogPrivate ESignatureScriptDialogPrivate; + +struct _ESignatureScriptDialog { + GtkDialog parent; + ESignatureScriptDialogPrivate *priv; +}; + +struct _ESignatureScriptDialogClass { + GtkDialogClass parent_class; +}; + +GType e_signature_script_dialog_get_type (void); +GtkWidget * e_signature_script_dialog_new (GtkWindow *parent); +GFile * e_signature_script_dialog_get_script_file + (ESignatureScriptDialog *dialog); +void e_signature_script_dialog_set_script_file + (ESignatureScriptDialog *dialog, + GFile *script_file); +const gchar * e_signature_script_dialog_get_script_name + (ESignatureScriptDialog *dialog); +void e_signature_script_dialog_set_script_name + (ESignatureScriptDialog *dialog, + const gchar *script_name); + +G_END_DECLS + +#endif /* E_SIGNATURE_SCRIPT_DIALOG_H */ diff --git a/widgets/misc/e-signature-tree-view.c b/widgets/misc/e-signature-tree-view.c new file mode 100644 index 0000000000..b2cc9d6f66 --- /dev/null +++ b/widgets/misc/e-signature-tree-view.c @@ -0,0 +1,445 @@ +/* + * e-signature-tree-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-signature-tree-view.h" + +#define E_SIGNATURE_TREE_VIEW_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_SIGNATURE_TREE_VIEW, ESignatureTreeViewPrivate)) + +enum { + COLUMN_STRING, + COLUMN_SIGNATURE +}; + +enum { + PROP_0, + PROP_SELECTED, + PROP_SIGNATURE_LIST +}; + +enum { + REFRESHED, + LAST_SIGNAL +}; + +struct _ESignatureTreeViewPrivate { + ESignatureList *signature_list; + GHashTable *index; +}; + +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; + +static void +signature_tree_view_refresh_cb (ESignatureList *signature_list, + ESignature *unused, + ESignatureTreeView *tree_view) +{ + GtkListStore *store; + GtkTreeModel *model; + GtkTreeIter tree_iter; + EIterator *signature_iter; + ESignature *signature; + GHashTable *index; + GList *list = NULL; + GList *iter; + + store = gtk_list_store_new (2, G_TYPE_STRING, E_TYPE_SIGNATURE); + model = GTK_TREE_MODEL (store); + index = tree_view->priv->index; + + g_hash_table_remove_all (index); + + if (signature_list == NULL) + goto skip; + + /* Build a list of ESignatures to display. */ + signature_iter = e_list_get_iterator (E_LIST (signature_list)); + while (e_iterator_is_valid (signature_iter)) { + + /* XXX EIterator misuses const. */ + signature = (ESignature *) e_iterator_get (signature_iter); + list = g_list_prepend (list, signature); + e_iterator_next (signature_iter); + } + g_object_unref (signature_iter); + + list = g_list_reverse (list); + + /* Populate the list store and index. */ + for (iter = list; iter != NULL; iter = iter->next) { + GtkTreeRowReference *reference; + GtkTreePath *path; + + signature = iter->data; + + /* Skip autogenerated signatures. */ + if (signature->autogen) + continue; + + gtk_list_store_append (store, &tree_iter); + gtk_list_store_set ( + store, &tree_iter, + COLUMN_STRING, signature->name, + COLUMN_SIGNATURE, signature, -1); + + path = gtk_tree_model_get_path (model, &tree_iter); + reference = gtk_tree_row_reference_new (model, path); + g_hash_table_insert (index, signature, reference); + gtk_tree_path_free (path); + } + +skip: + /* Restore the previously selected signature. */ + signature = e_signature_tree_view_get_selected (tree_view); + if (signature != NULL) + g_object_ref (signature); + gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model); + e_signature_tree_view_set_selected (tree_view, signature); + if (signature != NULL) + g_object_unref (signature); + + g_signal_emit (tree_view, signals[REFRESHED], 0); +} + +static void +signature_tree_view_selection_changed_cb (ESignatureTreeView *tree_view) +{ + g_object_notify (G_OBJECT (tree_view), "selected"); +} + +static GObject * +signature_tree_view_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *object; + GtkTreeView *tree_view; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + + /* Chain up to parent's constructor() method. */ + object = G_OBJECT_CLASS (parent_class)->constructor ( + type, n_construct_properties, construct_properties); + + tree_view = GTK_TREE_VIEW (object); + gtk_tree_view_set_headers_visible (tree_view, FALSE); + + column = gtk_tree_view_column_new (); + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute ( + column, renderer, "text", COLUMN_STRING); + gtk_tree_view_append_column (tree_view, column); + + return object; +} + +static void +signature_tree_view_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SELECTED: + e_signature_tree_view_set_selected ( + E_SIGNATURE_TREE_VIEW (object), + g_value_get_object (value)); + return; + + case PROP_SIGNATURE_LIST: + e_signature_tree_view_set_signature_list ( + E_SIGNATURE_TREE_VIEW (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +signature_tree_view_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SELECTED: + g_value_set_object ( + value, + e_signature_tree_view_get_selected ( + E_SIGNATURE_TREE_VIEW (object))); + return; + + case PROP_SIGNATURE_LIST: + g_value_set_object ( + value, + e_signature_tree_view_get_signature_list ( + E_SIGNATURE_TREE_VIEW (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +signature_tree_view_dispose (GObject *object) +{ + ESignatureTreeViewPrivate *priv; + + priv = E_SIGNATURE_TREE_VIEW_GET_PRIVATE (object); + + if (priv->signature_list != NULL) { + g_signal_handlers_disconnect_by_func ( + priv->signature_list, + signature_tree_view_refresh_cb, object); + g_object_unref (priv->signature_list); + priv->signature_list = NULL; + } + + g_hash_table_remove_all (priv->index); + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +signature_tree_view_finalize (GObject *object) +{ + ESignatureTreeViewPrivate *priv; + + priv = E_SIGNATURE_TREE_VIEW_GET_PRIVATE (object); + + g_hash_table_destroy (priv->index); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +signature_tree_view_class_init (ESignatureTreeViewClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (ESignatureTreeViewPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->constructor = signature_tree_view_constructor; + object_class->set_property = signature_tree_view_set_property; + object_class->get_property = signature_tree_view_get_property; + object_class->dispose = signature_tree_view_dispose; + object_class->finalize = signature_tree_view_finalize; + + g_object_class_install_property ( + object_class, + PROP_SELECTED, + g_param_spec_object ( + "selected", + "Selected Signature", + NULL, + E_TYPE_SIGNATURE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_SIGNATURE_LIST, + g_param_spec_object ( + "signature-list", + "Signature List", + NULL, + E_TYPE_SIGNATURE_LIST, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + signals[REFRESHED] = g_signal_new ( + "refreshed", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +signature_tree_view_init (ESignatureTreeView *tree_view) +{ + GHashTable *index; + GtkTreeSelection *selection; + + /* Reverse-lookup index */ + index = g_hash_table_new_full ( + g_direct_hash, g_direct_equal, + (GDestroyNotify) g_object_unref, + (GDestroyNotify) gtk_tree_row_reference_free); + + tree_view->priv = E_SIGNATURE_TREE_VIEW_GET_PRIVATE (tree_view); + tree_view->priv->index = index; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); + + g_signal_connect_swapped ( + selection, "changed", + G_CALLBACK (signature_tree_view_selection_changed_cb), + tree_view); +} + +GType +e_signature_tree_view_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (ESignatureTreeViewClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) signature_tree_view_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (ESignatureTreeView), + 0, /* n_preallocs */ + (GInstanceInitFunc) signature_tree_view_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_TREE_VIEW, "ESignatureTreeView", + &type_info, 0); + } + + return type; +} + +GtkWidget * +e_signature_tree_view_new (void) +{ + return g_object_new (E_TYPE_SIGNATURE_TREE_VIEW, NULL); +} + +ESignatureList * +e_signature_tree_view_get_signature_list (ESignatureTreeView *tree_view) +{ + g_return_val_if_fail (E_IS_SIGNATURE_TREE_VIEW (tree_view), NULL); + + return tree_view->priv->signature_list; +} + +void +e_signature_tree_view_set_signature_list (ESignatureTreeView *tree_view, + ESignatureList *signature_list) +{ + ESignatureTreeViewPrivate *priv; + + g_return_if_fail (E_IS_SIGNATURE_TREE_VIEW (tree_view)); + + if (signature_list != NULL) + g_return_if_fail (E_IS_SIGNATURE_LIST (signature_list)); + + priv = E_SIGNATURE_TREE_VIEW_GET_PRIVATE (tree_view); + + if (priv->signature_list != NULL) { + g_signal_handlers_disconnect_by_func ( + priv->signature_list, + signature_tree_view_refresh_cb, tree_view); + g_object_unref (priv->signature_list); + priv->signature_list = NULL; + } + + if (signature_list != NULL) { + priv->signature_list = g_object_ref (signature_list); + + /* Listen for changes to the signature list. */ + g_signal_connect ( + priv->signature_list, "signature-added", + G_CALLBACK (signature_tree_view_refresh_cb), + tree_view); + g_signal_connect ( + priv->signature_list, "signature-changed", + G_CALLBACK (signature_tree_view_refresh_cb), + tree_view); + g_signal_connect ( + priv->signature_list, "signature-removed", + G_CALLBACK (signature_tree_view_refresh_cb), + tree_view); + } + + signature_tree_view_refresh_cb (signature_list, NULL, tree_view); + + g_object_notify (G_OBJECT (tree_view), "signature-list"); +} + +ESignature * +e_signature_tree_view_get_selected (ESignatureTreeView *tree_view) +{ + ESignature *signature; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + + g_return_val_if_fail (E_IS_SIGNATURE_TREE_VIEW (tree_view), NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return NULL; + + gtk_tree_model_get (model, &iter, COLUMN_SIGNATURE, &signature, -1); + + return signature; +} + +gboolean +e_signature_tree_view_set_selected (ESignatureTreeView *tree_view, + ESignature *signature) +{ + GtkTreeRowReference *reference; + GtkTreeSelection *selection; + GtkTreePath *path; + + g_return_val_if_fail (E_IS_SIGNATURE_TREE_VIEW (tree_view), FALSE); + + if (signature != NULL) + g_return_val_if_fail (E_IS_SIGNATURE (signature), FALSE); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); + + /* NULL means clear the selection. */ + if (signature == NULL) { + gtk_tree_selection_unselect_all (selection); + return TRUE; + } + + /* Lookup the tree row reference for the signature. */ + reference = g_hash_table_lookup (tree_view->priv->index, signature); + if (reference == NULL) + return FALSE; + + /* Select the referenced path. */ + path = gtk_tree_row_reference_get_path (reference); + gtk_tree_selection_select_path (selection, path); + gtk_tree_path_free (path); + + g_object_notify (G_OBJECT (tree_view), "selected"); + + return TRUE; +} diff --git a/widgets/misc/e-signature-tree-view.h b/widgets/misc/e-signature-tree-view.h new file mode 100644 index 0000000000..50d1e11905 --- /dev/null +++ b/widgets/misc/e-signature-tree-view.h @@ -0,0 +1,78 @@ +/* + * e-signature-tree-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_SIGNATURE_TREE_VIEW_H +#define E_SIGNATURE_TREE_VIEW_H + +#include <gtk/gtk.h> +#include <e-util/e-signature.h> +#include <e-util/e-signature-list.h> + +/* Standard GObject macros */ +#define E_TYPE_SIGNATURE_TREE_VIEW \ + (e_signature_tree_view_get_type ()) +#define E_SIGNATURE_TREE_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_SIGNATURE_TREE_VIEW, ESignatureTreeView)) +#define E_SIGNATURE_TREE_VIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_SIGNATURE_TREE_VIEW, ESignatureTreeViewClass)) +#define E_IS_SIGNATURE_TREE_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_SIGNATURE_TREE_VIEW)) +#define E_IS_SIGNATURE_TREE_VIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_SIGNATURE_TREE_VIEW)) +#define E_SIGNATURE_TREE_VIEW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_SIGNATURE_TREE_VIEW, ESignatureTreeViewClass)) + +G_BEGIN_DECLS + +typedef struct _ESignatureTreeView ESignatureTreeView; +typedef struct _ESignatureTreeViewClass ESignatureTreeViewClass; +typedef struct _ESignatureTreeViewPrivate ESignatureTreeViewPrivate; + +struct _ESignatureTreeView { + GtkTreeView parent; + ESignatureTreeViewPrivate *priv; +}; + +struct _ESignatureTreeViewClass { + GtkTreeViewClass parent_class; +}; + +GType e_signature_tree_view_get_type (void); +GtkWidget * e_signature_tree_view_new (void); +ESignatureList *e_signature_tree_view_get_signature_list + (ESignatureTreeView *tree_view); +void e_signature_tree_view_set_signature_list + (ESignatureTreeView *tree_view, + ESignatureList *signature_list); +ESignature * e_signature_tree_view_get_selected + (ESignatureTreeView *tree_view); +gboolean e_signature_tree_view_set_selected + (ESignatureTreeView *tree_view, + ESignature *signature); + +G_END_DECLS + +#endif /* E_SIGNATURE_TREE_VIEW_H */ diff --git a/widgets/misc/e-task-bar.c b/widgets/misc/e-task-bar.c deleted file mode 100644 index e7fc15fe00..0000000000 --- a/widgets/misc/e-task-bar.c +++ /dev/null @@ -1,307 +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) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "e-task-bar.h" - -struct _ETaskBarPrivate -{ - GtkWidget *message_label; - GtkHBox *hbox; -}; - -/* WARNING: Ugly hack starts here. */ -#define MAX_ACTIVITIES_PER_COMPONENT 2 - -G_DEFINE_TYPE (ETaskBar, e_task_bar, GTK_TYPE_HBOX) - -#if 0 -static void -reduce_displayed_activities_per_component (ETaskBar *task_bar) -{ - GHashTable *component_ids_hash; - GtkBox *box; - GList *p; - - component_ids_hash = g_hash_table_new (g_str_hash, g_str_equal); - - box = GTK_BOX (task_bar->priv->hbox); - - for (p = box->children; p != NULL; p = p->next) { - GtkBoxChild *child; - const gchar *component_id; - gpointer hash_item; - - child = (GtkBoxChild *) p->data; - component_id = e_task_widget_get_component_id (E_TASK_WIDGET (child->widget)); - - hash_item = g_hash_table_lookup (component_ids_hash, component_id); - - if (hash_item == NULL) { - gtk_widget_show (child->widget); - g_hash_table_insert (component_ids_hash, (gpointer) component_id, GINT_TO_POINTER (1)); - } else { - gint num_items; - - num_items = GPOINTER_TO_INT (hash_item); - g_return_if_fail (num_items <= MAX_ACTIVITIES_PER_COMPONENT); - - if (num_items == MAX_ACTIVITIES_PER_COMPONENT) { - gtk_widget_hide (child->widget); - } else { - num_items ++; - gtk_widget_show (child->widget); - g_hash_table_insert (component_ids_hash, (gpointer) component_id, GINT_TO_POINTER (num_items)); - } - } - } - - g_hash_table_destroy (component_ids_hash); -} -#endif - - -static void impl_finalize (GObject *object); - -static void -e_task_bar_class_init (ETaskBarClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = impl_finalize; -} - -static void -e_task_bar_init (ETaskBar *task_bar) -{ - GtkWidget *label, *hbox; - gint height; - - task_bar->priv = g_new (ETaskBarPrivate, 1); - - gtk_box_set_spacing (GTK_BOX (task_bar), 10); - - label = gtk_label_new (NULL); - gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); - gtk_box_pack_start (GTK_BOX (task_bar), label, TRUE, TRUE, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - task_bar->priv->message_label = label; - - hbox = gtk_hbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (task_bar), hbox); - task_bar->priv->hbox = GTK_HBOX (hbox); - - /* Make the task bar large enough to accomodate a small icon. - * XXX The "* 2" is a fudge factor to allow for some padding. - * The true value is probably buried in a style property. */ - gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &height); - gtk_widget_set_size_request (GTK_WIDGET (task_bar), -1, height * 2); -} - -static void -impl_finalize (GObject *object) -{ - ETaskBar *task_bar; - ETaskBarPrivate *priv; - - task_bar = E_TASK_BAR (object); - priv = task_bar->priv; - - g_free (priv); - - (* G_OBJECT_CLASS (e_task_bar_parent_class)->finalize) (object); -} - - -void -e_task_bar_construct (ETaskBar *task_bar) -{ - g_return_if_fail (task_bar != NULL); - g_return_if_fail (E_IS_TASK_BAR (task_bar)); - - /* Nothing to do here. */ -} - -GtkWidget * -e_task_bar_new (void) -{ - ETaskBar *task_bar; - - task_bar = g_object_new (e_task_bar_get_type (), NULL); - e_task_bar_construct (task_bar); - - return GTK_WIDGET (task_bar); -} - -void -e_task_bar_set_message (ETaskBar *task_bar, - const gchar *message) -{ - if (message) { - gtk_label_set_text ( - GTK_LABEL (task_bar->priv->message_label), message); - gtk_widget_show (task_bar->priv->message_label); - } else { - e_task_bar_unset_message (task_bar); - } -} - -void -e_task_bar_unset_message (ETaskBar *task_bar) -{ - gtk_widget_hide (task_bar->priv->message_label); -} - -void -e_task_bar_prepend_task (ETaskBar *task_bar, - ETaskWidget *task_widget) -{ - GtkBoxChild *child_info; - GtkBox *box; - - g_return_if_fail (task_bar != NULL); - g_return_if_fail (E_IS_TASK_BAR (task_bar)); - g_return_if_fail (task_widget != NULL); - g_return_if_fail (E_IS_TASK_WIDGET (task_widget)); - - /* Hah hah. GTK+ sucks. This is adapted from `gtkhbox.c'. */ - - child_info = g_new (GtkBoxChild, 1); - child_info->widget = GTK_WIDGET (task_widget); - child_info->padding = 0; - child_info->expand = TRUE; - child_info->fill = TRUE; - child_info->pack = GTK_PACK_START; - - box = GTK_BOX (task_bar->priv->hbox); - - box->children = g_list_prepend (box->children, child_info); - - gtk_widget_set_parent (GTK_WIDGET (task_widget), GTK_WIDGET (task_bar->priv->hbox)); - - if (GTK_WIDGET_REALIZED (task_bar)) - gtk_widget_realize (GTK_WIDGET (task_widget)); - - if (GTK_WIDGET_VISIBLE (task_bar) && GTK_WIDGET_VISIBLE (task_widget)) { - if (GTK_WIDGET_MAPPED (task_bar)) - gtk_widget_map (GTK_WIDGET (task_widget)); - gtk_widget_queue_resize (GTK_WIDGET (task_widget)); - } - - /* We don't restrict */ - /* reduce_displayed_activities_per_component (task_bar);*/ - - gtk_widget_show (GTK_WIDGET (task_bar->priv->hbox)); -} - -void -e_task_bar_remove_task_from_id (ETaskBar *task_bar, - guint id) -{ - ETaskWidget *task_widget; - - g_return_if_fail (task_bar != NULL); - g_return_if_fail (E_IS_TASK_BAR (task_bar)); - - task_widget = e_task_bar_get_task_widget_from_id (task_bar, id); - if (!task_widget) { - printf("Failed...\n"); - return; - } - - gtk_widget_destroy (GTK_WIDGET (task_widget)); - - /* We don't restrict here on */ - /* reduce_displayed_activities_per_component (task_bar); */ - - if (g_list_length (GTK_BOX (task_bar->priv->hbox)->children) == 0) - gtk_widget_hide (GTK_WIDGET (task_bar->priv->hbox)); -} - -void -e_task_bar_remove_task (ETaskBar *task_bar, - gint n) -{ - ETaskWidget *task_widget; - - g_return_if_fail (task_bar != NULL); - g_return_if_fail (E_IS_TASK_BAR (task_bar)); - g_return_if_fail (n >= 0); - - task_widget = e_task_bar_get_task_widget (task_bar, n); - gtk_widget_destroy (GTK_WIDGET (task_widget)); - - /* We don't restrict here on */ - /* reduce_displayed_activities_per_component (task_bar); */ - - if (g_list_length (GTK_BOX (task_bar->priv->hbox)->children) == 0) - gtk_widget_hide (GTK_WIDGET (task_bar->priv->hbox)); -} - -ETaskWidget * -e_task_bar_get_task_widget_from_id (ETaskBar *task_bar, - guint id) -{ - GtkBoxChild *child_info; - ETaskWidget *w = NULL; - GList *list; - - g_return_val_if_fail (task_bar != NULL, NULL); - g_return_val_if_fail (E_IS_TASK_BAR (task_bar), NULL); - - list = GTK_BOX (task_bar->priv->hbox)->children; - while (list) { - child_info = list->data; - w = (ETaskWidget *) child_info->widget; - if (w && w->id == id) - break; - - w = NULL; - list = list->next; - } - - return w; -} - -ETaskWidget * - -e_task_bar_get_task_widget (ETaskBar *task_bar, - gint n) -{ - GtkBoxChild *child_info; - - g_return_val_if_fail (task_bar != NULL, NULL); - g_return_val_if_fail (E_IS_TASK_BAR (task_bar), NULL); - - child_info = (GtkBoxChild *) g_list_nth (GTK_BOX (task_bar->priv->hbox)->children, n)->data; - - return E_TASK_WIDGET (child_info->widget); -} - -gint -e_task_bar_get_num_children (ETaskBar *task_bar) -{ - return g_list_length (GTK_BOX (task_bar->priv->hbox)->children); -} diff --git a/widgets/misc/e-task-bar.h b/widgets/misc/e-task-bar.h deleted file mode 100644 index 19ed37a2e8..0000000000 --- a/widgets/misc/e-task-bar.h +++ /dev/null @@ -1,76 +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 _E_TASK_BAR_H_ -#define _E_TASK_BAR_H_ - -#include "e-task-widget.h" - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define E_TYPE_TASK_BAR (e_task_bar_get_type ()) -#define E_TASK_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_TASK_BAR, ETaskBar)) -#define E_TASK_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_TASK_BAR, ETaskBarClass)) -#define E_IS_TASK_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_TASK_BAR)) -#define E_IS_TASK_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_TASK_BAR)) - - -typedef struct _ETaskBar ETaskBar; -typedef struct _ETaskBarPrivate ETaskBarPrivate; -typedef struct _ETaskBarClass ETaskBarClass; - -struct _ETaskBar { - GtkHBox parent; - - ETaskBarPrivate *priv; -}; - -struct _ETaskBarClass { - GtkHBoxClass parent_class; -}; - - -GType e_task_bar_get_type (void); -void e_task_bar_construct (ETaskBar *task_bar); -GtkWidget *e_task_bar_new (void); - -void e_task_bar_set_message (ETaskBar *task_bar, - const gchar *message); -void e_task_bar_unset_message (ETaskBar *task_bar); - -void e_task_bar_prepend_task (ETaskBar *task_bar, - ETaskWidget *task_widget); -void e_task_bar_remove_task (ETaskBar *task_bar, - gint n); -ETaskWidget * e_task_bar_get_task_widget_from_id (ETaskBar *task_bar, - guint id); - -void e_task_bar_remove_task_from_id (ETaskBar *task_bar, - guint id); -ETaskWidget *e_task_bar_get_task_widget (ETaskBar *task_bar, - gint n); -gint e_task_bar_get_num_children (ETaskBar *task_bar); -G_END_DECLS - -#endif /* _E_TASK_BAR_H_ */ diff --git a/widgets/misc/e-task-widget.c b/widgets/misc/e-task-widget.c deleted file mode 100644 index 7d583c3ffa..0000000000 --- a/widgets/misc/e-task-widget.c +++ /dev/null @@ -1,290 +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) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "e-task-widget.h" -#include "e-spinner.h" - -#include <glib/gi18n.h> - -#define SPACING 2 - -struct _ETaskWidgetPrivate { - gchar *component_id; - - GtkWidget *label; - GtkWidget *box; - GtkWidget *image; - - void (*cancel_func) (gpointer data); - gpointer data; -}; - -G_DEFINE_TYPE (ETaskWidget, e_task_widget, GTK_TYPE_EVENT_BOX) - -/* GObject methods. */ - -static void -impl_finalize (GObject *object) -{ - ETaskWidget *task_widget; - ETaskWidgetPrivate *priv; - - task_widget = E_TASK_WIDGET (object); - priv = task_widget->priv; - - g_free (priv->component_id); - g_free (priv); - - (* G_OBJECT_CLASS (e_task_widget_parent_class)->finalize) (object); -} - - -static void -e_task_widget_class_init (ETaskWidgetClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = impl_finalize; -} - -static void -e_task_widget_init (ETaskWidget *task_widget) -{ - ETaskWidgetPrivate *priv; - - priv = g_new (ETaskWidgetPrivate, 1); - - priv->component_id = NULL; - priv->label = NULL; - priv->image = NULL; - priv->box = NULL; - - task_widget->priv = priv; - task_widget->id = 0; -} - -static gboolean -button_press_event_cb (GtkWidget *w, gpointer data) -{ - ETaskWidget *tw = (ETaskWidget *) data; - ETaskWidgetPrivate *priv = tw->priv; - - priv->cancel_func (priv->data); - - return TRUE; -} - -static gboolean -prepare_popup (ETaskWidget *widget, GdkEventButton *event) -{ - if (event->type != GDK_BUTTON_PRESS) - return FALSE; - - if (event->button != 3) - return FALSE; - - /* FIXME: Implement Cancel */ - - return TRUE; -} - - -void -e_task_widget_construct (ETaskWidget *task_widget, - const gchar *component_id, - const gchar *information, - void (*cancel_func) (gpointer data), - gpointer data) -{ - ETaskWidgetPrivate *priv; - GtkWidget *box; - GtkWidget *frame; - - g_return_if_fail (task_widget != NULL); - g_return_if_fail (E_IS_TASK_WIDGET (task_widget)); - g_return_if_fail (component_id != NULL); - g_return_if_fail (information != NULL); - - priv = task_widget->priv; - - priv->component_id = g_strdup (component_id); - - frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); - gtk_container_add (GTK_CONTAINER (task_widget), frame); - gtk_widget_show (frame); - - box = gtk_hbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (frame), box); - gtk_widget_show (box); - - gtk_widget_set_size_request (box, 1, -1); - - priv->box = gtk_hbox_new (FALSE, 0); - priv->image = e_spinner_new_spinning_small_shown (); - gtk_widget_show (priv->box); - gtk_box_pack_start (GTK_BOX (priv->box), priv->image, FALSE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (box), priv->box, FALSE, TRUE, 0); - priv->label = gtk_label_new (""); - gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.5); - gtk_widget_show (priv->label); - gtk_box_pack_start (GTK_BOX (box), priv->label, TRUE, TRUE, 0); - if (cancel_func) { - GdkPixbuf *pixbuf; - GtkWidget *image; - GtkWidget *tool; - - pixbuf = gtk_icon_theme_load_icon ( - gtk_icon_theme_get_default (), - "gtk-stop", 16, 0, NULL); - image = gtk_image_new_from_pixbuf (pixbuf); - g_object_unref (pixbuf); - - tool = (GtkWidget *) gtk_tool_button_new (image, NULL); - gtk_box_pack_end (GTK_BOX (box), tool, FALSE, TRUE, 0); - gtk_widget_show_all (tool); - - gtk_widget_set_sensitive (tool, cancel_func != NULL); - priv->cancel_func = cancel_func; - priv->data = data; - g_signal_connect (tool, "clicked", G_CALLBACK (button_press_event_cb), task_widget); - g_signal_connect (task_widget, "button-press-event", G_CALLBACK (prepare_popup), task_widget); - - } - - e_task_widget_update (task_widget, information, -1.0); -} - -GtkWidget * -e_task_widget_new_with_cancel (const gchar *component_id, - const gchar *information, - void (*cancel_func) (gpointer data), - gpointer data) -{ - ETaskWidget *task_widget; - - g_return_val_if_fail (information != NULL, NULL); - - task_widget = g_object_new (e_task_widget_get_type (), NULL); - e_task_widget_construct (task_widget, component_id, information, cancel_func, data); - - return GTK_WIDGET (task_widget); -} - -GtkWidget * -e_task_widget_new (const gchar *component_id, - const gchar *information) -{ - ETaskWidget *task_widget; - - g_return_val_if_fail (information != NULL, NULL); - - task_widget = g_object_new (e_task_widget_get_type (), NULL); - e_task_widget_construct (task_widget, component_id, information, NULL, NULL); - - return GTK_WIDGET (task_widget); -} - -GtkWidget * -e_task_widget_update_image (ETaskWidget *task_widget, - const gchar *stock, const gchar *text) -{ - GtkWidget *image, *tool; - GdkPixbuf *pixbuf; - - pixbuf = gtk_icon_theme_load_icon ( - gtk_icon_theme_get_default (), - stock, 16, 0, NULL); - image = gtk_image_new_from_pixbuf (pixbuf); - g_object_unref (pixbuf); - - tool = (GtkWidget *) gtk_tool_button_new (image, NULL); - gtk_box_pack_start (GTK_BOX(task_widget->priv->box), tool, FALSE, TRUE, 0); - gtk_widget_show_all (task_widget->priv->box); - gtk_widget_hide (task_widget->priv->image); - task_widget->priv->image = image; - gtk_label_set_text (GTK_LABEL (task_widget->priv->label), text); - - return tool; -} - - -void -e_task_widget_update (ETaskWidget *task_widget, - const gchar *information, - double completion) -{ - ETaskWidgetPrivate *priv; - gchar *text; - - g_return_if_fail (task_widget != NULL); - g_return_if_fail (E_IS_TASK_WIDGET (task_widget)); - g_return_if_fail (information != NULL); - - priv = task_widget->priv; - - if (completion < 0.0) { - /* For Translator only: %s is status message that is displayed (eg "moving items", "updating objects") */ - text = g_strdup_printf (_("%s (...)"), information); - } else { - gint percent_complete; - percent_complete = (gint) (completion * 100.0 + .5); - /* For Translator only: %s is status message that is displayed (eg "moving items", "updating objects"); - %d is a number between 0 and 100, describing the percentage of operation complete */ - text = g_strdup_printf (_("%s (%d%% complete)"), information, percent_complete); - } - - gtk_label_set_text (GTK_LABEL (priv->label), text); - - gtk_widget_set_tooltip_text (GTK_WIDGET (task_widget), text); - - g_free (text); -} - -void -e_task_wiget_alert (ETaskWidget *task_widget) -{ - g_return_if_fail (task_widget != NULL); - g_return_if_fail (E_IS_TASK_WIDGET (task_widget)); -} - -void -e_task_wiget_unalert (ETaskWidget *task_widget) -{ - g_return_if_fail (task_widget != NULL); - g_return_if_fail (E_IS_TASK_WIDGET (task_widget)); -} - - -const gchar * -e_task_widget_get_component_id (ETaskWidget *task_widget) -{ - g_return_val_if_fail (task_widget != NULL, NULL); - g_return_val_if_fail (E_IS_TASK_WIDGET (task_widget), NULL); - - return task_widget->priv->component_id; -} - diff --git a/widgets/misc/e-task-widget.h b/widgets/misc/e-task-widget.h deleted file mode 100644 index b650bd8ac5..0000000000 --- a/widgets/misc/e-task-widget.h +++ /dev/null @@ -1,77 +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 _E_TASK_WIDGET_H_ -#define _E_TASK_WIDGET_H_ - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define E_TYPE_TASK_WIDGET (e_task_widget_get_type ()) -#define E_TASK_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_TASK_WIDGET, ETaskWidget)) -#define E_TASK_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_TASK_WIDGET, ETaskWidgetClass)) -#define E_IS_TASK_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_TASK_WIDGET)) -#define E_IS_TASK_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_TASK_WIDGET)) - - -typedef struct _ETaskWidget ETaskWidget; -typedef struct _ETaskWidgetPrivate ETaskWidgetPrivate; -typedef struct _ETaskWidgetClass ETaskWidgetClass; - -struct _ETaskWidget { - GtkEventBox parent; - - ETaskWidgetPrivate *priv; - guint id; -}; - -struct _ETaskWidgetClass { - GtkEventBoxClass parent_class; -}; - - -GType e_task_widget_get_type (void); -void e_task_widget_construct (ETaskWidget *task_widget, - const gchar *component_id, - const gchar *information, - void (*cancel_func) (gpointer data), - gpointer data); -GtkWidget * e_task_widget_new (const gchar *component_id, - const gchar *information); -GtkWidget * e_task_widget_new_with_cancel (const gchar *component_id, - const gchar *information, - void (*cancel_func) (gpointer data), - gpointer data); -void e_task_widget_update (ETaskWidget *task_widget, - const gchar *information, - double completion); -GtkWidget * e_task_widget_update_image (ETaskWidget *task_widget, - const gchar *stock, - const gchar *text); -void e_task_wiget_alert (ETaskWidget *task_widget); -void e_task_wiget_unalert (ETaskWidget *task_widget); -const gchar * e_task_widget_get_component_id (ETaskWidget *task_widget); - -G_END_DECLS - -#endif /* _E_TASK_WIDGET_H_ */ diff --git a/widgets/misc/e-timeout-activity.c b/widgets/misc/e-timeout-activity.c new file mode 100644 index 0000000000..aa57960fe0 --- /dev/null +++ b/widgets/misc/e-timeout-activity.c @@ -0,0 +1,198 @@ +/* + * e-timeout-activity.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-timeout-activity.h" + +#include <stdarg.h> + +#define E_TIMEOUT_ACTIVITY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityPrivate)) + +struct _ETimeoutActivityPrivate { + guint timeout_id; +}; + +enum { + TIMEOUT, + LAST_SIGNAL +}; + +static gpointer parent_class; +static gulong signals[LAST_SIGNAL]; + +static gboolean +timeout_activity_cb (ETimeoutActivity *timeout_activity) +{ + g_signal_emit (timeout_activity, signals[TIMEOUT], 0); + + return FALSE; +} + +static void +timeout_activity_finalize (GObject *object) +{ + ETimeoutActivityPrivate *priv; + + priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (object); + + if (priv->timeout_id > 0) + g_source_remove (priv->timeout_id); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +timeout_activity_cancelled (EActivity *activity) +{ + ETimeoutActivityPrivate *priv; + + priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (activity); + + if (priv->timeout_id > 0) { + g_source_remove (priv->timeout_id); + priv->timeout_id = 0; + } + + /* Chain up to parent's cancelled() method. */ + E_ACTIVITY_CLASS (parent_class)->cancelled (activity); +} + +static void +timeout_activity_completed (EActivity *activity) +{ + ETimeoutActivityPrivate *priv; + + priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (activity); + + if (priv->timeout_id > 0) { + g_source_remove (priv->timeout_id); + priv->timeout_id = 0; + } + + /* Chain up to parent's completed() method. */ + E_ACTIVITY_CLASS (parent_class)->completed (activity); +} + +static void +timeout_activity_timeout (ETimeoutActivity *timeout_activity) +{ + /* Allow subclasses to safely chain up. */ +} + +static void +timeout_activity_class_init (ETimeoutActivityClass *class) +{ + GObjectClass *object_class; + EActivityClass *activity_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (ETimeoutActivityPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = timeout_activity_finalize; + + activity_class = E_ACTIVITY_CLASS (class); + activity_class->cancelled = timeout_activity_cancelled; + activity_class->completed = timeout_activity_completed; + + class->timeout = timeout_activity_timeout; + + signals[TIMEOUT] = g_signal_new ( + "timeout", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (ETimeoutActivityClass, timeout), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +timeout_activity_init (ETimeoutActivity *timeout_activity) +{ + timeout_activity->priv = + E_TIMEOUT_ACTIVITY_GET_PRIVATE (timeout_activity); +} + +GType +e_timeout_activity_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (ETimeoutActivityClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) timeout_activity_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (ETimeoutActivity), + 0, /* n_preallocs */ + (GInstanceInitFunc) timeout_activity_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + E_TYPE_ACTIVITY, "ETimeoutActivity", &type_info, 0); + } + + return type; +} + +EActivity * +e_timeout_activity_new (const gchar *primary_text) +{ + return g_object_new ( + E_TYPE_TIMEOUT_ACTIVITY, + "primary-text", primary_text, NULL); +} + +EActivity * +e_timeout_activity_newv (const gchar *format, ...) +{ + EActivity *activity; + gchar *primary_text; + va_list args; + + va_start (args, format); + primary_text = g_strdup_vprintf (format, args); + activity = e_timeout_activity_new (primary_text); + g_free (primary_text); + va_end (args); + + return activity; +} + +void +e_timeout_activity_set_timeout (ETimeoutActivity *timeout_activity, + guint seconds) +{ + g_return_if_fail (E_IS_TIMEOUT_ACTIVITY (timeout_activity)); + + if (timeout_activity->priv->timeout_id > 0) + e_activity_cancel (E_ACTIVITY (timeout_activity)); + + timeout_activity->priv->timeout_id = g_timeout_add_seconds ( + seconds, (GSourceFunc) timeout_activity_cb, timeout_activity); +} diff --git a/widgets/misc/e-timeout-activity.h b/widgets/misc/e-timeout-activity.h new file mode 100644 index 0000000000..82dd1138c2 --- /dev/null +++ b/widgets/misc/e-timeout-activity.h @@ -0,0 +1,73 @@ +/* + * e-timeout-activity.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_TIMEOUT_ACTIVITY_H +#define E_TIMEOUT_ACTIVITY_H + +#include <e-activity.h> + +/* Standard GObject macros */ +#define E_TYPE_TIMEOUT_ACTIVITY \ + (e_timeout_activity_get_type ()) +#define E_TIMEOUT_ACTIVITY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivity)) +#define E_TIMEOUT_ACTIVITY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityClass)) +#define E_IS_TIMEOUT_ACTIVITY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_TIMEOUT_ACTIVITY)) +#define E_IS_TIMEOUT_ACTIVITY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_TIMEOUT_ACTIVITY)) +#define E_TIMEOUT_ACTIVITY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityClass)) + +G_BEGIN_DECLS + +typedef struct _ETimeoutActivity ETimeoutActivity; +typedef struct _ETimeoutActivityClass ETimeoutActivityClass; +typedef struct _ETimeoutActivityPrivate ETimeoutActivityPrivate; + +struct _ETimeoutActivity { + EActivity parent; + ETimeoutActivityPrivate *priv; +}; + +struct _ETimeoutActivityClass { + EActivityClass parent_class; + + /* Signals */ + void (*timeout) (ETimeoutActivity *timeout_activity); +}; + +GType e_timeout_activity_get_type (void); +EActivity * e_timeout_activity_new (const gchar *primary_text); +EActivity * e_timeout_activity_newv (const gchar *format, + ...) G_GNUC_PRINTF (1, 2); +void e_timeout_activity_set_timeout (ETimeoutActivity *timeout_activity, + guint seconds); + +G_END_DECLS + +#endif /* E_TIMEOUT_ACTIVITY_H */ diff --git a/widgets/misc/e-unicode.c b/widgets/misc/e-unicode.c deleted file mode 100644 index fb815ff94f..0000000000 --- a/widgets/misc/e-unicode.c +++ /dev/null @@ -1,2052 +0,0 @@ -/* - * e-unicode.c - utf-8 support functions for gal - * - * 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: - * Lauris Kaplinski <lauris@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -/* - * TODO: Break simple ligatures in e_utf8_strstrcasedecomp - */ - -#include <config.h> - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <ctype.h> -#include <iconv.h> -#ifdef HAVE_ALLOCA_H -#include <alloca.h> -#endif - -#include <gdk/gdkkeysyms.h> -#include <gtk/gtk.h> -#include <libxml/xmlmemory.h> - -#include <camel/camel-iconv.h> - -#include <glib/gi18n.h> -#include "e-unicode.h" - -#define d(x) - -#define FONT_TESTING -#define MAX_DECOMP 8 - -static gint e_canonical_decomposition (gunichar ch, gunichar * buf); -static gunichar e_stripped_char (gunichar ch); - -/* FIXME: this has not been ported fully yet - non ASCII people beware. */ - -/* - * This my favourite - * - * strstr doing case insensitive, decomposing search - * - * Lauris - */ - -const gchar * -e_utf8_strstrcasedecomp (const gchar *haystack, const gchar *needle) -{ - gunichar *nuni; - gunichar unival; - gint nlen; - const gchar *o, *p; - - if (haystack == NULL) return NULL; - if (needle == NULL) return NULL; - if (strlen (needle) == 0) return haystack; - if (strlen (haystack) == 0) return NULL; - - nuni = alloca (sizeof (gunichar) * strlen (needle)); - - nlen = 0; - for (p = e_unicode_get_utf8 (needle, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { - gint sc; - sc = e_stripped_char (unival); - if (sc) { - nuni[nlen++] = sc; - } - } - /* NULL means there was illegal utf-8 sequence */ - if (!p) return NULL; - /* If everything is correct, we have decomposed, lowercase, stripped needle */ - if (nlen < 1) return haystack; - - o = haystack; - for (p = e_unicode_get_utf8 (o, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { - gint sc; - sc = e_stripped_char (unival); - if (sc) { - /* We have valid stripped gchar */ - if (sc == nuni[0]) { - const gchar *q = p; - gint npos = 1; - while (npos < nlen) { - q = e_unicode_get_utf8 (q, &unival); - if (!q || !unival) return NULL; - sc = e_stripped_char (unival); - if ((!sc) || (sc != nuni[npos])) break; - npos++; - } - if (npos == nlen) { - return o; - } - } - } - o = p; - } - - return NULL; -} - -const gchar * -e_utf8_strstrcase (const gchar *haystack, const gchar *needle) -{ - gunichar *nuni; - gunichar unival; - gint nlen; - const gchar *o, *p; - - if (haystack == NULL) return NULL; - if (needle == NULL) return NULL; - if (strlen (needle) == 0) return haystack; - if (strlen (haystack) == 0) return NULL; - - nuni = alloca (sizeof (gunichar) * strlen (needle)); - - nlen = 0; - for (p = e_unicode_get_utf8 (needle, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { - nuni[nlen++] = g_unichar_tolower (unival); - } - /* NULL means there was illegal utf-8 sequence */ - if (!p) return NULL; - - o = haystack; - for (p = e_unicode_get_utf8 (o, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { - gint sc; - sc = g_unichar_tolower (unival); - /* We have valid stripped gchar */ - if (sc == nuni[0]) { - const gchar *q = p; - gint npos = 1; - while (npos < nlen) { - q = e_unicode_get_utf8 (q, &unival); - if (!q || !unival) return NULL; - sc = g_unichar_tolower (unival); - if (sc != nuni[npos]) break; - npos++; - } - if (npos == nlen) { - return o; - } - } - o = p; - } - - return NULL; -} - -#if 0 -const gchar * -e_utf8_strstrcase (const gchar *haystack, const gchar *needle) -{ - gchar *p; - gunichar *huni, *nuni; - gunichar unival; - gint hlen, nlen, hp, np; - - if (haystack == NULL) return NULL; - if (needle == NULL) return NULL; - if (strlen (needle) == 0) return haystack; - - huni = alloca (sizeof (gunichar) * strlen (haystack)); - - for (hlen = 0, p = e_unicode_get_utf8 (haystack, &unival); p && unival; hlen++, p = e_unicode_get_utf8 (p, &unival)) { - huni[hlen] = g_unichar_tolower (unival); - } - - if (!p) return NULL; - if (hlen == 0) return NULL; - - nuni = alloca (sizeof (gunichar) * strlen (needle)); - - for (nlen = 0, p = e_unicode_get_utf8 (needle, &unival); p && unival; nlen++, p = e_unicode_get_utf8 (p, &unival)) { - nuni[nlen] = g_unichar_tolower (unival); - } - - if (!p) return NULL; - if (nlen == 0) return NULL; - - if (hlen < nlen) return NULL; - - for (hp = 0; hp <= hlen - nlen; hp++) { - for (np = 0; np < nlen; np++) { - if (huni[hp + np] != nuni[np]) break; - } - if (np == nlen) return haystack + unicode_offset_to_index (haystack, hp); - } - - return NULL; -} -#endif - -gchar * -e_utf8_from_gtk_event_key (GtkWidget *widget, guint keyval, const gchar *string) -{ - gint unival; - gchar *utf; - gint unilen; - - if (keyval == GDK_VoidSymbol) { - utf = e_utf8_from_locale_string (string); - } else { - unival = gdk_keyval_to_unicode (keyval); - - if (unival < ' ') return NULL; - - utf = g_new (gchar, 7); - - unilen = e_unichar_to_utf8 (unival, utf); - - utf[unilen] = '\0'; - } - - return utf; -} - -gchar * -e_utf8_from_iconv_string_sized (iconv_t ic, const gchar *string, gint bytes) -{ - gchar *new, *ob; - const gchar *ib; - gsize ibl, obl; - - if (!string) return NULL; - - if (ic == (iconv_t) -1) { - gint i; - /* iso-8859-1 */ - ib = (gchar *) string; - new = ob = (gchar *)g_new (unsigned char, bytes * 2 + 1); - for (i = 0; i < (bytes); i ++) { - ob += e_unichar_to_utf8 (ib[i], ob); - } - *ob = '\0'; - return new; - } - - ib = string; - ibl = bytes; - new = ob = g_new (gchar, ibl * 6 + 1); - obl = ibl * 6; - - while (ibl > 0) { - camel_iconv (ic, &ib, &ibl, &ob, &obl); - if (ibl > 0) { - gint len; - if ((*ib & 0x80) == 0x00) len = 1; - else if ((*ib &0xe0) == 0xc0) len = 2; - else if ((*ib &0xf0) == 0xe0) len = 3; - else if ((*ib &0xf8) == 0xf0) len = 4; - else { - g_warning ("Invalid UTF-8 sequence"); - break; - } - ib += len; - ibl = bytes - (ib - string); - if (ibl > bytes) ibl = 0; - *ob++ = '_'; - obl--; - } - } - - *ob = '\0'; - - return new; -} - -gchar * -e_utf8_from_iconv_string (iconv_t ic, const gchar *string) -{ - if (!string) return NULL; - return e_utf8_from_iconv_string_sized (ic, string, strlen (string)); -} - -gchar * -e_utf8_to_iconv_string_sized (iconv_t ic, const gchar *string, gint bytes) -{ - gchar *new, *ob; - const gchar *ib; - gsize ibl, obl; - - if (!string) return NULL; - - if (ic == (iconv_t) -1) { - gint len; - const gchar *u; - gunichar uc; - - new = (gchar *)g_new (unsigned char, bytes * 4 + 1); - u = string; - len = 0; - - while ((u) && (u - string < bytes)) { - u = e_unicode_get_utf8 (u, &uc); - new[len++] = uc & 0xff; - } - new[len] = '\0'; - return new; - } - - ib = string; - ibl = bytes; - new = ob = g_new (char, ibl * 4 + 4); - obl = ibl * 4; - - while (ibl > 0) { - camel_iconv (ic, &ib, &ibl, &ob, &obl); - if (ibl > 0) { - gint len; - if ((*ib & 0x80) == 0x00) len = 1; - else if ((*ib &0xe0) == 0xc0) len = 2; - else if ((*ib &0xf0) == 0xe0) len = 3; - else if ((*ib &0xf8) == 0xf0) len = 4; - else { - g_warning ("Invalid UTF-8 sequence"); - break; - } - ib += len; - ibl = bytes - (ib - string); - if (ibl > bytes) ibl = 0; - - /* FIXME: this is wrong... what if the destination charset is 16 or 32 bit? */ - *ob++ = '_'; - obl--; - } - } - - /* Make sure to terminate with plenty of padding */ - memset (ob, 0, 4); - - return new; -} - -gchar * -e_utf8_to_iconv_string (iconv_t ic, const gchar *string) -{ - if (!string) return NULL; - return e_utf8_to_iconv_string_sized (ic, string, strlen (string)); -} - -gchar * -e_utf8_from_charset_string_sized (const gchar *charset, const gchar *string, gint bytes) -{ - iconv_t ic; - gchar *ret; - - if (!string) return NULL; - - ic = camel_iconv_open("utf-8", charset); - ret = e_utf8_from_iconv_string_sized (ic, string, bytes); - camel_iconv_close(ic); - - return ret; -} - -gchar * -e_utf8_from_charset_string (const gchar *charset, const gchar *string) -{ - if (!string) return NULL; - return e_utf8_from_charset_string_sized (charset, string, strlen (string)); -} - -gchar * -e_utf8_to_charset_string_sized (const gchar *charset, const gchar *string, gint bytes) -{ - iconv_t ic; - gchar *ret; - - if (!string) return NULL; - - ic = camel_iconv_open(charset, "utf-8"); - ret = e_utf8_to_iconv_string_sized (ic, string, bytes); - camel_iconv_close(ic); - - return ret; -} - -gchar * -e_utf8_to_charset_string (const gchar *charset, const gchar *string) -{ - if (!string) return NULL; - return e_utf8_to_charset_string_sized (charset, string, strlen (string)); -} - -gchar * -e_utf8_from_locale_string_sized (const gchar *string, gint bytes) -{ - iconv_t ic; - gchar *ret; - - if (!string) return NULL; - - ic = camel_iconv_open("utf-8", camel_iconv_locale_charset()); - ret = e_utf8_from_iconv_string_sized (ic, string, bytes); - camel_iconv_close(ic); - - return ret; -} - -gchar * -e_utf8_from_locale_string (const gchar *string) -{ - if (!string) return NULL; - return e_utf8_from_locale_string_sized (string, strlen (string)); -} - -gchar * -e_utf8_to_locale_string_sized (const gchar *string, gint bytes) -{ - iconv_t ic; - gchar *ret; - - if (!string) return NULL; - - ic = camel_iconv_open(camel_iconv_locale_charset(), "utf-8"); - ret = e_utf8_to_iconv_string_sized (ic, string, bytes); - camel_iconv_close(ic); - - return ret; -} - -gchar * -e_utf8_to_locale_string (const gchar *string) -{ - if (!string) return NULL; - return e_utf8_to_locale_string_sized (string, strlen (string)); -} - -gboolean -e_utf8_is_ascii (const gchar *string) -{ - gchar c; - - g_return_val_if_fail (string != NULL, FALSE); - - for (; (c = *string); string++) { - if (c & 0x80) - return FALSE; - } - - return TRUE; -} - -gchar * -e_utf8_gtk_entry_get_text (GtkEntry *entry) -{ - return g_strdup (gtk_entry_get_text (entry)); -} - -gchar * -e_utf8_gtk_editable_get_text (GtkEditable *editable) -{ - return gtk_editable_get_chars (editable, 0, -1); -} - -gchar * -e_utf8_gtk_editable_get_chars (GtkEditable *editable, gint start, gint end) -{ - return gtk_editable_get_chars (editable, start, end); -} - -void -e_utf8_gtk_editable_insert_text (GtkEditable *editable, const gchar *text, gint length, gint *position) -{ - gtk_editable_insert_text (editable, text, length, position); -} - -void -e_utf8_gtk_editable_set_text (GtkEditable *editable, const gchar *text) -{ - gint position; - - gtk_editable_delete_text(editable, 0, -1); - gtk_editable_insert_text (editable, text, strlen (text), &position); -} - -void -e_utf8_gtk_entry_set_text (GtkEntry *entry, const gchar *text) -{ - if (!text) - gtk_entry_set_text(entry, ""); - else - gtk_entry_set_text (entry, text); -} - -/* - * Translate \U+XXXX\ sequences to utf8 chars - */ - -gchar * -e_utf8_xml1_decode (const gchar *text) -{ - const guchar *c; - gchar *u, *d; - gint len, s; - - g_return_val_if_fail (text != NULL, NULL); - - len = strlen (text)+1; - /* len * 2 is absolute maximum */ - u = d = g_malloc (len * 2); - - c = (guchar *)text; - s = 0; - while (s < len) { - if ((s <= (len - 8)) && - (c[s ] == '\\') && - (c[s + 1] == 'U' ) && - (c[s + 2] == '+' ) && - isxdigit (c[s + 3]) && - isxdigit (c[s + 4]) && - isxdigit (c[s + 5]) && - isxdigit (c[s + 6]) && - (c[s + 7] == '\\')) { - /* Valid \U+XXXX\ sequence */ - gint unival; - unival = strtol ((gchar *)(c + s + 3), NULL, 16); - d += e_unichar_to_utf8 (unival, d); - s += 8; - } else if (c[s] > 127) { - /* fixme: We assume iso-8859-1 currently */ - d += e_unichar_to_utf8 (c[s], d); - s += 1; - } else { - *d++ = c[s++]; - } - } - *d++ = '\0'; - u = g_realloc (u, (d - u)); - - return u; -} - -gchar * -e_utf8_xml1_encode (const gchar *text) -{ - gchar *u, *d, *c; - guint unival; - gint len; - - g_return_val_if_fail (text != NULL, NULL); - - len = 0; - for (u = e_unicode_get_utf8 (text, &unival); u && unival; u = e_unicode_get_utf8 (u, &unival)) { - if ((unival >= 0x80) || (unival == '\\')) { - len += 8; - } else { - len += 1; - } - } - d = c = (gchar *)g_new (guchar, len + 1); - - for (u = e_unicode_get_utf8 (text, &unival); u && unival; u = e_unicode_get_utf8 (u, &unival)) { - if ((unival >= 0x80) || (unival == '\\')) { - *c++ = '\\'; - *c++ = 'U'; - *c++ = '+'; - c += sprintf (c, "%04x", unival); - *c++ = '\\'; - } else { - *c++ = unival; - } - } - *c = '\0'; - - return d; -} - -/** - * e_unichar_to_utf8: - * @c: a ISO10646 character code - * @outbuf: output buffer, must have at least 6 bytes of space. - * If %NULL, the length will be computed and returned - * and nothing will be written to @out. - * - * Convert a single character to utf8 - * - * Return value: number of bytes written - **/ - -gint -e_unichar_to_utf8 (gint c, gchar *outbuf) -{ - gsize len = 0; - gint first; - gint i; - - if (c < 0x80) - { - first = 0; - len = 1; - } - else if (c < 0x800) - { - first = 0xc0; - len = 2; - } - else if (c < 0x10000) - { - first = 0xe0; - len = 3; - } - else if (c < 0x200000) - { - first = 0xf0; - len = 4; - } - else if (c < 0x4000000) - { - first = 0xf8; - len = 5; - } - else - { - first = 0xfc; - len = 6; - } - - if (outbuf) - { - for (i = len - 1; i > 0; --i) - { - outbuf[i] = (c & 0x3f) | 0x80; - c >>= 6; - } - outbuf[0] = c | first; - } - - return len; -} - -gchar * -e_unicode_get_utf8 (const gchar *text, gunichar *out) -{ - *out = g_utf8_get_char (text); - return (*out == (gunichar)-1) ? NULL : g_utf8_next_char (text); -} - -/* - * Canonical decomposition - * - * It is copied here from libunicode, because we do not want malloc - * - */ - -typedef struct -{ - gushort ch; - const gchar *expansion; -} e_decomposition; - -static e_decomposition e_decomp_table[] = -{ - { 0x00c0, "\x00\x41\x03\x00\0" }, - { 0x00c1, "\x00\x41\x03\x01\0" }, - { 0x00c2, "\x00\x41\x03\x02\0" }, - { 0x00c3, "\x00\x41\x03\x03\0" }, - { 0x00c4, "\x00\x41\x03\x08\0" }, - { 0x00c5, "\x00\x41\x03\x0a\0" }, - { 0x00c7, "\x00\x43\x03\x27\0" }, - { 0x00c8, "\x00\x45\x03\x00\0" }, - { 0x00c9, "\x00\x45\x03\x01\0" }, - { 0x00ca, "\x00\x45\x03\x02\0" }, - { 0x00cb, "\x00\x45\x03\x08\0" }, - { 0x00cc, "\x00\x49\x03\x00\0" }, - { 0x00cd, "\x00\x49\x03\x01\0" }, - { 0x00ce, "\x00\x49\x03\x02\0" }, - { 0x00cf, "\x00\x49\x03\x08\0" }, - { 0x00d1, "\x00\x4e\x03\x03\0" }, - { 0x00d2, "\x00\x4f\x03\x00\0" }, - { 0x00d3, "\x00\x4f\x03\x01\0" }, - { 0x00d4, "\x00\x4f\x03\x02\0" }, - { 0x00d5, "\x00\x4f\x03\x03\0" }, - { 0x00d6, "\x00\x4f\x03\x08\0" }, - { 0x00d9, "\x00\x55\x03\x00\0" }, - { 0x00da, "\x00\x55\x03\x01\0" }, - { 0x00db, "\x00\x55\x03\x02\0" }, - { 0x00dc, "\x00\x55\x03\x08\0" }, - { 0x00dd, "\x00\x59\x03\x01\0" }, - { 0x00e0, "\x00\x61\x03\x00\0" }, - { 0x00e1, "\x00\x61\x03\x01\0" }, - { 0x00e2, "\x00\x61\x03\x02\0" }, - { 0x00e3, "\x00\x61\x03\x03\0" }, - { 0x00e4, "\x00\x61\x03\x08\0" }, - { 0x00e5, "\x00\x61\x03\x0a\0" }, - { 0x00e7, "\x00\x63\x03\x27\0" }, - { 0x00e8, "\x00\x65\x03\x00\0" }, - { 0x00e9, "\x00\x65\x03\x01\0" }, - { 0x00ea, "\x00\x65\x03\x02\0" }, - { 0x00eb, "\x00\x65\x03\x08\0" }, - { 0x00ec, "\x00\x69\x03\x00\0" }, - { 0x00ed, "\x00\x69\x03\x01\0" }, - { 0x00ee, "\x00\x69\x03\x02\0" }, - { 0x00ef, "\x00\x69\x03\x08\0" }, - { 0x00f1, "\x00\x6e\x03\x03\0" }, - { 0x00f2, "\x00\x6f\x03\x00\0" }, - { 0x00f3, "\x00\x6f\x03\x01\0" }, - { 0x00f4, "\x00\x6f\x03\x02\0" }, - { 0x00f5, "\x00\x6f\x03\x03\0" }, - { 0x00f6, "\x00\x6f\x03\x08\0" }, - { 0x00f9, "\x00\x75\x03\x00\0" }, - { 0x00fa, "\x00\x75\x03\x01\0" }, - { 0x00fb, "\x00\x75\x03\x02\0" }, - { 0x00fc, "\x00\x75\x03\x08\0" }, - { 0x00fd, "\x00\x79\x03\x01\0" }, - { 0x00ff, "\x00\x79\x03\x08\0" }, - { 0x0100, "\x00\x41\x03\x04\0" }, - { 0x0101, "\x00\x61\x03\x04\0" }, - { 0x0102, "\x00\x41\x03\x06\0" }, - { 0x0103, "\x00\x61\x03\x06\0" }, - { 0x0104, "\x00\x41\x03\x28\0" }, - { 0x0105, "\x00\x61\x03\x28\0" }, - { 0x0106, "\x00\x43\x03\x01\0" }, - { 0x0107, "\x00\x63\x03\x01\0" }, - { 0x0108, "\x00\x43\x03\x02\0" }, - { 0x0109, "\x00\x63\x03\x02\0" }, - { 0x010a, "\x00\x43\x03\x07\0" }, - { 0x010b, "\x00\x63\x03\x07\0" }, - { 0x010c, "\x00\x43\x03\x0c\0" }, - { 0x010d, "\x00\x63\x03\x0c\0" }, - { 0x010e, "\x00\x44\x03\x0c\0" }, - { 0x010f, "\x00\x64\x03\x0c\0" }, - { 0x0112, "\x00\x45\x03\x04\0" }, - { 0x0113, "\x00\x65\x03\x04\0" }, - { 0x0114, "\x00\x45\x03\x06\0" }, - { 0x0115, "\x00\x65\x03\x06\0" }, - { 0x0116, "\x00\x45\x03\x07\0" }, - { 0x0117, "\x00\x65\x03\x07\0" }, - { 0x0118, "\x00\x45\x03\x28\0" }, - { 0x0119, "\x00\x65\x03\x28\0" }, - { 0x011a, "\x00\x45\x03\x0c\0" }, - { 0x011b, "\x00\x65\x03\x0c\0" }, - { 0x011c, "\x00\x47\x03\x02\0" }, - { 0x011d, "\x00\x67\x03\x02\0" }, - { 0x011e, "\x00\x47\x03\x06\0" }, - { 0x011f, "\x00\x67\x03\x06\0" }, - { 0x0120, "\x00\x47\x03\x07\0" }, - { 0x0121, "\x00\x67\x03\x07\0" }, - { 0x0122, "\x00\x47\x03\x27\0" }, - { 0x0123, "\x00\x67\x03\x27\0" }, - { 0x0124, "\x00\x48\x03\x02\0" }, - { 0x0125, "\x00\x68\x03\x02\0" }, - { 0x0128, "\x00\x49\x03\x03\0" }, - { 0x0129, "\x00\x69\x03\x03\0" }, - { 0x012a, "\x00\x49\x03\x04\0" }, - { 0x012b, "\x00\x69\x03\x04\0" }, - { 0x012c, "\x00\x49\x03\x06\0" }, - { 0x012d, "\x00\x69\x03\x06\0" }, - { 0x012e, "\x00\x49\x03\x28\0" }, - { 0x012f, "\x00\x69\x03\x28\0" }, - { 0x0130, "\x00\x49\x03\x07\0" }, - { 0x0134, "\x00\x4a\x03\x02\0" }, - { 0x0135, "\x00\x6a\x03\x02\0" }, - { 0x0136, "\x00\x4b\x03\x27\0" }, - { 0x0137, "\x00\x6b\x03\x27\0" }, - { 0x0139, "\x00\x4c\x03\x01\0" }, - { 0x013a, "\x00\x6c\x03\x01\0" }, - { 0x013b, "\x00\x4c\x03\x27\0" }, - { 0x013c, "\x00\x6c\x03\x27\0" }, - { 0x013d, "\x00\x4c\x03\x0c\0" }, - { 0x013e, "\x00\x6c\x03\x0c\0" }, - { 0x0143, "\x00\x4e\x03\x01\0" }, - { 0x0144, "\x00\x6e\x03\x01\0" }, - { 0x0145, "\x00\x4e\x03\x27\0" }, - { 0x0146, "\x00\x6e\x03\x27\0" }, - { 0x0147, "\x00\x4e\x03\x0c\0" }, - { 0x0148, "\x00\x6e\x03\x0c\0" }, - { 0x014c, "\x00\x4f\x03\x04\0" }, - { 0x014d, "\x00\x6f\x03\x04\0" }, - { 0x014e, "\x00\x4f\x03\x06\0" }, - { 0x014f, "\x00\x6f\x03\x06\0" }, - { 0x0150, "\x00\x4f\x03\x0b\0" }, - { 0x0151, "\x00\x6f\x03\x0b\0" }, - { 0x0154, "\x00\x52\x03\x01\0" }, - { 0x0155, "\x00\x72\x03\x01\0" }, - { 0x0156, "\x00\x52\x03\x27\0" }, - { 0x0157, "\x00\x72\x03\x27\0" }, - { 0x0158, "\x00\x52\x03\x0c\0" }, - { 0x0159, "\x00\x72\x03\x0c\0" }, - { 0x015a, "\x00\x53\x03\x01\0" }, - { 0x015b, "\x00\x73\x03\x01\0" }, - { 0x015c, "\x00\x53\x03\x02\0" }, - { 0x015d, "\x00\x73\x03\x02\0" }, - { 0x015e, "\x00\x53\x03\x27\0" }, - { 0x015f, "\x00\x73\x03\x27\0" }, - { 0x0160, "\x00\x53\x03\x0c\0" }, - { 0x0161, "\x00\x73\x03\x0c\0" }, - { 0x0162, "\x00\x54\x03\x27\0" }, - { 0x0163, "\x00\x74\x03\x27\0" }, - { 0x0164, "\x00\x54\x03\x0c\0" }, - { 0x0165, "\x00\x74\x03\x0c\0" }, - { 0x0168, "\x00\x55\x03\x03\0" }, - { 0x0169, "\x00\x75\x03\x03\0" }, - { 0x016a, "\x00\x55\x03\x04\0" }, - { 0x016b, "\x00\x75\x03\x04\0" }, - { 0x016c, "\x00\x55\x03\x06\0" }, - { 0x016d, "\x00\x75\x03\x06\0" }, - { 0x016e, "\x00\x55\x03\x0a\0" }, - { 0x016f, "\x00\x75\x03\x0a\0" }, - { 0x0170, "\x00\x55\x03\x0b\0" }, - { 0x0171, "\x00\x75\x03\x0b\0" }, - { 0x0172, "\x00\x55\x03\x28\0" }, - { 0x0173, "\x00\x75\x03\x28\0" }, - { 0x0174, "\x00\x57\x03\x02\0" }, - { 0x0175, "\x00\x77\x03\x02\0" }, - { 0x0176, "\x00\x59\x03\x02\0" }, - { 0x0177, "\x00\x79\x03\x02\0" }, - { 0x0178, "\x00\x59\x03\x08\0" }, - { 0x0179, "\x00\x5a\x03\x01\0" }, - { 0x017a, "\x00\x7a\x03\x01\0" }, - { 0x017b, "\x00\x5a\x03\x07\0" }, - { 0x017c, "\x00\x7a\x03\x07\0" }, - { 0x017d, "\x00\x5a\x03\x0c\0" }, - { 0x017e, "\x00\x7a\x03\x0c\0" }, - { 0x01a0, "\x00\x4f\x03\x1b\0" }, - { 0x01a1, "\x00\x6f\x03\x1b\0" }, - { 0x01af, "\x00\x55\x03\x1b\0" }, - { 0x01b0, "\x00\x75\x03\x1b\0" }, - { 0x01cd, "\x00\x41\x03\x0c\0" }, - { 0x01ce, "\x00\x61\x03\x0c\0" }, - { 0x01cf, "\x00\x49\x03\x0c\0" }, - { 0x01d0, "\x00\x69\x03\x0c\0" }, - { 0x01d1, "\x00\x4f\x03\x0c\0" }, - { 0x01d2, "\x00\x6f\x03\x0c\0" }, - { 0x01d3, "\x00\x55\x03\x0c\0" }, - { 0x01d4, "\x00\x75\x03\x0c\0" }, - { 0x01d5, "\x00\x55\x03\x08\x03\x04\0" }, - { 0x01d6, "\x00\x75\x03\x08\x03\x04\0" }, - { 0x01d7, "\x00\x55\x03\x08\x03\x01\0" }, - { 0x01d8, "\x00\x75\x03\x08\x03\x01\0" }, - { 0x01d9, "\x00\x55\x03\x08\x03\x0c\0" }, - { 0x01da, "\x00\x75\x03\x08\x03\x0c\0" }, - { 0x01db, "\x00\x55\x03\x08\x03\x00\0" }, - { 0x01dc, "\x00\x75\x03\x08\x03\x00\0" }, - { 0x01de, "\x00\x41\x03\x08\x03\x04\0" }, - { 0x01df, "\x00\x61\x03\x08\x03\x04\0" }, - { 0x01e0, "\x00\x41\x03\x07\x03\x04\0" }, - { 0x01e1, "\x00\x61\x03\x07\x03\x04\0" }, - { 0x01e2, "\x00\xc6\x03\x04\0" }, - { 0x01e3, "\x00\xe6\x03\x04\0" }, - { 0x01e6, "\x00\x47\x03\x0c\0" }, - { 0x01e7, "\x00\x67\x03\x0c\0" }, - { 0x01e8, "\x00\x4b\x03\x0c\0" }, - { 0x01e9, "\x00\x6b\x03\x0c\0" }, - { 0x01ea, "\x00\x4f\x03\x28\0" }, - { 0x01eb, "\x00\x6f\x03\x28\0" }, - { 0x01ec, "\x00\x4f\x03\x28\x03\x04\0" }, - { 0x01ed, "\x00\x6f\x03\x28\x03\x04\0" }, - { 0x01ee, "\x01\xb7\x03\x0c\0" }, - { 0x01ef, "\x02\x92\x03\x0c\0" }, - { 0x01f0, "\x00\x6a\x03\x0c\0" }, - { 0x01f4, "\x00\x47\x03\x01\0" }, - { 0x01f5, "\x00\x67\x03\x01\0" }, - { 0x01fa, "\x00\x41\x03\x0a\x03\x01\0" }, - { 0x01fb, "\x00\x61\x03\x0a\x03\x01\0" }, - { 0x01fc, "\x00\xc6\x03\x01\0" }, - { 0x01fd, "\x00\xe6\x03\x01\0" }, - { 0x01fe, "\x00\xd8\x03\x01\0" }, - { 0x01ff, "\x00\xf8\x03\x01\0" }, - { 0x0200, "\x00\x41\x03\x0f\0" }, - { 0x0201, "\x00\x61\x03\x0f\0" }, - { 0x0202, "\x00\x41\x03\x11\0" }, - { 0x0203, "\x00\x61\x03\x11\0" }, - { 0x0204, "\x00\x45\x03\x0f\0" }, - { 0x0205, "\x00\x65\x03\x0f\0" }, - { 0x0206, "\x00\x45\x03\x11\0" }, - { 0x0207, "\x00\x65\x03\x11\0" }, - { 0x0208, "\x00\x49\x03\x0f\0" }, - { 0x0209, "\x00\x69\x03\x0f\0" }, - { 0x020a, "\x00\x49\x03\x11\0" }, - { 0x020b, "\x00\x69\x03\x11\0" }, - { 0x020c, "\x00\x4f\x03\x0f\0" }, - { 0x020d, "\x00\x6f\x03\x0f\0" }, - { 0x020e, "\x00\x4f\x03\x11\0" }, - { 0x020f, "\x00\x6f\x03\x11\0" }, - { 0x0210, "\x00\x52\x03\x0f\0" }, - { 0x0211, "\x00\x72\x03\x0f\0" }, - { 0x0212, "\x00\x52\x03\x11\0" }, - { 0x0213, "\x00\x72\x03\x11\0" }, - { 0x0214, "\x00\x55\x03\x0f\0" }, - { 0x0215, "\x00\x75\x03\x0f\0" }, - { 0x0216, "\x00\x55\x03\x11\0" }, - { 0x0217, "\x00\x75\x03\x11\0" }, - { 0x0340, "\x03\x00\0" }, - { 0x0341, "\x03\x01\0" }, - { 0x0343, "\x03\x13\0" }, - { 0x0344, "\x03\x08\x03\x01\0" }, - { 0x0374, "\x02\xb9\0" }, - { 0x037e, "\x00\x3b\0" }, - { 0x0385, "\x00\xa8\x03\x01\0" }, - { 0x0386, "\x03\x91\x03\x01\0" }, - { 0x0387, "\x00\xb7\0" }, - { 0x0388, "\x03\x95\x03\x01\0" }, - { 0x0389, "\x03\x97\x03\x01\0" }, - { 0x038a, "\x03\x99\x03\x01\0" }, - { 0x038c, "\x03\x9f\x03\x01\0" }, - { 0x038e, "\x03\xa5\x03\x01\0" }, - { 0x038f, "\x03\xa9\x03\x01\0" }, - { 0x0390, "\x03\xb9\x03\x08\x03\x01\0" }, - { 0x03aa, "\x03\x99\x03\x08\0" }, - { 0x03ab, "\x03\xa5\x03\x08\0" }, - { 0x03ac, "\x03\xb1\x03\x01\0" }, - { 0x03ad, "\x03\xb5\x03\x01\0" }, - { 0x03ae, "\x03\xb7\x03\x01\0" }, - { 0x03af, "\x03\xb9\x03\x01\0" }, - { 0x03b0, "\x03\xc5\x03\x08\x03\x01\0" }, - { 0x03ca, "\x03\xb9\x03\x08\0" }, - { 0x03cb, "\x03\xc5\x03\x08\0" }, - { 0x03cc, "\x03\xbf\x03\x01\0" }, - { 0x03cd, "\x03\xc5\x03\x01\0" }, - { 0x03ce, "\x03\xc9\x03\x01\0" }, - { 0x03d3, "\x03\xd2\x03\x01\0" }, - { 0x03d4, "\x03\xd2\x03\x08\0" }, - { 0x0401, "\x04\x15\x03\x08\0" }, - { 0x0403, "\x04\x13\x03\x01\0" }, - { 0x0407, "\x04\x06\x03\x08\0" }, - { 0x040c, "\x04\x1a\x03\x01\0" }, - { 0x040e, "\x04\x23\x03\x06\0" }, - { 0x0419, "\x04\x18\x03\x06\0" }, - { 0x0439, "\x04\x38\x03\x06\0" }, - { 0x0451, "\x04\x35\x03\x08\0" }, - { 0x0453, "\x04\x33\x03\x01\0" }, - { 0x0457, "\x04\x56\x03\x08\0" }, - { 0x045c, "\x04\x3a\x03\x01\0" }, - { 0x045e, "\x04\x43\x03\x06\0" }, - { 0x0476, "\x04\x74\x03\x0f\0" }, - { 0x0477, "\x04\x75\x03\x0f\0" }, - { 0x04c1, "\x04\x16\x03\x06\0" }, - { 0x04c2, "\x04\x36\x03\x06\0" }, - { 0x04d0, "\x04\x10\x03\x06\0" }, - { 0x04d1, "\x04\x30\x03\x06\0" }, - { 0x04d2, "\x04\x10\x03\x08\0" }, - { 0x04d3, "\x04\x30\x03\x08\0" }, - { 0x04d6, "\x04\x15\x03\x06\0" }, - { 0x04d7, "\x04\x35\x03\x06\0" }, - { 0x04da, "\x04\xd8\x03\x08\0" }, - { 0x04db, "\x04\xd9\x03\x08\0" }, - { 0x04dc, "\x04\x16\x03\x08\0" }, - { 0x04dd, "\x04\x36\x03\x08\0" }, - { 0x04de, "\x04\x17\x03\x08\0" }, - { 0x04df, "\x04\x37\x03\x08\0" }, - { 0x04e2, "\x04\x18\x03\x04\0" }, - { 0x04e3, "\x04\x38\x03\x04\0" }, - { 0x04e4, "\x04\x18\x03\x08\0" }, - { 0x04e5, "\x04\x38\x03\x08\0" }, - { 0x04e6, "\x04\x1e\x03\x08\0" }, - { 0x04e7, "\x04\x3e\x03\x08\0" }, - { 0x04ea, "\x04\xe8\x03\x08\0" }, - { 0x04eb, "\x04\xe9\x03\x08\0" }, - { 0x04ee, "\x04\x23\x03\x04\0" }, - { 0x04ef, "\x04\x43\x03\x04\0" }, - { 0x04f0, "\x04\x23\x03\x08\0" }, - { 0x04f1, "\x04\x43\x03\x08\0" }, - { 0x04f2, "\x04\x23\x03\x0b\0" }, - { 0x04f3, "\x04\x43\x03\x0b\0" }, - { 0x04f4, "\x04\x27\x03\x08\0" }, - { 0x04f5, "\x04\x47\x03\x08\0" }, - { 0x04f8, "\x04\x2b\x03\x08\0" }, - { 0x04f9, "\x04\x4b\x03\x08\0" }, - { 0x0929, "\x09\x28\x09\x3c\0" }, - { 0x0931, "\x09\x30\x09\x3c\0" }, - { 0x0934, "\x09\x33\x09\x3c\0" }, - { 0x0958, "\x09\x15\x09\x3c\0" }, - { 0x0959, "\x09\x16\x09\x3c\0" }, - { 0x095a, "\x09\x17\x09\x3c\0" }, - { 0x095b, "\x09\x1c\x09\x3c\0" }, - { 0x095c, "\x09\x21\x09\x3c\0" }, - { 0x095d, "\x09\x22\x09\x3c\0" }, - { 0x095e, "\x09\x2b\x09\x3c\0" }, - { 0x095f, "\x09\x2f\x09\x3c\0" }, - { 0x09b0, "\x09\xac\x09\xbc\0" }, - { 0x09cb, "\x09\xc7\x09\xbe\0" }, - { 0x09cc, "\x09\xc7\x09\xd7\0" }, - { 0x09dc, "\x09\xa1\x09\xbc\0" }, - { 0x09dd, "\x09\xa2\x09\xbc\0" }, - { 0x09df, "\x09\xaf\x09\xbc\0" }, - { 0x0a59, "\x0a\x16\x0a\x3c\0" }, - { 0x0a5a, "\x0a\x17\x0a\x3c\0" }, - { 0x0a5b, "\x0a\x1c\x0a\x3c\0" }, - { 0x0a5c, "\x0a\x21\x0a\x3c\0" }, - { 0x0a5e, "\x0a\x2b\x0a\x3c\0" }, - { 0x0b48, "\x0b\x47\x0b\x56\0" }, - { 0x0b4b, "\x0b\x47\x0b\x3e\0" }, - { 0x0b4c, "\x0b\x47\x0b\x57\0" }, - { 0x0b5c, "\x0b\x21\x0b\x3c\0" }, - { 0x0b5d, "\x0b\x22\x0b\x3c\0" }, - { 0x0b5f, "\x0b\x2f\x0b\x3c\0" }, - { 0x0b94, "\x0b\x92\x0b\xd7\0" }, - { 0x0bca, "\x0b\xc6\x0b\xbe\0" }, - { 0x0bcb, "\x0b\xc7\x0b\xbe\0" }, - { 0x0bcc, "\x0b\xc6\x0b\xd7\0" }, - { 0x0c48, "\x0c\x46\x0c\x56\0" }, - { 0x0cc0, "\x0c\xbf\x0c\xd5\0" }, - { 0x0cc7, "\x0c\xc6\x0c\xd5\0" }, - { 0x0cc8, "\x0c\xc6\x0c\xd6\0" }, - { 0x0cca, "\x0c\xc6\x0c\xc2\0" }, - { 0x0ccb, "\x0c\xc6\x0c\xc2\x0c\xd5\0" }, - { 0x0d4a, "\x0d\x46\x0d\x3e\0" }, - { 0x0d4b, "\x0d\x47\x0d\x3e\0" }, - { 0x0d4c, "\x0d\x46\x0d\x57\0" }, - { 0x0e33, "\x0e\x4d\x0e\x32\0" }, - { 0x0eb3, "\x0e\xcd\x0e\xb2\0" }, - { 0x0f43, "\x0f\x42\x0f\xb7\0" }, - { 0x0f4d, "\x0f\x4c\x0f\xb7\0" }, - { 0x0f52, "\x0f\x51\x0f\xb7\0" }, - { 0x0f57, "\x0f\x56\x0f\xb7\0" }, - { 0x0f5c, "\x0f\x5b\x0f\xb7\0" }, - { 0x0f69, "\x0f\x40\x0f\xb5\0" }, - { 0x0f73, "\x0f\x71\x0f\x72\0" }, - { 0x0f75, "\x0f\x71\x0f\x74\0" }, - { 0x0f76, "\x0f\xb2\x0f\x80\0" }, - { 0x0f78, "\x0f\xb3\x0f\x80\0" }, - { 0x0f81, "\x0f\x71\x0f\x80\0" }, - { 0x0f93, "\x0f\x92\x0f\xb7\0" }, - { 0x0f9d, "\x0f\x9c\x0f\xb7\0" }, - { 0x0fa2, "\x0f\xa1\x0f\xb7\0" }, - { 0x0fa7, "\x0f\xa6\x0f\xb7\0" }, - { 0x0fac, "\x0f\xab\x0f\xb7\0" }, - { 0x0fb9, "\x0f\x90\x0f\xb5\0" }, - { 0x1e00, "\x00\x41\x03\x25\0" }, - { 0x1e01, "\x00\x61\x03\x25\0" }, - { 0x1e02, "\x00\x42\x03\x07\0" }, - { 0x1e03, "\x00\x62\x03\x07\0" }, - { 0x1e04, "\x00\x42\x03\x23\0" }, - { 0x1e05, "\x00\x62\x03\x23\0" }, - { 0x1e06, "\x00\x42\x03\x31\0" }, - { 0x1e07, "\x00\x62\x03\x31\0" }, - { 0x1e08, "\x00\x43\x03\x27\x03\x01\0" }, - { 0x1e09, "\x00\x63\x03\x27\x03\x01\0" }, - { 0x1e0a, "\x00\x44\x03\x07\0" }, - { 0x1e0b, "\x00\x64\x03\x07\0" }, - { 0x1e0c, "\x00\x44\x03\x23\0" }, - { 0x1e0d, "\x00\x64\x03\x23\0" }, - { 0x1e0e, "\x00\x44\x03\x31\0" }, - { 0x1e0f, "\x00\x64\x03\x31\0" }, - { 0x1e10, "\x00\x44\x03\x27\0" }, - { 0x1e11, "\x00\x64\x03\x27\0" }, - { 0x1e12, "\x00\x44\x03\x2d\0" }, - { 0x1e13, "\x00\x64\x03\x2d\0" }, - { 0x1e14, "\x00\x45\x03\x04\x03\x00\0" }, - { 0x1e15, "\x00\x65\x03\x04\x03\x00\0" }, - { 0x1e16, "\x00\x45\x03\x04\x03\x01\0" }, - { 0x1e17, "\x00\x65\x03\x04\x03\x01\0" }, - { 0x1e18, "\x00\x45\x03\x2d\0" }, - { 0x1e19, "\x00\x65\x03\x2d\0" }, - { 0x1e1a, "\x00\x45\x03\x30\0" }, - { 0x1e1b, "\x00\x65\x03\x30\0" }, - { 0x1e1c, "\x00\x45\x03\x27\x03\x06\0" }, - { 0x1e1d, "\x00\x65\x03\x27\x03\x06\0" }, - { 0x1e1e, "\x00\x46\x03\x07\0" }, - { 0x1e1f, "\x00\x66\x03\x07\0" }, - { 0x1e20, "\x00\x47\x03\x04\0" }, - { 0x1e21, "\x00\x67\x03\x04\0" }, - { 0x1e22, "\x00\x48\x03\x07\0" }, - { 0x1e23, "\x00\x68\x03\x07\0" }, - { 0x1e24, "\x00\x48\x03\x23\0" }, - { 0x1e25, "\x00\x68\x03\x23\0" }, - { 0x1e26, "\x00\x48\x03\x08\0" }, - { 0x1e27, "\x00\x68\x03\x08\0" }, - { 0x1e28, "\x00\x48\x03\x27\0" }, - { 0x1e29, "\x00\x68\x03\x27\0" }, - { 0x1e2a, "\x00\x48\x03\x2e\0" }, - { 0x1e2b, "\x00\x68\x03\x2e\0" }, - { 0x1e2c, "\x00\x49\x03\x30\0" }, - { 0x1e2d, "\x00\x69\x03\x30\0" }, - { 0x1e2e, "\x00\x49\x03\x08\x03\x01\0" }, - { 0x1e2f, "\x00\x69\x03\x08\x03\x01\0" }, - { 0x1e30, "\x00\x4b\x03\x01\0" }, - { 0x1e31, "\x00\x6b\x03\x01\0" }, - { 0x1e32, "\x00\x4b\x03\x23\0" }, - { 0x1e33, "\x00\x6b\x03\x23\0" }, - { 0x1e34, "\x00\x4b\x03\x31\0" }, - { 0x1e35, "\x00\x6b\x03\x31\0" }, - { 0x1e36, "\x00\x4c\x03\x23\0" }, - { 0x1e37, "\x00\x6c\x03\x23\0" }, - { 0x1e38, "\x00\x4c\x03\x23\x03\x04\0" }, - { 0x1e39, "\x00\x6c\x03\x23\x03\x04\0" }, - { 0x1e3a, "\x00\x4c\x03\x31\0" }, - { 0x1e3b, "\x00\x6c\x03\x31\0" }, - { 0x1e3c, "\x00\x4c\x03\x2d\0" }, - { 0x1e3d, "\x00\x6c\x03\x2d\0" }, - { 0x1e3e, "\x00\x4d\x03\x01\0" }, - { 0x1e3f, "\x00\x6d\x03\x01\0" }, - { 0x1e40, "\x00\x4d\x03\x07\0" }, - { 0x1e41, "\x00\x6d\x03\x07\0" }, - { 0x1e42, "\x00\x4d\x03\x23\0" }, - { 0x1e43, "\x00\x6d\x03\x23\0" }, - { 0x1e44, "\x00\x4e\x03\x07\0" }, - { 0x1e45, "\x00\x6e\x03\x07\0" }, - { 0x1e46, "\x00\x4e\x03\x23\0" }, - { 0x1e47, "\x00\x6e\x03\x23\0" }, - { 0x1e48, "\x00\x4e\x03\x31\0" }, - { 0x1e49, "\x00\x6e\x03\x31\0" }, - { 0x1e4a, "\x00\x4e\x03\x2d\0" }, - { 0x1e4b, "\x00\x6e\x03\x2d\0" }, - { 0x1e4c, "\x00\x4f\x03\x03\x03\x01\0" }, - { 0x1e4d, "\x00\x6f\x03\x03\x03\x01\0" }, - { 0x1e4e, "\x00\x4f\x03\x03\x03\x08\0" }, - { 0x1e4f, "\x00\x6f\x03\x03\x03\x08\0" }, - { 0x1e50, "\x00\x4f\x03\x04\x03\x00\0" }, - { 0x1e51, "\x00\x6f\x03\x04\x03\x00\0" }, - { 0x1e52, "\x00\x4f\x03\x04\x03\x01\0" }, - { 0x1e53, "\x00\x6f\x03\x04\x03\x01\0" }, - { 0x1e54, "\x00\x50\x03\x01\0" }, - { 0x1e55, "\x00\x70\x03\x01\0" }, - { 0x1e56, "\x00\x50\x03\x07\0" }, - { 0x1e57, "\x00\x70\x03\x07\0" }, - { 0x1e58, "\x00\x52\x03\x07\0" }, - { 0x1e59, "\x00\x72\x03\x07\0" }, - { 0x1e5a, "\x00\x52\x03\x23\0" }, - { 0x1e5b, "\x00\x72\x03\x23\0" }, - { 0x1e5c, "\x00\x52\x03\x23\x03\x04\0" }, - { 0x1e5d, "\x00\x72\x03\x23\x03\x04\0" }, - { 0x1e5e, "\x00\x52\x03\x31\0" }, - { 0x1e5f, "\x00\x72\x03\x31\0" }, - { 0x1e60, "\x00\x53\x03\x07\0" }, - { 0x1e61, "\x00\x73\x03\x07\0" }, - { 0x1e62, "\x00\x53\x03\x23\0" }, - { 0x1e63, "\x00\x73\x03\x23\0" }, - { 0x1e64, "\x00\x53\x03\x01\x03\x07\0" }, - { 0x1e65, "\x00\x73\x03\x01\x03\x07\0" }, - { 0x1e66, "\x00\x53\x03\x0c\x03\x07\0" }, - { 0x1e67, "\x00\x73\x03\x0c\x03\x07\0" }, - { 0x1e68, "\x00\x53\x03\x23\x03\x07\0" }, - { 0x1e69, "\x00\x73\x03\x23\x03\x07\0" }, - { 0x1e6a, "\x00\x54\x03\x07\0" }, - { 0x1e6b, "\x00\x74\x03\x07\0" }, - { 0x1e6c, "\x00\x54\x03\x23\0" }, - { 0x1e6d, "\x00\x74\x03\x23\0" }, - { 0x1e6e, "\x00\x54\x03\x31\0" }, - { 0x1e6f, "\x00\x74\x03\x31\0" }, - { 0x1e70, "\x00\x54\x03\x2d\0" }, - { 0x1e71, "\x00\x74\x03\x2d\0" }, - { 0x1e72, "\x00\x55\x03\x24\0" }, - { 0x1e73, "\x00\x75\x03\x24\0" }, - { 0x1e74, "\x00\x55\x03\x30\0" }, - { 0x1e75, "\x00\x75\x03\x30\0" }, - { 0x1e76, "\x00\x55\x03\x2d\0" }, - { 0x1e77, "\x00\x75\x03\x2d\0" }, - { 0x1e78, "\x00\x55\x03\x03\x03\x01\0" }, - { 0x1e79, "\x00\x75\x03\x03\x03\x01\0" }, - { 0x1e7a, "\x00\x55\x03\x04\x03\x08\0" }, - { 0x1e7b, "\x00\x75\x03\x04\x03\x08\0" }, - { 0x1e7c, "\x00\x56\x03\x03\0" }, - { 0x1e7d, "\x00\x76\x03\x03\0" }, - { 0x1e7e, "\x00\x56\x03\x23\0" }, - { 0x1e7f, "\x00\x76\x03\x23\0" }, - { 0x1e80, "\x00\x57\x03\x00\0" }, - { 0x1e81, "\x00\x77\x03\x00\0" }, - { 0x1e82, "\x00\x57\x03\x01\0" }, - { 0x1e83, "\x00\x77\x03\x01\0" }, - { 0x1e84, "\x00\x57\x03\x08\0" }, - { 0x1e85, "\x00\x77\x03\x08\0" }, - { 0x1e86, "\x00\x57\x03\x07\0" }, - { 0x1e87, "\x00\x77\x03\x07\0" }, - { 0x1e88, "\x00\x57\x03\x23\0" }, - { 0x1e89, "\x00\x77\x03\x23\0" }, - { 0x1e8a, "\x00\x58\x03\x07\0" }, - { 0x1e8b, "\x00\x78\x03\x07\0" }, - { 0x1e8c, "\x00\x58\x03\x08\0" }, - { 0x1e8d, "\x00\x78\x03\x08\0" }, - { 0x1e8e, "\x00\x59\x03\x07\0" }, - { 0x1e8f, "\x00\x79\x03\x07\0" }, - { 0x1e90, "\x00\x5a\x03\x02\0" }, - { 0x1e91, "\x00\x7a\x03\x02\0" }, - { 0x1e92, "\x00\x5a\x03\x23\0" }, - { 0x1e93, "\x00\x7a\x03\x23\0" }, - { 0x1e94, "\x00\x5a\x03\x31\0" }, - { 0x1e95, "\x00\x7a\x03\x31\0" }, - { 0x1e96, "\x00\x68\x03\x31\0" }, - { 0x1e97, "\x00\x74\x03\x08\0" }, - { 0x1e98, "\x00\x77\x03\x0a\0" }, - { 0x1e99, "\x00\x79\x03\x0a\0" }, - { 0x1e9b, "\x01\x7f\x03\x07\0" }, - { 0x1ea0, "\x00\x41\x03\x23\0" }, - { 0x1ea1, "\x00\x61\x03\x23\0" }, - { 0x1ea2, "\x00\x41\x03\x09\0" }, - { 0x1ea3, "\x00\x61\x03\x09\0" }, - { 0x1ea4, "\x00\x41\x03\x02\x03\x01\0" }, - { 0x1ea5, "\x00\x61\x03\x02\x03\x01\0" }, - { 0x1ea6, "\x00\x41\x03\x02\x03\x00\0" }, - { 0x1ea7, "\x00\x61\x03\x02\x03\x00\0" }, - { 0x1ea8, "\x00\x41\x03\x02\x03\x09\0" }, - { 0x1ea9, "\x00\x61\x03\x02\x03\x09\0" }, - { 0x1eaa, "\x00\x41\x03\x02\x03\x03\0" }, - { 0x1eab, "\x00\x61\x03\x02\x03\x03\0" }, - { 0x1eac, "\x00\x41\x03\x23\x03\x02\0" }, - { 0x1ead, "\x00\x61\x03\x23\x03\x02\0" }, - { 0x1eae, "\x00\x41\x03\x06\x03\x01\0" }, - { 0x1eaf, "\x00\x61\x03\x06\x03\x01\0" }, - { 0x1eb0, "\x00\x41\x03\x06\x03\x00\0" }, - { 0x1eb1, "\x00\x61\x03\x06\x03\x00\0" }, - { 0x1eb2, "\x00\x41\x03\x06\x03\x09\0" }, - { 0x1eb3, "\x00\x61\x03\x06\x03\x09\0" }, - { 0x1eb4, "\x00\x41\x03\x06\x03\x03\0" }, - { 0x1eb5, "\x00\x61\x03\x06\x03\x03\0" }, - { 0x1eb6, "\x00\x41\x03\x23\x03\x06\0" }, - { 0x1eb7, "\x00\x61\x03\x23\x03\x06\0" }, - { 0x1eb8, "\x00\x45\x03\x23\0" }, - { 0x1eb9, "\x00\x65\x03\x23\0" }, - { 0x1eba, "\x00\x45\x03\x09\0" }, - { 0x1ebb, "\x00\x65\x03\x09\0" }, - { 0x1ebc, "\x00\x45\x03\x03\0" }, - { 0x1ebd, "\x00\x65\x03\x03\0" }, - { 0x1ebe, "\x00\x45\x03\x02\x03\x01\0" }, - { 0x1ebf, "\x00\x65\x03\x02\x03\x01\0" }, - { 0x1ec0, "\x00\x45\x03\x02\x03\x00\0" }, - { 0x1ec1, "\x00\x65\x03\x02\x03\x00\0" }, - { 0x1ec2, "\x00\x45\x03\x02\x03\x09\0" }, - { 0x1ec3, "\x00\x65\x03\x02\x03\x09\0" }, - { 0x1ec4, "\x00\x45\x03\x02\x03\x03\0" }, - { 0x1ec5, "\x00\x65\x03\x02\x03\x03\0" }, - { 0x1ec6, "\x00\x45\x03\x23\x03\x02\0" }, - { 0x1ec7, "\x00\x65\x03\x23\x03\x02\0" }, - { 0x1ec8, "\x00\x49\x03\x09\0" }, - { 0x1ec9, "\x00\x69\x03\x09\0" }, - { 0x1eca, "\x00\x49\x03\x23\0" }, - { 0x1ecb, "\x00\x69\x03\x23\0" }, - { 0x1ecc, "\x00\x4f\x03\x23\0" }, - { 0x1ecd, "\x00\x6f\x03\x23\0" }, - { 0x1ece, "\x00\x4f\x03\x09\0" }, - { 0x1ecf, "\x00\x6f\x03\x09\0" }, - { 0x1ed0, "\x00\x4f\x03\x02\x03\x01\0" }, - { 0x1ed1, "\x00\x6f\x03\x02\x03\x01\0" }, - { 0x1ed2, "\x00\x4f\x03\x02\x03\x00\0" }, - { 0x1ed3, "\x00\x6f\x03\x02\x03\x00\0" }, - { 0x1ed4, "\x00\x4f\x03\x02\x03\x09\0" }, - { 0x1ed5, "\x00\x6f\x03\x02\x03\x09\0" }, - { 0x1ed6, "\x00\x4f\x03\x02\x03\x03\0" }, - { 0x1ed7, "\x00\x6f\x03\x02\x03\x03\0" }, - { 0x1ed8, "\x00\x4f\x03\x23\x03\x02\0" }, - { 0x1ed9, "\x00\x6f\x03\x23\x03\x02\0" }, - { 0x1eda, "\x00\x4f\x03\x1b\x03\x01\0" }, - { 0x1edb, "\x00\x6f\x03\x1b\x03\x01\0" }, - { 0x1edc, "\x00\x4f\x03\x1b\x03\x00\0" }, - { 0x1edd, "\x00\x6f\x03\x1b\x03\x00\0" }, - { 0x1ede, "\x00\x4f\x03\x1b\x03\x09\0" }, - { 0x1edf, "\x00\x6f\x03\x1b\x03\x09\0" }, - { 0x1ee0, "\x00\x4f\x03\x1b\x03\x03\0" }, - { 0x1ee1, "\x00\x6f\x03\x1b\x03\x03\0" }, - { 0x1ee2, "\x00\x4f\x03\x1b\x03\x23\0" }, - { 0x1ee3, "\x00\x6f\x03\x1b\x03\x23\0" }, - { 0x1ee4, "\x00\x55\x03\x23\0" }, - { 0x1ee5, "\x00\x75\x03\x23\0" }, - { 0x1ee6, "\x00\x55\x03\x09\0" }, - { 0x1ee7, "\x00\x75\x03\x09\0" }, - { 0x1ee8, "\x00\x55\x03\x1b\x03\x01\0" }, - { 0x1ee9, "\x00\x75\x03\x1b\x03\x01\0" }, - { 0x1eea, "\x00\x55\x03\x1b\x03\x00\0" }, - { 0x1eeb, "\x00\x75\x03\x1b\x03\x00\0" }, - { 0x1eec, "\x00\x55\x03\x1b\x03\x09\0" }, - { 0x1eed, "\x00\x75\x03\x1b\x03\x09\0" }, - { 0x1eee, "\x00\x55\x03\x1b\x03\x03\0" }, - { 0x1eef, "\x00\x75\x03\x1b\x03\x03\0" }, - { 0x1ef0, "\x00\x55\x03\x1b\x03\x23\0" }, - { 0x1ef1, "\x00\x75\x03\x1b\x03\x23\0" }, - { 0x1ef2, "\x00\x59\x03\x00\0" }, - { 0x1ef3, "\x00\x79\x03\x00\0" }, - { 0x1ef4, "\x00\x59\x03\x23\0" }, - { 0x1ef5, "\x00\x79\x03\x23\0" }, - { 0x1ef6, "\x00\x59\x03\x09\0" }, - { 0x1ef7, "\x00\x79\x03\x09\0" }, - { 0x1ef8, "\x00\x59\x03\x03\0" }, - { 0x1ef9, "\x00\x79\x03\x03\0" }, - { 0x1f00, "\x03\xb1\x03\x13\0" }, - { 0x1f01, "\x03\xb1\x03\x14\0" }, - { 0x1f02, "\x03\xb1\x03\x13\x03\x00\0" }, - { 0x1f03, "\x03\xb1\x03\x14\x03\x00\0" }, - { 0x1f04, "\x03\xb1\x03\x13\x03\x01\0" }, - { 0x1f05, "\x03\xb1\x03\x14\x03\x01\0" }, - { 0x1f06, "\x03\xb1\x03\x13\x03\x42\0" }, - { 0x1f07, "\x03\xb1\x03\x14\x03\x42\0" }, - { 0x1f08, "\x03\x91\x03\x13\0" }, - { 0x1f09, "\x03\x91\x03\x14\0" }, - { 0x1f0a, "\x03\x91\x03\x13\x03\x00\0" }, - { 0x1f0b, "\x03\x91\x03\x14\x03\x00\0" }, - { 0x1f0c, "\x03\x91\x03\x13\x03\x01\0" }, - { 0x1f0d, "\x03\x91\x03\x14\x03\x01\0" }, - { 0x1f0e, "\x03\x91\x03\x13\x03\x42\0" }, - { 0x1f0f, "\x03\x91\x03\x14\x03\x42\0" }, - { 0x1f10, "\x03\xb5\x03\x13\0" }, - { 0x1f11, "\x03\xb5\x03\x14\0" }, - { 0x1f12, "\x03\xb5\x03\x13\x03\x00\0" }, - { 0x1f13, "\x03\xb5\x03\x14\x03\x00\0" }, - { 0x1f14, "\x03\xb5\x03\x13\x03\x01\0" }, - { 0x1f15, "\x03\xb5\x03\x14\x03\x01\0" }, - { 0x1f18, "\x03\x95\x03\x13\0" }, - { 0x1f19, "\x03\x95\x03\x14\0" }, - { 0x1f1a, "\x03\x95\x03\x13\x03\x00\0" }, - { 0x1f1b, "\x03\x95\x03\x14\x03\x00\0" }, - { 0x1f1c, "\x03\x95\x03\x13\x03\x01\0" }, - { 0x1f1d, "\x03\x95\x03\x14\x03\x01\0" }, - { 0x1f20, "\x03\xb7\x03\x13\0" }, - { 0x1f21, "\x03\xb7\x03\x14\0" }, - { 0x1f22, "\x03\xb7\x03\x13\x03\x00\0" }, - { 0x1f23, "\x03\xb7\x03\x14\x03\x00\0" }, - { 0x1f24, "\x03\xb7\x03\x13\x03\x01\0" }, - { 0x1f25, "\x03\xb7\x03\x14\x03\x01\0" }, - { 0x1f26, "\x03\xb7\x03\x13\x03\x42\0" }, - { 0x1f27, "\x03\xb7\x03\x14\x03\x42\0" }, - { 0x1f28, "\x03\x97\x03\x13\0" }, - { 0x1f29, "\x03\x97\x03\x14\0" }, - { 0x1f2a, "\x03\x97\x03\x13\x03\x00\0" }, - { 0x1f2b, "\x03\x97\x03\x14\x03\x00\0" }, - { 0x1f2c, "\x03\x97\x03\x13\x03\x01\0" }, - { 0x1f2d, "\x03\x97\x03\x14\x03\x01\0" }, - { 0x1f2e, "\x03\x97\x03\x13\x03\x42\0" }, - { 0x1f2f, "\x03\x97\x03\x14\x03\x42\0" }, - { 0x1f30, "\x03\xb9\x03\x13\0" }, - { 0x1f31, "\x03\xb9\x03\x14\0" }, - { 0x1f32, "\x03\xb9\x03\x13\x03\x00\0" }, - { 0x1f33, "\x03\xb9\x03\x14\x03\x00\0" }, - { 0x1f34, "\x03\xb9\x03\x13\x03\x01\0" }, - { 0x1f35, "\x03\xb9\x03\x14\x03\x01\0" }, - { 0x1f36, "\x03\xb9\x03\x13\x03\x42\0" }, - { 0x1f37, "\x03\xb9\x03\x14\x03\x42\0" }, - { 0x1f38, "\x03\x99\x03\x13\0" }, - { 0x1f39, "\x03\x99\x03\x14\0" }, - { 0x1f3a, "\x03\x99\x03\x13\x03\x00\0" }, - { 0x1f3b, "\x03\x99\x03\x14\x03\x00\0" }, - { 0x1f3c, "\x03\x99\x03\x13\x03\x01\0" }, - { 0x1f3d, "\x03\x99\x03\x14\x03\x01\0" }, - { 0x1f3e, "\x03\x99\x03\x13\x03\x42\0" }, - { 0x1f3f, "\x03\x99\x03\x14\x03\x42\0" }, - { 0x1f40, "\x03\xbf\x03\x13\0" }, - { 0x1f41, "\x03\xbf\x03\x14\0" }, - { 0x1f42, "\x03\xbf\x03\x13\x03\x00\0" }, - { 0x1f43, "\x03\xbf\x03\x14\x03\x00\0" }, - { 0x1f44, "\x03\xbf\x03\x13\x03\x01\0" }, - { 0x1f45, "\x03\xbf\x03\x14\x03\x01\0" }, - { 0x1f48, "\x03\x9f\x03\x13\0" }, - { 0x1f49, "\x03\x9f\x03\x14\0" }, - { 0x1f4a, "\x03\x9f\x03\x13\x03\x00\0" }, - { 0x1f4b, "\x03\x9f\x03\x14\x03\x00\0" }, - { 0x1f4c, "\x03\x9f\x03\x13\x03\x01\0" }, - { 0x1f4d, "\x03\x9f\x03\x14\x03\x01\0" }, - { 0x1f50, "\x03\xc5\x03\x13\0" }, - { 0x1f51, "\x03\xc5\x03\x14\0" }, - { 0x1f52, "\x03\xc5\x03\x13\x03\x00\0" }, - { 0x1f53, "\x03\xc5\x03\x14\x03\x00\0" }, - { 0x1f54, "\x03\xc5\x03\x13\x03\x01\0" }, - { 0x1f55, "\x03\xc5\x03\x14\x03\x01\0" }, - { 0x1f56, "\x03\xc5\x03\x13\x03\x42\0" }, - { 0x1f57, "\x03\xc5\x03\x14\x03\x42\0" }, - { 0x1f59, "\x03\xa5\x03\x14\0" }, - { 0x1f5b, "\x03\xa5\x03\x14\x03\x00\0" }, - { 0x1f5d, "\x03\xa5\x03\x14\x03\x01\0" }, - { 0x1f5f, "\x03\xa5\x03\x14\x03\x42\0" }, - { 0x1f60, "\x03\xc9\x03\x13\0" }, - { 0x1f61, "\x03\xc9\x03\x14\0" }, - { 0x1f62, "\x03\xc9\x03\x13\x03\x00\0" }, - { 0x1f63, "\x03\xc9\x03\x14\x03\x00\0" }, - { 0x1f64, "\x03\xc9\x03\x13\x03\x01\0" }, - { 0x1f65, "\x03\xc9\x03\x14\x03\x01\0" }, - { 0x1f66, "\x03\xc9\x03\x13\x03\x42\0" }, - { 0x1f67, "\x03\xc9\x03\x14\x03\x42\0" }, - { 0x1f68, "\x03\xa9\x03\x13\0" }, - { 0x1f69, "\x03\xa9\x03\x14\0" }, - { 0x1f6a, "\x03\xa9\x03\x13\x03\x00\0" }, - { 0x1f6b, "\x03\xa9\x03\x14\x03\x00\0" }, - { 0x1f6c, "\x03\xa9\x03\x13\x03\x01\0" }, - { 0x1f6d, "\x03\xa9\x03\x14\x03\x01\0" }, - { 0x1f6e, "\x03\xa9\x03\x13\x03\x42\0" }, - { 0x1f6f, "\x03\xa9\x03\x14\x03\x42\0" }, - { 0x1f70, "\x03\xb1\x03\x00\0" }, - { 0x1f71, "\x03\xb1\x03\x01\0" }, - { 0x1f72, "\x03\xb5\x03\x00\0" }, - { 0x1f73, "\x03\xb5\x03\x01\0" }, - { 0x1f74, "\x03\xb7\x03\x00\0" }, - { 0x1f75, "\x03\xb7\x03\x01\0" }, - { 0x1f76, "\x03\xb9\x03\x00\0" }, - { 0x1f77, "\x03\xb9\x03\x01\0" }, - { 0x1f78, "\x03\xbf\x03\x00\0" }, - { 0x1f79, "\x03\xbf\x03\x01\0" }, - { 0x1f7a, "\x03\xc5\x03\x00\0" }, - { 0x1f7b, "\x03\xc5\x03\x01\0" }, - { 0x1f7c, "\x03\xc9\x03\x00\0" }, - { 0x1f7d, "\x03\xc9\x03\x01\0" }, - { 0x1f80, "\x03\xb1\x03\x13\x03\x45\0" }, - { 0x1f81, "\x03\xb1\x03\x14\x03\x45\0" }, - { 0x1f82, "\x03\xb1\x03\x13\x03\x00\x03\x45\0" }, - { 0x1f83, "\x03\xb1\x03\x14\x03\x00\x03\x45\0" }, - { 0x1f84, "\x03\xb1\x03\x13\x03\x01\x03\x45\0" }, - { 0x1f85, "\x03\xb1\x03\x14\x03\x01\x03\x45\0" }, - { 0x1f86, "\x03\xb1\x03\x13\x03\x42\x03\x45\0" }, - { 0x1f87, "\x03\xb1\x03\x14\x03\x42\x03\x45\0" }, - { 0x1f88, "\x03\x91\x03\x13\x03\x45\0" }, - { 0x1f89, "\x03\x91\x03\x14\x03\x45\0" }, - { 0x1f8a, "\x03\x91\x03\x13\x03\x00\x03\x45\0" }, - { 0x1f8b, "\x03\x91\x03\x14\x03\x00\x03\x45\0" }, - { 0x1f8c, "\x03\x91\x03\x13\x03\x01\x03\x45\0" }, - { 0x1f8d, "\x03\x91\x03\x14\x03\x01\x03\x45\0" }, - { 0x1f8e, "\x03\x91\x03\x13\x03\x42\x03\x45\0" }, - { 0x1f8f, "\x03\x91\x03\x14\x03\x42\x03\x45\0" }, - { 0x1f90, "\x03\xb7\x03\x13\x03\x45\0" }, - { 0x1f91, "\x03\xb7\x03\x14\x03\x45\0" }, - { 0x1f92, "\x03\xb7\x03\x13\x03\x00\x03\x45\0" }, - { 0x1f93, "\x03\xb7\x03\x14\x03\x00\x03\x45\0" }, - { 0x1f94, "\x03\xb7\x03\x13\x03\x01\x03\x45\0" }, - { 0x1f95, "\x03\xb7\x03\x14\x03\x01\x03\x45\0" }, - { 0x1f96, "\x03\xb7\x03\x13\x03\x42\x03\x45\0" }, - { 0x1f97, "\x03\xb7\x03\x14\x03\x42\x03\x45\0" }, - { 0x1f98, "\x03\x97\x03\x13\x03\x45\0" }, - { 0x1f99, "\x03\x97\x03\x14\x03\x45\0" }, - { 0x1f9a, "\x03\x97\x03\x13\x03\x00\x03\x45\0" }, - { 0x1f9b, "\x03\x97\x03\x14\x03\x00\x03\x45\0" }, - { 0x1f9c, "\x03\x97\x03\x13\x03\x01\x03\x45\0" }, - { 0x1f9d, "\x03\x97\x03\x14\x03\x01\x03\x45\0" }, - { 0x1f9e, "\x03\x97\x03\x13\x03\x42\x03\x45\0" }, - { 0x1f9f, "\x03\x97\x03\x14\x03\x42\x03\x45\0" }, - { 0x1fa0, "\x03\xc9\x03\x13\x03\x45\0" }, - { 0x1fa1, "\x03\xc9\x03\x14\x03\x45\0" }, - { 0x1fa2, "\x03\xc9\x03\x13\x03\x00\x03\x45\0" }, - { 0x1fa3, "\x03\xc9\x03\x14\x03\x00\x03\x45\0" }, - { 0x1fa4, "\x03\xc9\x03\x13\x03\x01\x03\x45\0" }, - { 0x1fa5, "\x03\xc9\x03\x14\x03\x01\x03\x45\0" }, - { 0x1fa6, "\x03\xc9\x03\x13\x03\x42\x03\x45\0" }, - { 0x1fa7, "\x03\xc9\x03\x14\x03\x42\x03\x45\0" }, - { 0x1fa8, "\x03\xa9\x03\x13\x03\x45\0" }, - { 0x1fa9, "\x03\xa9\x03\x14\x03\x45\0" }, - { 0x1faa, "\x03\xa9\x03\x13\x03\x00\x03\x45\0" }, - { 0x1fab, "\x03\xa9\x03\x14\x03\x00\x03\x45\0" }, - { 0x1fac, "\x03\xa9\x03\x13\x03\x01\x03\x45\0" }, - { 0x1fad, "\x03\xa9\x03\x14\x03\x01\x03\x45\0" }, - { 0x1fae, "\x03\xa9\x03\x13\x03\x42\x03\x45\0" }, - { 0x1faf, "\x03\xa9\x03\x14\x03\x42\x03\x45\0" }, - { 0x1fb0, "\x03\xb1\x03\x06\0" }, - { 0x1fb1, "\x03\xb1\x03\x04\0" }, - { 0x1fb2, "\x03\xb1\x03\x00\x03\x45\0" }, - { 0x1fb3, "\x03\xb1\x03\x45\0" }, - { 0x1fb4, "\x03\xb1\x03\x01\x03\x45\0" }, - { 0x1fb6, "\x03\xb1\x03\x42\0" }, - { 0x1fb7, "\x03\xb1\x03\x42\x03\x45\0" }, - { 0x1fb8, "\x03\x91\x03\x06\0" }, - { 0x1fb9, "\x03\x91\x03\x04\0" }, - { 0x1fba, "\x03\x91\x03\x00\0" }, - { 0x1fbb, "\x03\x91\x03\x01\0" }, - { 0x1fbc, "\x03\x91\x03\x45\0" }, - { 0x1fbe, "\x03\xb9\0" }, - { 0x1fc1, "\x00\xa8\x03\x42\0" }, - { 0x1fc2, "\x03\xb7\x03\x00\x03\x45\0" }, - { 0x1fc3, "\x03\xb7\x03\x45\0" }, - { 0x1fc4, "\x03\xb7\x03\x01\x03\x45\0" }, - { 0x1fc6, "\x03\xb7\x03\x42\0" }, - { 0x1fc7, "\x03\xb7\x03\x42\x03\x45\0" }, - { 0x1fc8, "\x03\x95\x03\x00\0" }, - { 0x1fc9, "\x03\x95\x03\x01\0" }, - { 0x1fca, "\x03\x97\x03\x00\0" }, - { 0x1fcb, "\x03\x97\x03\x01\0" }, - { 0x1fcc, "\x03\x97\x03\x45\0" }, - { 0x1fcd, "\x1f\xbf\x03\x00\0" }, - { 0x1fce, "\x1f\xbf\x03\x01\0" }, - { 0x1fcf, "\x1f\xbf\x03\x42\0" }, - { 0x1fd0, "\x03\xb9\x03\x06\0" }, - { 0x1fd1, "\x03\xb9\x03\x04\0" }, - { 0x1fd2, "\x03\xb9\x03\x08\x03\x00\0" }, - { 0x1fd3, "\x03\xb9\x03\x08\x03\x01\0" }, - { 0x1fd6, "\x03\xb9\x03\x42\0" }, - { 0x1fd7, "\x03\xb9\x03\x08\x03\x42\0" }, - { 0x1fd8, "\x03\x99\x03\x06\0" }, - { 0x1fd9, "\x03\x99\x03\x04\0" }, - { 0x1fda, "\x03\x99\x03\x00\0" }, - { 0x1fdb, "\x03\x99\x03\x01\0" }, - { 0x1fdd, "\x1f\xfe\x03\x00\0" }, - { 0x1fde, "\x1f\xfe\x03\x01\0" }, - { 0x1fdf, "\x1f\xfe\x03\x42\0" }, - { 0x1fe0, "\x03\xc5\x03\x06\0" }, - { 0x1fe1, "\x03\xc5\x03\x04\0" }, - { 0x1fe2, "\x03\xc5\x03\x08\x03\x00\0" }, - { 0x1fe3, "\x03\xc5\x03\x08\x03\x01\0" }, - { 0x1fe4, "\x03\xc1\x03\x13\0" }, - { 0x1fe5, "\x03\xc1\x03\x14\0" }, - { 0x1fe6, "\x03\xc5\x03\x42\0" }, - { 0x1fe7, "\x03\xc5\x03\x08\x03\x42\0" }, - { 0x1fe8, "\x03\xa5\x03\x06\0" }, - { 0x1fe9, "\x03\xa5\x03\x04\0" }, - { 0x1fea, "\x03\xa5\x03\x00\0" }, - { 0x1feb, "\x03\xa5\x03\x01\0" }, - { 0x1fec, "\x03\xa1\x03\x14\0" }, - { 0x1fed, "\x00\xa8\x03\x00\0" }, - { 0x1fee, "\x00\xa8\x03\x01\0" }, - { 0x1fef, "\x00\x60\0" }, - { 0x1ff2, "\x03\xc9\x03\x00\x03\x45\0" }, - { 0x1ff3, "\x03\xc9\x03\x45\0" }, - { 0x1ff4, "\x03\xc9\x03\x01\x03\x45\0" }, - { 0x1ff6, "\x03\xc9\x03\x42\0" }, - { 0x1ff7, "\x03\xc9\x03\x42\x03\x45\0" }, - { 0x1ff8, "\x03\x9f\x03\x00\0" }, - { 0x1ff9, "\x03\x9f\x03\x01\0" }, - { 0x1ffa, "\x03\xa9\x03\x00\0" }, - { 0x1ffb, "\x03\xa9\x03\x01\0" }, - { 0x1ffc, "\x03\xa9\x03\x45\0" }, - { 0x1ffd, "\x00\xb4\0" }, - { 0x2000, "\x20\x02\0" }, - { 0x2001, "\x20\x03\0" }, - { 0x2126, "\x03\xa9\0" }, - { 0x212a, "\x00\x4b\0" }, - { 0x212b, "\x00\x41\x03\x0a\0" }, - { 0x2204, "\x22\x03\x03\x38\0" }, - { 0x2209, "\x22\x08\x03\x38\0" }, - { 0x220c, "\x22\x0b\x03\x38\0" }, - { 0x2224, "\x22\x23\x03\x38\0" }, - { 0x2226, "\x22\x25\x03\x38\0" }, - { 0x2241, "\x00\x7e\x03\x38\0" }, - { 0x2244, "\x22\x43\x03\x38\0" }, - { 0x2247, "\x22\x45\x03\x38\0" }, - { 0x2249, "\x22\x48\x03\x38\0" }, - { 0x2260, "\x00\x3d\x03\x38\0" }, - { 0x2262, "\x22\x61\x03\x38\0" }, - { 0x226d, "\x22\x4d\x03\x38\0" }, - { 0x226e, "\x00\x3c\x03\x38\0" }, - { 0x226f, "\x00\x3e\x03\x38\0" }, - { 0x2270, "\x22\x64\x03\x38\0" }, - { 0x2271, "\x22\x65\x03\x38\0" }, - { 0x2274, "\x22\x72\x03\x38\0" }, - { 0x2275, "\x22\x73\x03\x38\0" }, - { 0x2278, "\x22\x76\x03\x38\0" }, - { 0x2279, "\x22\x77\x03\x38\0" }, - { 0x2280, "\x22\x7a\x03\x38\0" }, - { 0x2281, "\x22\x7b\x03\x38\0" }, - { 0x2284, "\x22\x82\x03\x38\0" }, - { 0x2285, "\x22\x83\x03\x38\0" }, - { 0x2288, "\x22\x86\x03\x38\0" }, - { 0x2289, "\x22\x87\x03\x38\0" }, - { 0x22ac, "\x22\xa2\x03\x38\0" }, - { 0x22ad, "\x22\xa8\x03\x38\0" }, - { 0x22ae, "\x22\xa9\x03\x38\0" }, - { 0x22af, "\x22\xab\x03\x38\0" }, - { 0x22e0, "\x22\x7c\x03\x38\0" }, - { 0x22e1, "\x22\x7d\x03\x38\0" }, - { 0x22e2, "\x22\x91\x03\x38\0" }, - { 0x22e3, "\x22\x92\x03\x38\0" }, - { 0x22ea, "\x22\xb2\x03\x38\0" }, - { 0x22eb, "\x22\xb3\x03\x38\0" }, - { 0x22ec, "\x22\xb4\x03\x38\0" }, - { 0x22ed, "\x22\xb5\x03\x38\0" }, - { 0x2329, "\x30\x08\0" }, - { 0x232a, "\x30\x09\0" }, - { 0x304c, "\x30\x4b\x30\x99\0" }, - { 0x304e, "\x30\x4d\x30\x99\0" }, - { 0x3050, "\x30\x4f\x30\x99\0" }, - { 0x3052, "\x30\x51\x30\x99\0" }, - { 0x3054, "\x30\x53\x30\x99\0" }, - { 0x3056, "\x30\x55\x30\x99\0" }, - { 0x3058, "\x30\x57\x30\x99\0" }, - { 0x305a, "\x30\x59\x30\x99\0" }, - { 0x305c, "\x30\x5b\x30\x99\0" }, - { 0x305e, "\x30\x5d\x30\x99\0" }, - { 0x3060, "\x30\x5f\x30\x99\0" }, - { 0x3062, "\x30\x61\x30\x99\0" }, - { 0x3065, "\x30\x64\x30\x99\0" }, - { 0x3067, "\x30\x66\x30\x99\0" }, - { 0x3069, "\x30\x68\x30\x99\0" }, - { 0x3070, "\x30\x6f\x30\x99\0" }, - { 0x3071, "\x30\x6f\x30\x9a\0" }, - { 0x3073, "\x30\x72\x30\x99\0" }, - { 0x3074, "\x30\x72\x30\x9a\0" }, - { 0x3076, "\x30\x75\x30\x99\0" }, - { 0x3077, "\x30\x75\x30\x9a\0" }, - { 0x3079, "\x30\x78\x30\x99\0" }, - { 0x307a, "\x30\x78\x30\x9a\0" }, - { 0x307c, "\x30\x7b\x30\x99\0" }, - { 0x307d, "\x30\x7b\x30\x9a\0" }, - { 0x3094, "\x30\x46\x30\x99\0" }, - { 0x309e, "\x30\x9d\x30\x99\0" }, - { 0x30ac, "\x30\xab\x30\x99\0" }, - { 0x30ae, "\x30\xad\x30\x99\0" }, - { 0x30b0, "\x30\xaf\x30\x99\0" }, - { 0x30b2, "\x30\xb1\x30\x99\0" }, - { 0x30b4, "\x30\xb3\x30\x99\0" }, - { 0x30b6, "\x30\xb5\x30\x99\0" }, - { 0x30b8, "\x30\xb7\x30\x99\0" }, - { 0x30ba, "\x30\xb9\x30\x99\0" }, - { 0x30bc, "\x30\xbb\x30\x99\0" }, - { 0x30be, "\x30\xbd\x30\x99\0" }, - { 0x30c0, "\x30\xbf\x30\x99\0" }, - { 0x30c2, "\x30\xc1\x30\x99\0" }, - { 0x30c5, "\x30\xc4\x30\x99\0" }, - { 0x30c7, "\x30\xc6\x30\x99\0" }, - { 0x30c9, "\x30\xc8\x30\x99\0" }, - { 0x30d0, "\x30\xcf\x30\x99\0" }, - { 0x30d1, "\x30\xcf\x30\x9a\0" }, - { 0x30d3, "\x30\xd2\x30\x99\0" }, - { 0x30d4, "\x30\xd2\x30\x9a\0" }, - { 0x30d6, "\x30\xd5\x30\x99\0" }, - { 0x30d7, "\x30\xd5\x30\x9a\0" }, - { 0x30d9, "\x30\xd8\x30\x99\0" }, - { 0x30da, "\x30\xd8\x30\x9a\0" }, - { 0x30dc, "\x30\xdb\x30\x99\0" }, - { 0x30dd, "\x30\xdb\x30\x9a\0" }, - { 0x30f4, "\x30\xa6\x30\x99\0" }, - { 0x30f7, "\x30\xef\x30\x99\0" }, - { 0x30f8, "\x30\xf0\x30\x99\0" }, - { 0x30f9, "\x30\xf1\x30\x99\0" }, - { 0x30fa, "\x30\xf2\x30\x99\0" }, - { 0x30fe, "\x30\xfd\x30\x99\0" }, - { 0xf900, "\x8c\x48\0" }, - { 0xf901, "\x66\xf4\0" }, - { 0xf902, "\x8e\xca\0" }, - { 0xf903, "\x8c\xc8\0" }, - { 0xf904, "\x6e\xd1\0" }, - { 0xf905, "\x4e\x32\0" }, - { 0xf906, "\x53\xe5\0" }, - { 0xf907, "\x9f\x9c\0" }, - { 0xf908, "\x9f\x9c\0" }, - { 0xf909, "\x59\x51\0" }, - { 0xf90a, "\x91\xd1\0" }, - { 0xf90b, "\x55\x87\0" }, - { 0xf90c, "\x59\x48\0" }, - { 0xf90d, "\x61\xf6\0" }, - { 0xf90e, "\x76\x69\0" }, - { 0xf90f, "\x7f\x85\0" }, - { 0xf910, "\x86\x3f\0" }, - { 0xf911, "\x87\xba\0" }, - { 0xf912, "\x88\xf8\0" }, - { 0xf913, "\x90\x8f\0" }, - { 0xf914, "\x6a\x02\0" }, - { 0xf915, "\x6d\x1b\0" }, - { 0xf916, "\x70\xd9\0" }, - { 0xf917, "\x73\xde\0" }, - { 0xf918, "\x84\x3d\0" }, - { 0xf919, "\x91\x6a\0" }, - { 0xf91a, "\x99\xf1\0" }, - { 0xf91b, "\x4e\x82\0" }, - { 0xf91c, "\x53\x75\0" }, - { 0xf91d, "\x6b\x04\0" }, - { 0xf91e, "\x72\x1b\0" }, - { 0xf91f, "\x86\x2d\0" }, - { 0xf920, "\x9e\x1e\0" }, - { 0xf921, "\x5d\x50\0" }, - { 0xf922, "\x6f\xeb\0" }, - { 0xf923, "\x85\xcd\0" }, - { 0xf924, "\x89\x64\0" }, - { 0xf925, "\x62\xc9\0" }, - { 0xf926, "\x81\xd8\0" }, - { 0xf927, "\x88\x1f\0" }, - { 0xf928, "\x5e\xca\0" }, - { 0xf929, "\x67\x17\0" }, - { 0xf92a, "\x6d\x6a\0" }, - { 0xf92b, "\x72\xfc\0" }, - { 0xf92c, "\x90\xce\0" }, - { 0xf92d, "\x4f\x86\0" }, - { 0xf92e, "\x51\xb7\0" }, - { 0xf92f, "\x52\xde\0" }, - { 0xf930, "\x64\xc4\0" }, - { 0xf931, "\x6a\xd3\0" }, - { 0xf932, "\x72\x10\0" }, - { 0xf933, "\x76\xe7\0" }, - { 0xf934, "\x80\x01\0" }, - { 0xf935, "\x86\x06\0" }, - { 0xf936, "\x86\x5c\0" }, - { 0xf937, "\x8d\xef\0" }, - { 0xf938, "\x97\x32\0" }, - { 0xf939, "\x9b\x6f\0" }, - { 0xf93a, "\x9d\xfa\0" }, - { 0xf93b, "\x78\x8c\0" }, - { 0xf93c, "\x79\x7f\0" }, - { 0xf93d, "\x7d\xa0\0" }, - { 0xf93e, "\x83\xc9\0" }, - { 0xf93f, "\x93\x04\0" }, - { 0xf940, "\x9e\x7f\0" }, - { 0xf941, "\x8a\xd6\0" }, - { 0xf942, "\x58\xdf\0" }, - { 0xf943, "\x5f\x04\0" }, - { 0xf944, "\x7c\x60\0" }, - { 0xf945, "\x80\x7e\0" }, - { 0xf946, "\x72\x62\0" }, - { 0xf947, "\x78\xca\0" }, - { 0xf948, "\x8c\xc2\0" }, - { 0xf949, "\x96\xf7\0" }, - { 0xf94a, "\x58\xd8\0" }, - { 0xf94b, "\x5c\x62\0" }, - { 0xf94c, "\x6a\x13\0" }, - { 0xf94d, "\x6d\xda\0" }, - { 0xf94e, "\x6f\x0f\0" }, - { 0xf94f, "\x7d\x2f\0" }, - { 0xf950, "\x7e\x37\0" }, - { 0xf951, "\x96\xfb\0" }, - { 0xf952, "\x52\xd2\0" }, - { 0xf953, "\x80\x8b\0" }, - { 0xf954, "\x51\xdc\0" }, - { 0xf955, "\x51\xcc\0" }, - { 0xf956, "\x7a\x1c\0" }, - { 0xf957, "\x7d\xbe\0" }, - { 0xf958, "\x83\xf1\0" }, - { 0xf959, "\x96\x75\0" }, - { 0xf95a, "\x8b\x80\0" }, - { 0xf95b, "\x62\xcf\0" }, - { 0xf95c, "\x6a\x02\0" }, - { 0xf95d, "\x8a\xfe\0" }, - { 0xf95e, "\x4e\x39\0" }, - { 0xf95f, "\x5b\xe7\0" }, - { 0xf960, "\x60\x12\0" }, - { 0xf961, "\x73\x87\0" }, - { 0xf962, "\x75\x70\0" }, - { 0xf963, "\x53\x17\0" }, - { 0xf964, "\x78\xfb\0" }, - { 0xf965, "\x4f\xbf\0" }, - { 0xf966, "\x5f\xa9\0" }, - { 0xf967, "\x4e\x0d\0" }, - { 0xf968, "\x6c\xcc\0" }, - { 0xf969, "\x65\x78\0" }, - { 0xf96a, "\x7d\x22\0" }, - { 0xf96b, "\x53\xc3\0" }, - { 0xf96c, "\x58\x5e\0" }, - { 0xf96d, "\x77\x01\0" }, - { 0xf96e, "\x84\x49\0" }, - { 0xf96f, "\x8a\xaa\0" }, - { 0xf970, "\x6b\xba\0" }, - { 0xf971, "\x8f\xb0\0" }, - { 0xf972, "\x6c\x88\0" }, - { 0xf973, "\x62\xfe\0" }, - { 0xf974, "\x82\xe5\0" }, - { 0xf975, "\x63\xa0\0" }, - { 0xf976, "\x75\x65\0" }, - { 0xf977, "\x4e\xae\0" }, - { 0xf978, "\x51\x69\0" }, - { 0xf979, "\x51\xc9\0" }, - { 0xf97a, "\x68\x81\0" }, - { 0xf97b, "\x7c\xe7\0" }, - { 0xf97c, "\x82\x6f\0" }, - { 0xf97d, "\x8a\xd2\0" }, - { 0xf97e, "\x91\xcf\0" }, - { 0xf97f, "\x52\xf5\0" }, - { 0xf980, "\x54\x42\0" }, - { 0xf981, "\x59\x73\0" }, - { 0xf982, "\x5e\xec\0" }, - { 0xf983, "\x65\xc5\0" }, - { 0xf984, "\x6f\xfe\0" }, - { 0xf985, "\x79\x2a\0" }, - { 0xf986, "\x95\xad\0" }, - { 0xf987, "\x9a\x6a\0" }, - { 0xf988, "\x9e\x97\0" }, - { 0xf989, "\x9e\xce\0" }, - { 0xf98a, "\x52\x9b\0" }, - { 0xf98b, "\x66\xc6\0" }, - { 0xf98c, "\x6b\x77\0" }, - { 0xf98d, "\x8f\x62\0" }, - { 0xf98e, "\x5e\x74\0" }, - { 0xf98f, "\x61\x90\0" }, - { 0xf990, "\x62\x00\0" }, - { 0xf991, "\x64\x9a\0" }, - { 0xf992, "\x6f\x23\0" }, - { 0xf993, "\x71\x49\0" }, - { 0xf994, "\x74\x89\0" }, - { 0xf995, "\x79\xca\0" }, - { 0xf996, "\x7d\xf4\0" }, - { 0xf997, "\x80\x6f\0" }, - { 0xf998, "\x8f\x26\0" }, - { 0xf999, "\x84\xee\0" }, - { 0xf99a, "\x90\x23\0" }, - { 0xf99b, "\x93\x4a\0" }, - { 0xf99c, "\x52\x17\0" }, - { 0xf99d, "\x52\xa3\0" }, - { 0xf99e, "\x54\xbd\0" }, - { 0xf99f, "\x70\xc8\0" }, - { 0xf9a0, "\x88\xc2\0" }, - { 0xf9a1, "\x8a\xaa\0" }, - { 0xf9a2, "\x5e\xc9\0" }, - { 0xf9a3, "\x5f\xf5\0" }, - { 0xf9a4, "\x63\x7b\0" }, - { 0xf9a5, "\x6b\xae\0" }, - { 0xf9a6, "\x7c\x3e\0" }, - { 0xf9a7, "\x73\x75\0" }, - { 0xf9a8, "\x4e\xe4\0" }, - { 0xf9a9, "\x56\xf9\0" }, - { 0xf9aa, "\x5b\xe7\0" }, - { 0xf9ab, "\x5d\xba\0" }, - { 0xf9ac, "\x60\x1c\0" }, - { 0xf9ad, "\x73\xb2\0" }, - { 0xf9ae, "\x74\x69\0" }, - { 0xf9af, "\x7f\x9a\0" }, - { 0xf9b0, "\x80\x46\0" }, - { 0xf9b1, "\x92\x34\0" }, - { 0xf9b2, "\x96\xf6\0" }, - { 0xf9b3, "\x97\x48\0" }, - { 0xf9b4, "\x98\x18\0" }, - { 0xf9b5, "\x4f\x8b\0" }, - { 0xf9b6, "\x79\xae\0" }, - { 0xf9b7, "\x91\xb4\0" }, - { 0xf9b8, "\x96\xb8\0" }, - { 0xf9b9, "\x60\xe1\0" }, - { 0xf9ba, "\x4e\x86\0" }, - { 0xf9bb, "\x50\xda\0" }, - { 0xf9bc, "\x5b\xee\0" }, - { 0xf9bd, "\x5c\x3f\0" }, - { 0xf9be, "\x65\x99\0" }, - { 0xf9bf, "\x6a\x02\0" }, - { 0xf9c0, "\x71\xce\0" }, - { 0xf9c1, "\x76\x42\0" }, - { 0xf9c2, "\x84\xfc\0" }, - { 0xf9c3, "\x90\x7c\0" }, - { 0xf9c4, "\x9f\x8d\0" }, - { 0xf9c5, "\x66\x88\0" }, - { 0xf9c6, "\x96\x2e\0" }, - { 0xf9c7, "\x52\x89\0" }, - { 0xf9c8, "\x67\x7b\0" }, - { 0xf9c9, "\x67\xf3\0" }, - { 0xf9ca, "\x6d\x41\0" }, - { 0xf9cb, "\x6e\x9c\0" }, - { 0xf9cc, "\x74\x09\0" }, - { 0xf9cd, "\x75\x59\0" }, - { 0xf9ce, "\x78\x6b\0" }, - { 0xf9cf, "\x7d\x10\0" }, - { 0xf9d0, "\x98\x5e\0" }, - { 0xf9d1, "\x51\x6d\0" }, - { 0xf9d2, "\x62\x2e\0" }, - { 0xf9d3, "\x96\x78\0" }, - { 0xf9d4, "\x50\x2b\0" }, - { 0xf9d5, "\x5d\x19\0" }, - { 0xf9d6, "\x6d\xea\0" }, - { 0xf9d7, "\x8f\x2a\0" }, - { 0xf9d8, "\x5f\x8b\0" }, - { 0xf9d9, "\x61\x44\0" }, - { 0xf9da, "\x68\x17\0" }, - { 0xf9db, "\x73\x87\0" }, - { 0xf9dc, "\x96\x86\0" }, - { 0xf9dd, "\x52\x29\0" }, - { 0xf9de, "\x54\x0f\0" }, - { 0xf9df, "\x5c\x65\0" }, - { 0xf9e0, "\x66\x13\0" }, - { 0xf9e1, "\x67\x4e\0" }, - { 0xf9e2, "\x68\xa8\0" }, - { 0xf9e3, "\x6c\xe5\0" }, - { 0xf9e4, "\x74\x06\0" }, - { 0xf9e5, "\x75\xe2\0" }, - { 0xf9e6, "\x7f\x79\0" }, - { 0xf9e7, "\x88\xcf\0" }, - { 0xf9e8, "\x88\xe1\0" }, - { 0xf9e9, "\x91\xcc\0" }, - { 0xf9ea, "\x96\xe2\0" }, - { 0xf9eb, "\x53\x3f\0" }, - { 0xf9ec, "\x6e\xba\0" }, - { 0xf9ed, "\x54\x1d\0" }, - { 0xf9ee, "\x71\xd0\0" }, - { 0xf9ef, "\x74\x98\0" }, - { 0xf9f0, "\x85\xfa\0" }, - { 0xf9f1, "\x96\xa3\0" }, - { 0xf9f2, "\x9c\x57\0" }, - { 0xf9f3, "\x9e\x9f\0" }, - { 0xf9f4, "\x67\x97\0" }, - { 0xf9f5, "\x6d\xcb\0" }, - { 0xf9f6, "\x81\xe8\0" }, - { 0xf9f7, "\x7a\xcb\0" }, - { 0xf9f8, "\x7b\x20\0" }, - { 0xf9f9, "\x7c\x92\0" }, - { 0xf9fa, "\x72\xc0\0" }, - { 0xf9fb, "\x70\x99\0" }, - { 0xf9fc, "\x8b\x58\0" }, - { 0xf9fd, "\x4e\xc0\0" }, - { 0xf9fe, "\x83\x36\0" }, - { 0xf9ff, "\x52\x3a\0" }, - { 0xfa00, "\x52\x07\0" }, - { 0xfa01, "\x5e\xa6\0" }, - { 0xfa02, "\x62\xd3\0" }, - { 0xfa03, "\x7c\xd6\0" }, - { 0xfa04, "\x5b\x85\0" }, - { 0xfa05, "\x6d\x1e\0" }, - { 0xfa06, "\x66\xb4\0" }, - { 0xfa07, "\x8f\x3b\0" }, - { 0xfa08, "\x88\x4c\0" }, - { 0xfa09, "\x96\x4d\0" }, - { 0xfa0a, "\x89\x8b\0" }, - { 0xfa0b, "\x5e\xd3\0" }, - { 0xfa0c, "\x51\x40\0" }, - { 0xfa0d, "\x55\xc0\0" }, - { 0xfa10, "\x58\x5a\0" }, - { 0xfa12, "\x66\x74\0" }, - { 0xfa15, "\x51\xde\0" }, - { 0xfa16, "\x73\x2a\0" }, - { 0xfa17, "\x76\xca\0" }, - { 0xfa18, "\x79\x3c\0" }, - { 0xfa19, "\x79\x5e\0" }, - { 0xfa1a, "\x79\x65\0" }, - { 0xfa1b, "\x79\x8f\0" }, - { 0xfa1c, "\x97\x56\0" }, - { 0xfa1d, "\x7c\xbe\0" }, - { 0xfa1e, "\x7f\xbd\0" }, - { 0xfa20, "\x86\x12\0" }, - { 0xfa22, "\x8a\xf8\0" }, - { 0xfa25, "\x90\x38\0" }, - { 0xfa26, "\x90\xfd\0" }, - { 0xfa2a, "\x98\xef\0" }, - { 0xfa2b, "\x98\xfc\0" }, - { 0xfa2c, "\x99\x28\0" }, - { 0xfa2d, "\x9d\xb4\0" }, - { 0xfb1f, "\x05\xf2\x05\xb7\0" }, - { 0xfb2a, "\x05\xe9\x05\xc1\0" }, - { 0xfb2b, "\x05\xe9\x05\xc2\0" }, - { 0xfb2c, "\x05\xe9\x05\xbc\x05\xc1\0" }, - { 0xfb2d, "\x05\xe9\x05\xbc\x05\xc2\0" }, - { 0xfb2e, "\x05\xd0\x05\xb7\0" }, - { 0xfb2f, "\x05\xd0\x05\xb8\0" }, - { 0xfb30, "\x05\xd0\x05\xbc\0" }, - { 0xfb31, "\x05\xd1\x05\xbc\0" }, - { 0xfb32, "\x05\xd2\x05\xbc\0" }, - { 0xfb33, "\x05\xd3\x05\xbc\0" }, - { 0xfb34, "\x05\xd4\x05\xbc\0" }, - { 0xfb35, "\x05\xd5\x05\xbc\0" }, - { 0xfb36, "\x05\xd6\x05\xbc\0" }, - { 0xfb38, "\x05\xd8\x05\xbc\0" }, - { 0xfb39, "\x05\xd9\x05\xbc\0" }, - { 0xfb3a, "\x05\xda\x05\xbc\0" }, - { 0xfb3b, "\x05\xdb\x05\xbc\0" }, - { 0xfb3c, "\x05\xdc\x05\xbc\0" }, - { 0xfb3e, "\x05\xde\x05\xbc\0" }, - { 0xfb40, "\x05\xe0\x05\xbc\0" }, - { 0xfb41, "\x05\xe1\x05\xbc\0" }, - { 0xfb43, "\x05\xe3\x05\xbc\0" }, - { 0xfb44, "\x05\xe4\x05\xbc\0" }, - { 0xfb46, "\x05\xe6\x05\xbc\0" }, - { 0xfb47, "\x05\xe7\x05\xbc\0" }, - { 0xfb48, "\x05\xe8\x05\xbc\0" }, - { 0xfb49, "\x05\xe9\x05\xbc\0" }, - { 0xfb4a, "\x05\xea\x05\xbc\0" }, - { 0xfb4b, "\x05\xd5\x05\xb9\0" }, - { 0xfb4c, "\x05\xd1\x05\xbf\0" }, - { 0xfb4d, "\x05\xdb\x05\xbf\0" }, - { 0xfb4e, "\x05\xe4\x05\xbf\0" } -}; - -/* - * WARNING! - * - * NO BUFFER CHECKING AHEAD! - * - */ - -static gint -e_canonical_decomposition (gunichar ch, gunichar * buf) -{ - gint len = 0; - - if (ch <= 0xffff) - { - gint start = 0; - gint end = sizeof (e_decomp_table) / sizeof (e_decomp_table[0]); - while (start != end) - { - gint half = (start + end) / 2; - if (ch == e_decomp_table[half].ch) { - /* Found it. */ - gint i; - /* We store as a double-nul terminated string. */ - for (len = 0; (e_decomp_table[half].expansion[len] || e_decomp_table[half].expansion[len + 1]); len += 2); - - /* We've counted twice as many bytes as there are - characters. */ - len /= 2; - - for (i = 0; i < len; i ++) { - buf[i] = (e_decomp_table[half].expansion[2 * i] << 8) | e_decomp_table[half].expansion[2 * i + 1]; - } - break; - } else if (ch > e_decomp_table[half].ch) { - if (start == half) break; - start = half; - } else { - if (end == half) break; - end = half; - } - } - } - - if (len == 0) - { - /* Not in our table. */ - *buf = ch; - len = 1; - } - - /* Supposedly following the Unicode 2.1.9 table means that the - decompositions come out in canonical order. I haven't tested - this, but we rely on it here. */ - return len; -} - -static gunichar -e_stripped_char (gunichar ch) -{ - gunichar decomp[MAX_DECOMP]; - GUnicodeType utype; - gint dlen; - - utype = g_unichar_type (ch); - - switch (utype) { - case G_UNICODE_CONTROL: - case G_UNICODE_FORMAT: - case G_UNICODE_UNASSIGNED: - case G_UNICODE_COMBINING_MARK: - /* Ignore those */ - return 0; - default: - /* Convert to lowercase, fall through */ - ch = g_unichar_tolower (ch); - case G_UNICODE_LOWERCASE_LETTER: - dlen = e_canonical_decomposition (ch, decomp); - if (dlen > 0) return *decomp; - break; - } - - return 0; -} - -gchar * -e_xml_get_translated_utf8_string_prop_by_name (const xmlNode *parent, const xmlChar *prop_name) -{ - xmlChar *prop; - gchar *ret_val = NULL; - gchar *combined_name; - - g_return_val_if_fail (parent != NULL, NULL); - g_return_val_if_fail (prop_name != NULL, NULL); - - prop = xmlGetProp ((xmlNode *) parent, prop_name); - if (prop != NULL) { - ret_val = g_strdup ((gchar *)prop); - xmlFree (prop); - return ret_val; - } - - combined_name = g_strdup_printf("_%s", prop_name); - prop = xmlGetProp ((xmlNode *) parent, (guchar *)combined_name); - if (prop != NULL) { - ret_val = g_strdup (gettext ((gchar *)prop)); - xmlFree (prop); - } - g_free(combined_name); - - return ret_val; -} diff --git a/widgets/misc/e-unicode.h b/widgets/misc/e-unicode.h deleted file mode 100644 index 737c5088eb..0000000000 --- a/widgets/misc/e-unicode.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * e-unicode.h - utf-8 support functions for gal - * - * 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: - * Lauris Kaplinski <lauris@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef _E_UNICODE_H_ -#define _E_UNICODE_H_ - -#include <sys/types.h> -#include <glib.h> -#include <gtk/gtk.h> -#include <libxml/tree.h> -#include <iconv.h> - -G_BEGIN_DECLS - -#define G_UTF8_IN_GAL - -/* - * UTF-8 searching implementations - * - * e_utf8_strstrcase - case insensitive search - * e_utf8_strstrcasedecomp - case insensitive and decompositing search (i.e. accented - * letters are treated equal to their base letters, explicit accent marks (unicode - * not ascii/iso ones) are ignored). - */ - -const gchar *e_utf8_strstrcase (const gchar *haystack, - const gchar *needle); -const gchar *e_utf8_strstrcasedecomp (const gchar *haystack, - const gchar *needle); -gchar *e_utf8_from_gtk_event_key (GtkWidget *widget, - guint keyval, - const gchar *string); -gchar *e_utf8_from_iconv_string (iconv_t ic, - const gchar *string); -gchar *e_utf8_from_iconv_string_sized (iconv_t ic, - const gchar *string, - gint bytes); -gchar *e_utf8_to_iconv_string (iconv_t ic, - const gchar *string); -gchar *e_utf8_to_iconv_string_sized (iconv_t ic, - const gchar *string, - gint bytes); -gchar *e_utf8_from_charset_string (const gchar *charset, - const gchar *string); -gchar *e_utf8_from_charset_string_sized (const gchar *charset, - const gchar *string, - gint bytes); -gchar *e_utf8_to_charset_string (const gchar *charset, - const gchar *string); -gchar *e_utf8_to_charset_string_sized (const gchar *charset, - const gchar *string, - gint bytes); -gchar *e_utf8_from_locale_string (const gchar *string); -gchar *e_utf8_from_locale_string_sized (const gchar *string, - gint bytes); -gchar *e_utf8_to_locale_string (const gchar *string); -gchar *e_utf8_to_locale_string_sized (const gchar *string, - gint bytes); -gboolean e_utf8_is_ascii (const gchar *string); -/* - * These are simple wrappers that save us some typing - */ - -/* NB! This return newly allocated string, not const as gtk+ one */ -gchar *e_utf8_gtk_entry_get_text (GtkEntry *entry); -void e_utf8_gtk_entry_set_text (GtkEntry *entry, - const gchar *text); -gchar *e_utf8_gtk_editable_get_text (GtkEditable *editable); -void e_utf8_gtk_editable_set_text (GtkEditable *editable, - const gchar *text); -gchar *e_utf8_gtk_editable_get_chars (GtkEditable *editable, - gint start, - gint end); -void e_utf8_gtk_editable_insert_text (GtkEditable *editable, - const gchar *text, - gint length, - gint *position); -gchar *e_utf8_xml1_decode (const gchar *text); -gchar *e_utf8_xml1_encode (const gchar *text); -gint e_unichar_to_utf8 (gint c, - gchar *outbuf); -gchar *e_unicode_get_utf8 (const gchar *text, - gunichar *out); -gchar *e_xml_get_translated_utf8_string_prop_by_name (const xmlNode *parent, - const xmlChar *prop_name); - -G_END_DECLS - -#endif - diff --git a/widgets/misc/ea-calendar-cell.c b/widgets/misc/ea-calendar-cell.c new file mode 100644 index 0000000000..05d0dcce6b --- /dev/null +++ b/widgets/misc/ea-calendar-cell.c @@ -0,0 +1,386 @@ +/* + * + * 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: + * Bolian Yin <bolian.yin@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <gtk/gtk.h> +#include <e-util/e-util.h> +#include "ea-calendar-cell.h" +#include "ea-calendar-item.h" +#include "a11y/ea-factory.h" + +/* ECalendarCell */ + +static void e_calendar_cell_class_init (ECalendarCellClass *class); + +EA_FACTORY_GOBJECT (EA_TYPE_CALENDAR_CELL, ea_calendar_cell, ea_calendar_cell_new) + +GType +e_calendar_cell_get_type (void) +{ + static GType type = 0; + + if (!type) { + static GTypeInfo tinfo = { + sizeof (ECalendarCellClass), + (GBaseInitFunc) NULL, /* base init */ + (GBaseFinalizeFunc) NULL, /* base finalize */ + (GClassInitFunc) e_calendar_cell_class_init, /* class init */ + (GClassFinalizeFunc) NULL, /* class finalize */ + NULL, /* class data */ + sizeof (ECalendarCell), /* instance size */ + 0, /* nb preallocs */ + (GInstanceInitFunc) NULL, /* instance init */ + NULL /* value table */ + }; + + type = g_type_register_static (G_TYPE_OBJECT, + "ECalendarCell", &tinfo, 0); + } + + return type; +} + +static void +e_calendar_cell_class_init (ECalendarCellClass *class) +{ + EA_SET_FACTORY (e_calendar_cell_get_type (), ea_calendar_cell); +} + +ECalendarCell * +e_calendar_cell_new (ECalendarItem *calitem, gint row, gint column) +{ + GObject *object; + ECalendarCell *cell; + + g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), NULL); + + object = g_object_new (E_TYPE_CALENDAR_CELL, NULL); + cell = E_CALENDAR_CELL (object); + cell->calitem = calitem; + cell->row = row; + cell->column = column; + +#ifdef ACC_DEBUG + g_print ("EvoAcc: e_calendar_cell created %p\n", (gpointer)cell); +#endif + + return cell; +} + +/* EaCalendarCell */ + +static void ea_calendar_cell_class_init (EaCalendarCellClass *klass); +static void ea_calendar_cell_init (EaCalendarCell *a11y); + +static G_CONST_RETURN gchar * ea_calendar_cell_get_name (AtkObject *accessible); +static G_CONST_RETURN gchar * ea_calendar_cell_get_description (AtkObject *accessible); +static AtkObject * ea_calendar_cell_get_parent (AtkObject *accessible); +static gint ea_calendar_cell_get_index_in_parent (AtkObject *accessible); +static AtkStateSet *ea_calendar_cell_ref_state_set (AtkObject *accessible); + +/* component interface */ +static void atk_component_interface_init (AtkComponentIface *iface); +static void component_interface_get_extents (AtkComponent *component, + gint *x, gint *y, + gint *width, gint *height, + AtkCoordType coord_type); +static gboolean component_interface_grab_focus (AtkComponent *component); + +static gpointer parent_class = NULL; + +#ifdef ACC_DEBUG +static gint n_ea_calendar_cell_created = 0, n_ea_calendar_cell_destroyed = 0; +static void ea_calendar_cell_finalize (GObject *object); +#endif + +GType +ea_calendar_cell_get_type (void) +{ + static GType type = 0; + + if (!type) { + static GTypeInfo tinfo = { + sizeof (EaCalendarCellClass), + (GBaseInitFunc) NULL, /* base init */ + (GBaseFinalizeFunc) NULL, /* base finalize */ + (GClassInitFunc) ea_calendar_cell_class_init, /* class init */ + (GClassFinalizeFunc) NULL, /* class finalize */ + NULL, /* class data */ + sizeof (EaCalendarCell), /* instance size */ + 0, /* nb preallocs */ + (GInstanceInitFunc) ea_calendar_cell_init, /* instance init */ + NULL /* value table */ + }; + + static const GInterfaceInfo atk_component_info = { + (GInterfaceInitFunc) atk_component_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + type = g_type_register_static (ATK_TYPE_GOBJECT_ACCESSIBLE, + "EaCalendarCell", &tinfo, 0); + g_type_add_interface_static (type, ATK_TYPE_COMPONENT, + &atk_component_info); + } + + return type; +} + +static void +ea_calendar_cell_class_init (EaCalendarCellClass *klass) +{ + AtkObjectClass *class = ATK_OBJECT_CLASS (klass); + +#ifdef ACC_DEBUG + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = ea_calendar_cell_finalize; +#endif + + parent_class = g_type_class_peek_parent (klass); + + class->get_name = ea_calendar_cell_get_name; + class->get_description = ea_calendar_cell_get_description; + + class->get_parent = ea_calendar_cell_get_parent; + class->get_index_in_parent = ea_calendar_cell_get_index_in_parent; + class->ref_state_set = ea_calendar_cell_ref_state_set; +} + +static void +ea_calendar_cell_init (EaCalendarCell *a11y) +{ + a11y->state_set = atk_state_set_new (); + atk_state_set_add_state (a11y->state_set, ATK_STATE_TRANSIENT); + atk_state_set_add_state (a11y->state_set, ATK_STATE_ENABLED); + atk_state_set_add_state (a11y->state_set, ATK_STATE_SENSITIVE); + atk_state_set_add_state (a11y->state_set, ATK_STATE_SELECTABLE); + atk_state_set_add_state (a11y->state_set, ATK_STATE_SHOWING); + atk_state_set_add_state (a11y->state_set, ATK_STATE_FOCUSABLE); +} + +AtkObject* +ea_calendar_cell_new (GObject *obj) +{ + gpointer object; + AtkObject *atk_object; + + g_return_val_if_fail (E_IS_CALENDAR_CELL (obj), NULL); + object = g_object_new (EA_TYPE_CALENDAR_CELL, NULL); + atk_object = ATK_OBJECT (object); + atk_object_initialize (atk_object, obj); + atk_object->role = ATK_ROLE_TABLE_CELL; + +#ifdef ACC_DEBUG + ++n_ea_calendar_cell_created; + g_print ("ACC_DEBUG: n_ea_calendar_cell_created = %d\n", + n_ea_calendar_cell_created); +#endif + return atk_object; +} + +#ifdef ACC_DEBUG +static void ea_calendar_cell_finalize (GObject *object) +{ + G_OBJECT_CLASS (parent_class)->finalize (object); + + ++n_ea_calendar_cell_destroyed; + g_print ("ACC_DEBUG: n_ea_calendar_cell_destroyed = %d\n", + n_ea_calendar_cell_destroyed); +} +#endif + +static G_CONST_RETURN gchar * +ea_calendar_cell_get_name (AtkObject *accessible) +{ + GObject *g_obj; + + g_return_val_if_fail (EA_IS_CALENDAR_CELL (accessible), NULL); + + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible)); + if (!g_obj) + /* defunct object*/ + return NULL; + + if (!accessible->name) { + AtkObject *atk_obj; + EaCalendarItem *ea_calitem; + ECalendarCell *cell; + gint day_index; + gint year, month, day; + gchar buffer[128]; + + cell = E_CALENDAR_CELL (g_obj); + atk_obj = ea_calendar_cell_get_parent (accessible); + ea_calitem = EA_CALENDAR_ITEM (atk_obj); + day_index = atk_table_get_index_at (ATK_TABLE (ea_calitem), + cell->row, cell->column); + e_calendar_item_get_date_for_offset (cell->calitem, day_index, + &year, &month, &day); + + g_snprintf (buffer, 128, "%d-%d-%d", year, month + 1, day); + ATK_OBJECT_CLASS (parent_class)->set_name (accessible, buffer); + } + return accessible->name; +} + +static G_CONST_RETURN gchar * +ea_calendar_cell_get_description (AtkObject *accessible) +{ + return ea_calendar_cell_get_name (accessible); +} + +static AtkObject * +ea_calendar_cell_get_parent (AtkObject *accessible) +{ + GObject *g_obj; + ECalendarCell *cell; + ECalendarItem *calitem; + + g_return_val_if_fail (EA_IS_CALENDAR_CELL (accessible), NULL); + + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible)); + if (!g_obj) + /* defunct object*/ + return NULL; + + cell = E_CALENDAR_CELL (g_obj); + calitem = cell->calitem; + return atk_gobject_accessible_for_object (G_OBJECT (calitem)); +} + +static gint +ea_calendar_cell_get_index_in_parent (AtkObject *accessible) +{ + GObject *g_obj; + ECalendarCell *cell; + AtkObject *parent; + + g_return_val_if_fail (EA_IS_CALENDAR_CELL (accessible), -1); + + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible)); + if (!g_obj) + return -1; + cell = E_CALENDAR_CELL (g_obj); + parent = atk_object_get_parent (accessible); + return atk_table_get_index_at (ATK_TABLE (parent), + cell->row, cell->column); +} + +static AtkStateSet * +ea_calendar_cell_ref_state_set (AtkObject *accessible) +{ + EaCalendarCell *atk_cell = EA_CALENDAR_CELL (accessible); + + g_return_val_if_fail (atk_cell->state_set, NULL); + + g_object_ref(atk_cell->state_set); + + return atk_cell->state_set; + +} + +/* Atk Component Interface */ + +static void +atk_component_interface_init (AtkComponentIface *iface) +{ + g_return_if_fail (iface != NULL); + + iface->get_extents = component_interface_get_extents; + iface->grab_focus = component_interface_grab_focus; +} + +static void +component_interface_get_extents (AtkComponent *component, + gint *x, gint *y, gint *width, gint *height, + AtkCoordType coord_type) +{ + GObject *g_obj; + AtkObject *atk_obj, *atk_canvas; + ECalendarCell *cell; + ECalendarItem *calitem; + EaCalendarItem *ea_calitem; + gint day_index; + gint year, month, day; + gint canvas_x, canvas_y, canvas_width, canvas_height; + + *x = *y = *width = *height = 0; + + g_return_if_fail (EA_IS_CALENDAR_CELL (component)); + + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(component)); + if (!g_obj) + /* defunct object*/ + return; + + cell = E_CALENDAR_CELL (g_obj); + calitem = cell->calitem; + atk_obj = atk_gobject_accessible_for_object (G_OBJECT (calitem)); + ea_calitem = EA_CALENDAR_ITEM (atk_obj); + day_index = atk_table_get_index_at (ATK_TABLE (ea_calitem), + cell->row, cell->column); + e_calendar_item_get_date_for_offset (calitem, day_index, + &year, &month, &day); + + if (!e_calendar_item_get_day_extents (calitem, + year, month, day, + x, y, width, height)) + return; + atk_canvas = atk_object_get_parent (ATK_OBJECT (ea_calitem)); + atk_component_get_extents (ATK_COMPONENT (atk_canvas), + &canvas_x, &canvas_y, + &canvas_width, &canvas_height, + coord_type); + *x += canvas_x; + *y += canvas_y; +} + +static gboolean +component_interface_grab_focus (AtkComponent *component) +{ + GObject *g_obj; + GtkWidget *toplevel; + AtkObject *ea_calitem; + ECalendarItem *calitem; + EaCalendarCell *a11y; + gint index; + + a11y = EA_CALENDAR_CELL (component); + ea_calitem = ea_calendar_cell_get_parent (ATK_OBJECT (a11y)); + + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(ea_calitem)); + calitem = E_CALENDAR_ITEM (g_obj); + + index = atk_object_get_index_in_parent (ATK_OBJECT (a11y)); + + atk_selection_clear_selection (ATK_SELECTION (ea_calitem)); + atk_selection_add_selection (ATK_SELECTION (ea_calitem), index); + + gtk_widget_grab_focus (GTK_WIDGET (GNOME_CANVAS_ITEM (calitem)->canvas)); + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (GNOME_CANVAS_ITEM (calitem)->canvas)); + if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel)) + gtk_window_present (GTK_WINDOW (toplevel)); + + return TRUE; + +} diff --git a/widgets/misc/ea-calendar-cell.h b/widgets/misc/ea-calendar-cell.h new file mode 100644 index 0000000000..fa68fdca55 --- /dev/null +++ b/widgets/misc/ea-calendar-cell.h @@ -0,0 +1,86 @@ +/* + * 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: + * Bolian Yin <bolian.yin@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __EA_CALENDAR_CELL_H__ +#define __EA_CALENDAR_CELL_H__ + +#include <atk/atkgobjectaccessible.h> +#include "misc/e-calendar-item.h" + +G_BEGIN_DECLS + +#define E_TYPE_CALENDAR_CELL (e_calendar_cell_get_type ()) +#define E_CALENDAR_CELL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CALENDAR_CELL, ECalendarCell)) +#define E_CALENDAR_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CALENDAR_CELL, ECalendarCellClass)) +#define E_IS_CALENDAR_CELL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CALENDAR_CELL)) +#define E_IS_CALENDAR_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CALENDAR_CELL)) +#define E_CALENDAR_CELL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CALENDAR_CELL, ECalendarCellClass)) + +typedef struct _ECalendarCell ECalendarCell; +typedef struct _ECalendarCellClass ECalendarCellClass; + +struct _ECalendarCell +{ + GObject parent; + ECalendarItem *calitem; + gint row; + gint column; +}; + +GType e_calendar_cell_get_type (void); + +struct _ECalendarCellClass +{ + GObjectClass parent_class; +}; + +ECalendarCell * e_calendar_cell_new (ECalendarItem *calitem, + gint row, gint column); + +#define EA_TYPE_CALENDAR_CELL (ea_calendar_cell_get_type ()) +#define EA_CALENDAR_CELL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EA_TYPE_CALENDAR_CELL, EaCalendarCell)) +#define EA_CALENDAR_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EA_TYPE_CALENDAR_CELL, EaCalendarCellClass)) +#define EA_IS_CALENDAR_CELL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EA_TYPE_CALENDAR_CELL)) +#define EA_IS_CALENDAR_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EA_TYPE_CALENDAR_CELL)) +#define EA_CALENDAR_CELL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EA_TYPE_CALENDAR_CELL, EaCalendarCellClass)) + +typedef struct _EaCalendarCell EaCalendarCell; +typedef struct _EaCalendarCellClass EaCalendarCellClass; + +struct _EaCalendarCell +{ + AtkGObjectAccessible parent; + AtkStateSet *state_set; +}; + +GType ea_calendar_cell_get_type (void); + +struct _EaCalendarCellClass +{ + AtkGObjectAccessibleClass parent_class; +}; + +AtkObject* ea_calendar_cell_new (GObject *gobj); + +G_END_DECLS + +#endif /* __EA_CALENDAR_CELL_H__ */ diff --git a/widgets/misc/ea-calendar-item.c b/widgets/misc/ea-calendar-item.c new file mode 100644 index 0000000000..9dcb83449c --- /dev/null +++ b/widgets/misc/ea-calendar-item.c @@ -0,0 +1,1314 @@ +/* + * 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: + * Bolian Yin <bolian.yin@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <stdio.h> +#include <time.h> +#include <string.h> +#include <libgnomecanvas/gnome-canvas.h> +#include <glib.h> +#include <e-util/e-util.h> +#include <glib/gi18n.h> +#include <libedataserver/e-data-server-util.h> +#include "ea-calendar-item.h" +#include "ea-calendar-cell.h" +#include "ea-cell-table.h" + +#define EA_CALENDAR_COLUMN_NUM E_CALENDAR_COLS_PER_MONTH + +/* EaCalendarItem */ +static void ea_calendar_item_class_init (EaCalendarItemClass *klass); +static void ea_calendar_item_finalize (GObject *object); + +static G_CONST_RETURN gchar * ea_calendar_item_get_name (AtkObject *accessible); +static G_CONST_RETURN gchar * ea_calendar_item_get_description (AtkObject *accessible); +static gint ea_calendar_item_get_n_children (AtkObject *accessible); +static AtkObject *ea_calendar_item_ref_child (AtkObject *accessible, gint index); +static AtkStateSet* ea_calendar_item_ref_state_set (AtkObject *accessible); + +/* atk table interface */ +static void atk_table_interface_init (AtkTableIface *iface); +static gint table_interface_get_index_at (AtkTable *table, + gint row, + gint column); +static gint table_interface_get_column_at_index (AtkTable *table, + gint index); +static gint table_interface_get_row_at_index (AtkTable *table, + gint index); +static AtkObject* table_interface_ref_at (AtkTable *table, + gint row, + gint column); +static gint table_interface_get_n_rows (AtkTable *table); +static gint table_interface_get_n_columns (AtkTable *table); +static gint table_interface_get_column_extent_at (AtkTable *table, + gint row, + gint column); +static gint table_interface_get_row_extent_at (AtkTable *table, + gint row, + gint column); + +static gboolean table_interface_is_row_selected (AtkTable *table, + gint row); +static gboolean table_interface_is_column_selected (AtkTable *table, + gint row); +static gboolean table_interface_is_selected (AtkTable *table, + gint row, + gint column); +static gint table_interface_get_selected_rows (AtkTable *table, + gint **rows_selected); +static gint table_interface_get_selected_columns (AtkTable *table, + gint **columns_selected); +static gboolean table_interface_add_row_selection (AtkTable *table, gint row); +static gboolean table_interface_remove_row_selection (AtkTable *table, + gint row); +static gboolean table_interface_add_column_selection (AtkTable *table, + gint column); +static gboolean table_interface_remove_column_selection (AtkTable *table, + gint column); +static AtkObject* table_interface_get_row_header (AtkTable *table, gint row); +static AtkObject* table_interface_get_column_header (AtkTable *table, + gint in_col); +static AtkObject* table_interface_get_caption (AtkTable *table); + +static G_CONST_RETURN gchar * +table_interface_get_column_description (AtkTable *table, gint in_col); + +static G_CONST_RETURN gchar * +table_interface_get_row_description (AtkTable *table, gint row); + +static AtkObject* table_interface_get_summary (AtkTable *table); + +/* atk selection interface */ +static void atk_selection_interface_init (AtkSelectionIface *iface); +static gboolean selection_interface_add_selection (AtkSelection *selection, + gint i); +static gboolean selection_interface_clear_selection (AtkSelection *selection); +static AtkObject* selection_interface_ref_selection (AtkSelection *selection, + gint i); +static gint selection_interface_get_selection_count (AtkSelection *selection); +static gboolean selection_interface_is_child_selected (AtkSelection *selection, + gint i); + +/* callbacks */ +static void selection_preview_change_cb (ECalendarItem *calitem); +static void date_range_changed_cb (ECalendarItem *calitem); + +/* helpers */ +static EaCellTable *ea_calendar_item_get_cell_data (EaCalendarItem *ea_calitem); +static void ea_calendar_item_destory_cell_data (EaCalendarItem *ea_calitem); +static gboolean ea_calendar_item_get_column_label (EaCalendarItem *ea_calitem, + gint column, + gchar *buffer, + gint buffer_size); +static gboolean ea_calendar_item_get_row_label (EaCalendarItem *ea_calitem, + gint row, + gchar *buffer, + gint buffer_size); +static gboolean e_calendar_item_get_offset_for_date (ECalendarItem *calitem, + gint year, gint month, gint day, + gint *offset); +static void ea_calendar_set_focus_object (EaCalendarItem *ea_calitem, + AtkObject *item_cell); + +#ifdef ACC_DEBUG +static gint n_ea_calendar_item_created = 0; +static gint n_ea_calendar_item_destroyed = 0; +#endif + +static gpointer parent_class = NULL; + +GType +ea_calendar_item_get_type (void) +{ + static GType type = 0; + AtkObjectFactory *factory; + GTypeQuery query; + GType derived_atk_type; + + if (!type) { + static GTypeInfo tinfo = { + sizeof (EaCalendarItemClass), + (GBaseInitFunc) NULL, /* base init */ + (GBaseFinalizeFunc) NULL, /* base finalize */ + (GClassInitFunc) ea_calendar_item_class_init, /* class init */ + (GClassFinalizeFunc) NULL, /* class finalize */ + NULL, /* class data */ + sizeof (EaCalendarItem), /* instance size */ + 0, /* nb preallocs */ + (GInstanceInitFunc) NULL, /* instance init */ + NULL /* value table */ + }; + + static const GInterfaceInfo atk_table_info = { + (GInterfaceInitFunc) atk_table_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + static const GInterfaceInfo atk_selection_info = { + (GInterfaceInitFunc) atk_selection_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + /* + * Figure out the size of the class and instance + * we are run-time deriving from (GailCanvasItem, in this case) + */ + + factory = atk_registry_get_factory (atk_get_default_registry (), + GNOME_TYPE_CANVAS_ITEM); + derived_atk_type = atk_object_factory_get_accessible_type (factory); + g_type_query (derived_atk_type, &query); + + tinfo.class_size = query.class_size; + tinfo.instance_size = query.instance_size; + + type = g_type_register_static (derived_atk_type, + "EaCalendarItem", &tinfo, 0); + g_type_add_interface_static (type, ATK_TYPE_TABLE, + &atk_table_info); + g_type_add_interface_static (type, ATK_TYPE_SELECTION, + &atk_selection_info); + } + + return type; +} + +static void +ea_calendar_item_class_init (EaCalendarItemClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + AtkObjectClass *class = ATK_OBJECT_CLASS (klass); + + gobject_class->finalize = ea_calendar_item_finalize; + parent_class = g_type_class_peek_parent (klass); + + class->get_name = ea_calendar_item_get_name; + class->get_description = ea_calendar_item_get_description; + class->ref_state_set = ea_calendar_item_ref_state_set; + + class->get_n_children = ea_calendar_item_get_n_children; + class->ref_child = ea_calendar_item_ref_child; +} + +AtkObject* +ea_calendar_item_new (GObject *obj) +{ + gpointer object; + AtkObject *atk_object; + AtkObject *item_cell; + + g_return_val_if_fail (E_IS_CALENDAR_ITEM (obj), NULL); + object = g_object_new (EA_TYPE_CALENDAR_ITEM, NULL); + atk_object = ATK_OBJECT (object); + atk_object_initialize (atk_object, obj); + atk_object->role = ATK_ROLE_CALENDAR; + + item_cell = atk_selection_ref_selection (ATK_SELECTION (atk_object), + 0); + if (item_cell) + ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_object), item_cell); + +#ifdef ACC_DEBUG + ++n_ea_calendar_item_created; + g_print ("ACC_DEBUG: n_ea_calendar_item_created = %d\n", + n_ea_calendar_item_created); +#endif + /* connect signal handlers */ + g_signal_connect (obj, "selection_preview_changed", + G_CALLBACK (selection_preview_change_cb), + atk_object); + g_signal_connect (obj, "date_range_changed", + G_CALLBACK (date_range_changed_cb), + atk_object); + + return atk_object; +} + +static void +ea_calendar_item_finalize (GObject *object) +{ + EaCalendarItem *ea_calitem; + + g_return_if_fail (EA_IS_CALENDAR_ITEM (object)); + + ea_calitem = EA_CALENDAR_ITEM (object); + + /* Free the allocated cell data */ + ea_calendar_item_destory_cell_data (ea_calitem); + + G_OBJECT_CLASS (parent_class)->finalize (object); +#ifdef ACC_DEBUG + ++n_ea_calendar_item_destroyed; + printf ("ACC_DEBUG: n_ea_calendar_item_destroyed = %d\n", + n_ea_calendar_item_destroyed); +#endif +} + +static G_CONST_RETURN gchar * +ea_calendar_item_get_name (AtkObject *accessible) +{ + GObject *g_obj; + ECalendarItem *calitem; + gint start_year, start_month, start_day; + gint end_year, end_month, end_day; + gchar *name_str = NULL; + gchar buffer_start[128] = ""; + gchar buffer_end[128] = ""; + struct tm day_start = { 0 }; + struct tm day_end = { 0 }; + + g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), NULL); + + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible)); + if (!g_obj) + return NULL; + g_return_val_if_fail (E_IS_CALENDAR_ITEM (g_obj), NULL); + + calitem = E_CALENDAR_ITEM (g_obj); + if (e_calendar_item_get_date_range (calitem, + &start_year, &start_month, &start_day, + &end_year, &end_month, &end_day)) { + + day_start.tm_year = start_year - 1900; + day_start.tm_mon = start_month; + day_start.tm_mday = start_day; + day_start.tm_isdst = -1; + e_utf8_strftime (buffer_start, sizeof (buffer_start), _("%d %B %Y"), &day_start); + + day_end.tm_year = end_year - 1900; + day_end.tm_mon = end_month; + day_end.tm_mday = end_day; + day_end.tm_isdst = -1; + e_utf8_strftime (buffer_end, sizeof (buffer_end), _("%d %B %Y"), &day_end); + + name_str = g_strdup_printf (_("Calendar: from %s to %s"), buffer_start, buffer_end); + } + +#if 0 + if (e_calendar_item_get_selection (calitem, &select_start, &select_end)) { + GDate select_start, select_end; + gint year1, year2, month1, month2, day1, day2; + + year1 = g_date_get_year (&select_start); + month1 = g_date_get_month (&select_start); + day1 = g_date_get_day (&select_start); + + year2 = g_date_get_year (&select_end); + month2 = g_date_get_month (&select_end); + day2 = g_date_get_day (&select_end); + + sprintf (new_name + strlen (new_name), + " : current selection: from %d-%d-%d to %d-%d-%d.", + year1, month1, day1, + year2, month2, day2); + } +#endif + + ATK_OBJECT_CLASS (parent_class)->set_name (accessible, name_str); + g_free (name_str); + + return accessible->name; +} + +static G_CONST_RETURN gchar * +ea_calendar_item_get_description (AtkObject *accessible) +{ + if (accessible->description) + return accessible->description; + + return _("evolution calendar item"); +} + +static AtkStateSet* +ea_calendar_item_ref_state_set (AtkObject *accessible) +{ + AtkStateSet *state_set; + GObject *g_obj; + + state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible); + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible)); + if (!g_obj) + return state_set; + + atk_state_set_add_state (state_set, ATK_STATE_ENABLED); + atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE); + + return state_set; +} + +static gint +ea_calendar_item_get_n_children (AtkObject *accessible) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + gint n_children = 0; + gint start_year, start_month, start_day; + gint end_year, end_month, end_day; + GDate *start_date, *end_date; + + g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), -1); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return -1; + + calitem = E_CALENDAR_ITEM (g_obj); + if (!e_calendar_item_get_date_range (calitem, &start_year, + &start_month, &start_day, + &end_year, &end_month, + &end_day)) + return 0; + + start_date = g_date_new_dmy (start_day, start_month + 1, start_year); + end_date = g_date_new_dmy (end_day, end_month + 1, end_year); + + n_children = g_date_days_between (start_date, end_date) + 1; + g_free (start_date); + g_free (end_date); + return n_children; +} + +static AtkObject * +ea_calendar_item_ref_child (AtkObject *accessible, gint index) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + gint n_children; + ECalendarCell *cell; + EaCellTable *cell_data; + EaCalendarItem *ea_calitem; + + g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), NULL); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return NULL; + + calitem = E_CALENDAR_ITEM (g_obj); + + n_children = ea_calendar_item_get_n_children (accessible); + if (index < 0 || index >= n_children) + return NULL; + + ea_calitem = EA_CALENDAR_ITEM (accessible); + cell_data = ea_calendar_item_get_cell_data (ea_calitem); + if (!cell_data) + return NULL; + + cell = ea_cell_table_get_cell_at_index (cell_data, index); + if (!cell) { + cell = e_calendar_cell_new (calitem, + index / EA_CALENDAR_COLUMN_NUM, + index % EA_CALENDAR_COLUMN_NUM); + ea_cell_table_set_cell_at_index (cell_data, index, cell); + g_object_unref (cell); + } + +#ifdef ACC_DEBUG + g_print ("AccDebug: ea_calendar_item children[%d]=%p\n", index, + (gpointer)cell); +#endif + return g_object_ref (atk_gobject_accessible_for_object (G_OBJECT(cell))); +} + +/* atk table interface */ + +static void +atk_table_interface_init (AtkTableIface *iface) +{ + g_return_if_fail (iface != NULL); + + iface->ref_at = table_interface_ref_at; + + iface->get_n_rows = table_interface_get_n_rows; + iface->get_n_columns = table_interface_get_n_columns; + iface->get_index_at = table_interface_get_index_at; + iface->get_column_at_index = table_interface_get_column_at_index; + iface->get_row_at_index = table_interface_get_row_at_index; + iface->get_column_extent_at = table_interface_get_column_extent_at; + iface->get_row_extent_at = table_interface_get_row_extent_at; + + iface->is_selected = table_interface_is_selected; + iface->get_selected_rows = table_interface_get_selected_rows; + iface->get_selected_columns = table_interface_get_selected_columns; + iface->is_row_selected = table_interface_is_row_selected; + iface->is_column_selected = table_interface_is_column_selected; + iface->add_row_selection = table_interface_add_row_selection; + iface->remove_row_selection = table_interface_remove_row_selection; + iface->add_column_selection = table_interface_add_column_selection; + iface->remove_column_selection = table_interface_remove_column_selection; + + iface->get_row_header = table_interface_get_row_header; + iface->get_column_header = table_interface_get_column_header; + iface->get_caption = table_interface_get_caption; + iface->get_summary = table_interface_get_summary; + iface->get_row_description = table_interface_get_row_description; + iface->get_column_description = table_interface_get_column_description; +} + +static AtkObject* +table_interface_ref_at (AtkTable *table, + gint row, + gint column) +{ + gint index; + + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + index = EA_CALENDAR_COLUMN_NUM * row + column; + return ea_calendar_item_ref_child (ATK_OBJECT (ea_calitem), index); +} + +static gint +table_interface_get_n_rows (AtkTable *table) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + gint n_children; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return -1; + + n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem)); + return (n_children - 1) / EA_CALENDAR_COLUMN_NUM + 1; +} + +static gint +table_interface_get_n_columns (AtkTable *table) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return -1; + + return EA_CALENDAR_COLUMN_NUM; +} + +static gint +table_interface_get_index_at (AtkTable *table, + gint row, + gint column) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return -1; + + return row * EA_CALENDAR_COLUMN_NUM + column; +} + +static gint +table_interface_get_column_at_index (AtkTable *table, + gint index) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + gint n_children; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return -1; + + n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem)); + if (index >= 0 && index < n_children) + return index % EA_CALENDAR_COLUMN_NUM; + return -1; +} + +static gint +table_interface_get_row_at_index (AtkTable *table, + gint index) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + gint n_children; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return -1; + + n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem)); + if (index >= 0 && index < n_children) + return index / EA_CALENDAR_COLUMN_NUM; + return -1; +} + +static gint +table_interface_get_column_extent_at (AtkTable *table, + gint row, + gint column) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + calitem = E_CALENDAR_ITEM (g_obj); + return calitem->cell_width; +} + +static gint +table_interface_get_row_extent_at (AtkTable *table, + gint row, gint column) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + calitem = E_CALENDAR_ITEM (g_obj); + return calitem->cell_height; +} + +/* any day in the row is selected, the row is selected */ +static gboolean +table_interface_is_row_selected (AtkTable *table, + gint row) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + gint n_rows; + ECalendarItem *calitem; + gint row_index_start, row_index_end; + gint sel_index_start, sel_index_end; + + GDate start_date, end_date; + + g_return_val_if_fail (EA_IS_CALENDAR_ITEM (table), FALSE); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (table); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + n_rows = table_interface_get_n_rows (table); + if (row < 0 || row >= n_rows) + return FALSE; + + row_index_start = row * EA_CALENDAR_COLUMN_NUM; + row_index_end = row_index_start + EA_CALENDAR_COLUMN_NUM - 1; + + calitem = E_CALENDAR_ITEM (g_obj); + if (!e_calendar_item_get_selection (calitem, &start_date, &end_date)) + return FALSE; + + e_calendar_item_get_offset_for_date (calitem, + g_date_get_year (&start_date), + g_date_get_month (&start_date), + g_date_get_day (&start_date), + &sel_index_start); + e_calendar_item_get_offset_for_date (calitem, + g_date_get_year (&end_date), + g_date_get_month (&end_date), + g_date_get_day (&end_date), + &sel_index_end); + + if ((sel_index_start < row_index_start && + sel_index_end >= row_index_start) || + (sel_index_start >= row_index_start && + sel_index_start <= row_index_end)) + return TRUE; + return FALSE; +} + +static gboolean +table_interface_is_selected (AtkTable *table, + gint row, + gint column) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + gint n_rows, n_columns; + ECalendarItem *calitem; + gint index; + gint sel_index_start, sel_index_end; + + GDate start_date, end_date; + + g_return_val_if_fail (EA_IS_CALENDAR_ITEM (table), FALSE); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (table); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + n_rows = table_interface_get_n_rows (table); + if (row < 0 || row >= n_rows) + return FALSE; + n_columns = table_interface_get_n_columns (table); + if (column < 0 || column >= n_columns) + return FALSE; + + index = table_interface_get_index_at (table, row, column); + + calitem = E_CALENDAR_ITEM (g_obj); + if (!e_calendar_item_get_selection (calitem, &start_date, &end_date)) + return FALSE; + + e_calendar_item_get_offset_for_date (calitem, + g_date_get_year (&start_date), + g_date_get_month (&start_date), + g_date_get_day (&start_date), + &sel_index_start); + e_calendar_item_get_offset_for_date (calitem, + g_date_get_year (&end_date), + g_date_get_month (&end_date), + g_date_get_day (&end_date), &sel_index_end); + + if (sel_index_start <= index && sel_index_end >= index) + return TRUE; + return FALSE; +} + +static gboolean +table_interface_is_column_selected (AtkTable *table, + gint column) +{ + return FALSE; +} + +static gint +table_interface_get_selected_rows (AtkTable *table, + gint **rows_selected) +{ + *rows_selected = NULL; + return -1; +} + +static gint +table_interface_get_selected_columns (AtkTable *table, + gint **columns_selected) +{ + *columns_selected = NULL; + return -1; +} + +static gboolean +table_interface_add_row_selection (AtkTable *table, + gint row) +{ + return FALSE; +} + +static gboolean +table_interface_remove_row_selection (AtkTable *table, + gint row) +{ + return FALSE; +} + +static gboolean +table_interface_add_column_selection (AtkTable *table, + gint column) +{ + return FALSE; +} + +static gboolean +table_interface_remove_column_selection (AtkTable *table, + gint column) +{ + /* FIXME: NOT IMPLEMENTED */ + return FALSE; +} + +static AtkObject* +table_interface_get_row_header (AtkTable *table, + gint row) +{ + /* FIXME: NOT IMPLEMENTED */ + return NULL; +} + +static AtkObject* +table_interface_get_column_header (AtkTable *table, + gint in_col) +{ + /* FIXME: NOT IMPLEMENTED */ + return NULL; +} + +static AtkObject* +table_interface_get_caption (AtkTable *table) +{ + /* FIXME: NOT IMPLEMENTED */ + return NULL; +} + +static G_CONST_RETURN gchar * +table_interface_get_column_description (AtkTable *table, gint in_col) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + const gchar *description = NULL; + EaCellTable *cell_data; + gint n_columns; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return NULL; + + n_columns = table_interface_get_n_columns (table); + if (in_col < 0 || in_col >= n_columns) + return NULL; + cell_data = ea_calendar_item_get_cell_data (ea_calitem); + if (!cell_data) + return NULL; + + description = ea_cell_table_get_column_label (cell_data, in_col); + if (!description) { + gchar buffer[128] = "column description"; + ea_calendar_item_get_column_label (ea_calitem, in_col, + buffer, sizeof (buffer)); + ea_cell_table_set_column_label (cell_data, in_col, buffer); + description = ea_cell_table_get_column_label (cell_data, + in_col); + } + return description; +} + +static G_CONST_RETURN gchar * +table_interface_get_row_description (AtkTable *table, gint row) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + const gchar *description = NULL; + EaCellTable *cell_data; + gint n_rows; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return NULL; + + n_rows = table_interface_get_n_rows (table); + if (row < 0 || row >= n_rows) + return NULL; + cell_data = ea_calendar_item_get_cell_data (ea_calitem); + if (!cell_data) + return NULL; + + description = ea_cell_table_get_row_label (cell_data, row); + if (!description) { + gchar buffer[128] = "row description"; + ea_calendar_item_get_row_label (ea_calitem, row, + buffer, sizeof (buffer)); + ea_cell_table_set_row_label (cell_data, row, buffer); + description = ea_cell_table_get_row_label (cell_data, + row); + } + return description; +} + +static AtkObject* +table_interface_get_summary (AtkTable *table) +{ + /* FIXME: NOT IMPLEMENTED */ + return NULL; +} + +/* atkselection interface */ + +static void +atk_selection_interface_init (AtkSelectionIface *iface) +{ + g_return_if_fail (iface != NULL); + + iface->add_selection = selection_interface_add_selection; + iface->clear_selection = selection_interface_clear_selection; + iface->ref_selection = selection_interface_ref_selection; + iface->get_selection_count = selection_interface_get_selection_count; + iface->is_child_selected = selection_interface_is_child_selected; +} + +static gboolean +selection_interface_add_selection (AtkSelection *selection, gint index) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection); + gint year, month, day; + GDate start_date, end_date; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + calitem = E_CALENDAR_ITEM (g_obj); + if (!e_calendar_item_get_date_for_offset (calitem, index, + &year, &month, &day)) + return FALSE; + + /* FIXME: not support mulit-selection */ + g_date_set_dmy (&start_date, day, month + 1, year); + end_date = start_date; + e_calendar_item_set_selection (calitem, &start_date, &end_date); + return TRUE; +} + +static gboolean +selection_interface_clear_selection (AtkSelection *selection) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + calitem = E_CALENDAR_ITEM (g_obj); + e_calendar_item_set_selection (calitem, NULL, NULL); + + return TRUE; +} + +static AtkObject* +selection_interface_ref_selection (AtkSelection *selection, gint i) +{ + GObject *g_obj; + ECalendarItem *calitem; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection); + gint count, sel_offset; + GDate start_date, end_date; + + count = selection_interface_get_selection_count (selection); + if (i < 0 || i >= count) + return NULL; + + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (ea_calitem)); + + calitem = E_CALENDAR_ITEM (g_obj); + if (!e_calendar_item_get_selection (calitem, &start_date, &end_date)) + return NULL; + if (!e_calendar_item_get_offset_for_date (calitem, + g_date_get_year (&start_date), + g_date_get_month (&start_date) - 1, + g_date_get_day (&start_date), + &sel_offset)) + return NULL; + + return ea_calendar_item_ref_child (ATK_OBJECT (selection), sel_offset + i); +} + +static gint +selection_interface_get_selection_count (AtkSelection *selection) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection); + GDate start_date, end_date; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return 0; + + calitem = E_CALENDAR_ITEM (g_obj); + if (e_calendar_item_get_selection (calitem, &start_date, &end_date)) + return g_date_days_between (&start_date, &end_date) + 1; + else + return 0; +} + +static gboolean +selection_interface_is_child_selected (AtkSelection *selection, gint index) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection); + gint row, column, n_children; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + n_children = atk_object_get_n_accessible_children (ATK_OBJECT (selection)); + if (index < 0 || index >= n_children) + return FALSE; + + row = index / EA_CALENDAR_COLUMN_NUM; + column = index % EA_CALENDAR_COLUMN_NUM; + + return table_interface_is_selected (ATK_TABLE (selection), row, column); +} + +/* callbacks */ + +static void +selection_preview_change_cb (ECalendarItem *calitem) +{ + AtkObject *atk_obj; + AtkObject *item_cell; + + g_return_if_fail (E_IS_CALENDAR_ITEM (calitem)); + atk_obj = atk_gobject_accessible_for_object (G_OBJECT (calitem)); + ea_calendar_item_destory_cell_data (EA_CALENDAR_ITEM (atk_obj)); + + /* only deal with the first selected child, for now */ + item_cell = atk_selection_ref_selection (ATK_SELECTION (atk_obj), + 0); + + if (item_cell) + ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_obj), item_cell); + + g_signal_emit_by_name (atk_obj, + "active-descendant-changed", + item_cell); + g_signal_emit_by_name (atk_obj, "selection_changed"); +} + +static void +date_range_changed_cb (ECalendarItem *calitem) +{ + AtkObject *atk_obj; + AtkObject *item_cell; + + g_return_if_fail (E_IS_CALENDAR_ITEM (calitem)); + atk_obj = atk_gobject_accessible_for_object (G_OBJECT (calitem)); + ea_calendar_item_destory_cell_data (EA_CALENDAR_ITEM (atk_obj)); + + item_cell = atk_selection_ref_selection (ATK_SELECTION (atk_obj), + 0); + if (item_cell) + ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_obj), item_cell); + + g_signal_emit_by_name (atk_obj, "model_changed"); +} + +/* helpers */ + +static EaCellTable * +ea_calendar_item_get_cell_data (EaCalendarItem *ea_calitem) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCellTable *cell_data; + + g_return_val_if_fail (ea_calitem, NULL); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return NULL; + + cell_data = g_object_get_data (G_OBJECT(ea_calitem), + "ea-calendar-cell-table"); + + if (!cell_data) { + gint n_cells = ea_calendar_item_get_n_children (ATK_OBJECT(ea_calitem)); + cell_data = ea_cell_table_create (n_cells/EA_CALENDAR_COLUMN_NUM, + EA_CALENDAR_COLUMN_NUM, + FALSE); + g_object_set_data (G_OBJECT(ea_calitem), + "ea-calendar-cell-table", cell_data); + } + return cell_data; +} + +static void +ea_calendar_item_destory_cell_data (EaCalendarItem *ea_calitem) +{ + EaCellTable *cell_data; + + g_return_if_fail (ea_calitem); + + cell_data = g_object_get_data (G_OBJECT(ea_calitem), + "ea-calendar-cell-table"); + if (cell_data) { + g_object_set_data (G_OBJECT(ea_calitem), + "ea-calendar-cell-table", NULL); + ea_cell_table_destroy (cell_data); + } +} + +static gboolean +ea_calendar_item_get_row_label (EaCalendarItem *ea_calitem, gint row, + gchar *buffer, gint buffer_size) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + gint index, week_num; + gint year, month, day; + + g_return_val_if_fail (ea_calitem, FALSE); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + calitem = E_CALENDAR_ITEM (g_obj); + + index = atk_table_get_index_at (ATK_TABLE (ea_calitem), row, 0); + if (!e_calendar_item_get_date_for_offset (calitem, index, + &year, &month, &day)) + return FALSE; + + week_num = e_calendar_item_get_week_number (calitem, + day, month, year); + + g_snprintf (buffer, buffer_size, "week number : %d", week_num); + return TRUE; +} + +static gboolean +ea_calendar_item_get_column_label (EaCalendarItem *ea_calitem, gint column, + gchar *buffer, gint buffer_size) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + const gchar *abbr_name; + + g_return_val_if_fail (ea_calitem, FALSE); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + /* Columns are 0 = Monday ... 6 = Sunday */ + calitem = E_CALENDAR_ITEM (g_obj); + abbr_name = e_get_weekday_name (column + 1, TRUE); + g_strlcpy (buffer, abbr_name, buffer_size); + + return TRUE; +} + +/* the coordinate the e-calendar canvas coord */ +gboolean +e_calendar_item_get_day_extents (ECalendarItem *calitem, + gint year, gint month, gint date, + gint *x, gint *y, + gint *width, gint *height) +{ + GnomeCanvasItem *item; + GtkWidget *widget; + GtkStyle *style; + PangoFontDescription *font_desc; + PangoContext *pango_context; + PangoFontMetrics *font_metrics; + gint char_height, xthickness, ythickness, text_y; + gint new_year, new_month, num_months, months_offset; + gint month_x, month_y, month_cell_x, month_cell_y; + gint month_row, month_col; + gint day_row, day_col; + gint days_from_week_start; + + g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE); + + item = GNOME_CANVAS_ITEM (calitem); + widget = GTK_WIDGET (item->canvas); + style = widget->style; + + /* Set up Pango prerequisites */ + font_desc = calitem->font_desc; + if (!font_desc) + font_desc = style->font_desc; + pango_context = gtk_widget_get_pango_context (widget); + font_metrics = pango_context_get_metrics (pango_context, font_desc, + pango_context_get_language (pango_context)); + + char_height = + PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics)) + + PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics)); + + xthickness = style->xthickness; + ythickness = style->ythickness; + + new_year = year; + new_month = month; + e_calendar_item_normalize_date (calitem, &new_year, &new_month); + num_months = calitem->rows * calitem->cols; + months_offset = (new_year - calitem->year) * 12 + + new_month - calitem->month; + + if (months_offset > num_months || months_offset < 0) + return FALSE; + + month_row = months_offset / calitem->cols; + month_col = months_offset % calitem->cols; + + month_x = item->x1 + xthickness + calitem->x_offset + + month_col * calitem->month_width; + month_y = item->y1 + ythickness + month_row * calitem->month_height; + + month_cell_x = month_x + E_CALENDAR_ITEM_XPAD_BEFORE_WEEK_NUMBERS + + calitem->month_lpad + E_CALENDAR_ITEM_XPAD_BEFORE_CELLS; + text_y = month_y + ythickness * 2 + + E_CALENDAR_ITEM_YPAD_ABOVE_MONTH_NAME + + char_height + E_CALENDAR_ITEM_YPAD_BELOW_MONTH_NAME + + E_CALENDAR_ITEM_YPAD_ABOVE_DAY_LETTERS + calitem->month_tpad; + + month_cell_y = text_y + char_height + + E_CALENDAR_ITEM_YPAD_BELOW_DAY_LETTERS + 1 + + E_CALENDAR_ITEM_YPAD_ABOVE_CELLS; + + days_from_week_start = + e_calendar_item_get_n_days_from_week_start (calitem, new_year, + new_month); + day_row = (date + days_from_week_start - 1) / EA_CALENDAR_COLUMN_NUM; + day_col = (date + days_from_week_start - 1) % EA_CALENDAR_COLUMN_NUM; + + *x = month_cell_x + day_col * calitem->cell_width; + *y = month_cell_y + day_row * calitem->cell_height; + *width = calitem->cell_width; + *height = calitem->cell_height; + + return TRUE; +} + +/* month is from 0 to 11 */ +gboolean +e_calendar_item_get_date_for_offset (ECalendarItem *calitem, gint day_offset, + gint *year, gint *month, gint *day) +{ + gint start_year, start_month, start_day; + gint end_year, end_month, end_day; + GDate *start_date; + + g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE); + + if (!e_calendar_item_get_date_range (calitem, &start_year, + &start_month, &start_day, + &end_year, &end_month, + &end_day)) + return FALSE; + + start_date = g_date_new_dmy (start_day, start_month + 1, start_year); + + g_date_add_days (start_date, day_offset); + + *year = g_date_get_year (start_date); + *month = g_date_get_month (start_date) - 1; + *day = g_date_get_day (start_date); + + return TRUE; +} + +/* the arg month is from 0 to 11 */ +static gboolean +e_calendar_item_get_offset_for_date (ECalendarItem *calitem, + gint year, gint month, gint day, + gint *offset) +{ + gint start_year, start_month, start_day; + gint end_year, end_month, end_day; + GDate *start_date, *end_date; + + *offset = 0; + g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE); + + if (!e_calendar_item_get_date_range (calitem, &start_year, + &start_month, &start_day, + &end_year, &end_month, + &end_day)) + return FALSE; + + start_date = g_date_new_dmy (start_day, start_month + 1, start_year); + end_date = g_date_new_dmy (day, month + 1, year); + + *offset = g_date_days_between (start_date, end_date); + g_free (start_date); + g_free (end_date); + + return TRUE; +} + +gint +e_calendar_item_get_n_days_from_week_start (ECalendarItem *calitem, + gint year, gint month) +{ + struct tm tmp_tm; + gint start_weekday, days_from_week_start; + + memset (&tmp_tm, 0, sizeof (tmp_tm)); + tmp_tm.tm_year = year - 1900; + tmp_tm.tm_mon = month; + tmp_tm.tm_mday = 1; + tmp_tm.tm_isdst = -1; + mktime (&tmp_tm); + start_weekday = (tmp_tm.tm_wday + 6) % 7; /* 0 to 6 */ + days_from_week_start = (start_weekday + 7 - calitem->week_start_day) + % 7; + return days_from_week_start; +} + +static void +ea_calendar_set_focus_object (EaCalendarItem *ea_calitem, AtkObject *item_cell) +{ + AtkStateSet *state_set, *old_state_set; + AtkObject *old_cell; + + old_cell = (AtkObject *)g_object_get_data (G_OBJECT(ea_calitem), "gail-focus-object"); + if (old_cell && EA_IS_CALENDAR_CELL (old_cell)) { + old_state_set = atk_object_ref_state_set (old_cell); + atk_state_set_remove_state (old_state_set, ATK_STATE_FOCUSED); + g_object_unref (old_state_set); + } + if (old_cell) + g_object_unref (old_cell); + + state_set = atk_object_ref_state_set (item_cell); + atk_state_set_add_state (state_set, ATK_STATE_FOCUSED); + g_object_set_data (G_OBJECT(ea_calitem), "gail-focus-object", item_cell); + g_object_unref (state_set); +} diff --git a/widgets/misc/ea-calendar-item.h b/widgets/misc/ea-calendar-item.h new file mode 100644 index 0000000000..b5271a9f8b --- /dev/null +++ b/widgets/misc/ea-calendar-item.h @@ -0,0 +1,67 @@ +/* + * 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: + * Bolian Yin <bolian.yin@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __EA_CALENDAR_ITEM_H__ +#define __EA_CALENDAR_ITEM_H__ + +#include <atk/atkgobjectaccessible.h> +#include <misc/e-calendar-item.h> + +G_BEGIN_DECLS + +#define EA_TYPE_CALENDAR_ITEM (ea_calendar_item_get_type ()) +#define EA_CALENDAR_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EA_TYPE_CALENDAR_ITEM, EaCalendarItem)) +#define EA_CALENDAR_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EA_TYPE_CALENDAR_ITEM, EaCalendarItemClass)) +#define EA_IS_CALENDAR_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EA_TYPE_CALENDAR_ITEM)) +#define EA_IS_CALENDAR_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EA_TYPE_CALENDAR_ITEM)) +#define EA_CALENDAR_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EA_TYPE_CALENDAR_ITEM, EaCalendarItemClass)) + +typedef struct _EaCalendarItem EaCalendarItem; +typedef struct _EaCalendarItemClass EaCalendarItemClass; + +struct _EaCalendarItem +{ + AtkGObjectAccessible parent; +}; + +GType ea_calendar_item_get_type (void); + +struct _EaCalendarItemClass +{ + AtkGObjectAccessibleClass parent_class; +}; + +AtkObject *ea_calendar_item_new (GObject *obj); +gboolean e_calendar_item_get_day_extents (ECalendarItem *calitem, + gint year, gint month, gint date, + gint *x, gint *y, + gint *width, gint *height); +gboolean e_calendar_item_get_date_for_offset (ECalendarItem *calitem, + gint day_offset, + gint *year, gint *month, + gint *day); +gint e_calendar_item_get_n_days_from_week_start (ECalendarItem *calitem, + gint year, gint month); + +G_END_DECLS + +#endif /* __EA_CALENDAR_ITEM_H__ */ diff --git a/widgets/misc/ea-cell-table.c b/widgets/misc/ea-cell-table.c new file mode 100644 index 0000000000..95ae59dea4 --- /dev/null +++ b/widgets/misc/ea-cell-table.c @@ -0,0 +1,202 @@ +/* + * 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: + * Bolian Yin <bolian.yin@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "ea-cell-table.h" + +EaCellTable * +ea_cell_table_create (gint rows, gint columns, gboolean column_first) +{ + EaCellTable * cell_data; + gint index; + + g_return_val_if_fail (((columns > 0) && (rows > 0)), NULL); + + cell_data = g_new0 (EaCellTable, 1); + + cell_data->column_first = column_first; + cell_data->columns = columns; + cell_data->rows = rows; + + cell_data->column_labels = g_new0 (gchar *, columns); + for (index = columns -1; index >= 0; --index) + cell_data->column_labels [index] = NULL; + + cell_data->row_labels = g_new0 (gchar *, rows); + for (index = rows -1; index >= 0; --index) + cell_data->row_labels [index] = NULL; + + cell_data->cells = g_new0(gpointer, (columns * rows)); + for (index = (columns * rows) -1; index >= 0; --index) + cell_data->cells [index] = NULL; + return cell_data; +} + +void +ea_cell_table_destroy (EaCellTable * cell_data) +{ + gint index; + g_return_if_fail (cell_data); + + for (index = 0; index < cell_data->columns; ++index) + if (cell_data->column_labels [index]) + g_free (cell_data->column_labels [index]); + g_free (cell_data->column_labels); + + for (index = 0; index < cell_data->rows; ++index) + if (cell_data->row_labels [index]) + g_free (cell_data->row_labels [index]); + g_free (cell_data->row_labels); + + for (index = (cell_data->columns * cell_data->rows) -1; + index >= 0; --index) + if (cell_data->cells[index] && + G_IS_OBJECT (cell_data->cells[index])) + g_object_unref (cell_data->cells[index]); + + g_free (cell_data->cells); +} + +gpointer +ea_cell_table_get_cell (EaCellTable * cell_data, + gint row, gint column) +{ + gint index; + + g_return_val_if_fail (cell_data, NULL); + + index = ea_cell_table_get_index (cell_data, column, row); + if (index == -1) + return NULL; + + return cell_data->cells[index]; +} + +gboolean +ea_cell_table_set_cell (EaCellTable * cell_data, + gint row, gint column, gpointer cell) +{ + gint index; + + g_return_val_if_fail (cell_data, FALSE); + + index = ea_cell_table_get_index (cell_data, column, row); + if (index == -1) + return FALSE; + + if (cell && G_IS_OBJECT(cell)) + g_object_ref (cell); + if (cell_data->cells[index] && + G_IS_OBJECT (cell_data->cells[index])) + g_object_unref (cell_data->cells[index]); + cell_data->cells[index] = cell; + + return TRUE; +} + +gpointer +ea_cell_table_get_cell_at_index (EaCellTable * cell_data, + gint index) +{ + g_return_val_if_fail (cell_data, NULL); + + if (index >=0 && index < (cell_data->columns * cell_data->rows)) + return cell_data->cells [index]; + return NULL; +} + +gboolean +ea_cell_table_set_cell_at_index (EaCellTable * cell_data, + gint index, gpointer cell) +{ + g_return_val_if_fail (cell_data, FALSE); + + if (index < 0 || index >=cell_data->columns * cell_data->rows) + return FALSE; + + if (cell && G_IS_OBJECT(cell)) + g_object_ref (cell); + if (cell_data->cells[index] && + G_IS_OBJECT (cell_data->cells[index])) + g_object_unref (cell_data->cells[index]); + cell_data->cells[index] = cell; + + return TRUE; +} + +G_CONST_RETURN gchar * +ea_cell_table_get_column_label (EaCellTable * cell_data, + gint column) +{ + g_return_val_if_fail (cell_data, NULL); + g_return_val_if_fail ((column >= 0 && column < cell_data->columns), NULL); + + return cell_data->column_labels[column]; +} + +void +ea_cell_table_set_column_label (EaCellTable * cell_data, + gint column, const gchar *label) +{ + g_return_if_fail (cell_data); + g_return_if_fail ((column >= 0 && column < cell_data->columns)); + + if (cell_data->column_labels[column]) + g_free (cell_data->column_labels[column]); + cell_data->column_labels[column] = g_strdup(label); +} + +G_CONST_RETURN gchar * +ea_cell_table_get_row_label (EaCellTable * cell_data, + gint row) +{ + g_return_val_if_fail (cell_data, NULL); + g_return_val_if_fail ((row >= 0 && row < cell_data->rows), NULL); + + return cell_data->row_labels[row]; +} + +void +ea_cell_table_set_row_label (EaCellTable * cell_data, + gint row, const gchar *label) +{ + g_return_if_fail (cell_data); + g_return_if_fail ((row >= 0 && row < cell_data->rows)); + + if (cell_data->row_labels[row]) + g_free (cell_data->row_labels[row]); + cell_data->row_labels[row] = g_strdup(label); +} + +gint +ea_cell_table_get_index (EaCellTable *cell_data, + gint row, gint column) +{ + g_return_val_if_fail (cell_data, -1); + if (row < 0 || row >= cell_data->rows || + column < 0 || column >= cell_data->columns) + return -1; + + if (cell_data->column_first) + return column * cell_data->rows + row; + else + return row * cell_data->columns + column; +} diff --git a/widgets/misc/ea-cell-table.h b/widgets/misc/ea-cell-table.h new file mode 100644 index 0000000000..353bbd0634 --- /dev/null +++ b/widgets/misc/ea-cell-table.h @@ -0,0 +1,60 @@ +/* + * 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: + * Bolian Yin <bolian.yin@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +/* EaCellTable */ + +#include <glib.h> +#include <glib-object.h> + +struct _EaCellTable { + gint columns; + gint rows; + gboolean column_first; /* index order */ + gchar **column_labels; + gchar **row_labels; + gpointer *cells; +}; + +typedef struct _EaCellTable EaCellTable; + +EaCellTable * ea_cell_table_create (gint rows, gint columns, + gboolean column_first); +void ea_cell_table_destroy (EaCellTable * cell_data); +gpointer ea_cell_table_get_cell (EaCellTable * cell_data, + gint row, gint column); +gboolean ea_cell_table_set_cell (EaCellTable * cell_data, + gint row, gint column, gpointer cell); +gpointer ea_cell_table_get_cell_at_index (EaCellTable * cell_data, + gint index); +gboolean ea_cell_table_set_cell_at_index (EaCellTable * cell_data, + gint index, gpointer cell); + +G_CONST_RETURN gchar * +ea_cell_table_get_column_label (EaCellTable * cell_data, gint column); +void ea_cell_table_set_column_label (EaCellTable * cell_data, + gint column, const gchar *label); +G_CONST_RETURN gchar * +ea_cell_table_get_row_label (EaCellTable * cell_data, gint row); +void ea_cell_table_set_row_label (EaCellTable * cell_data, + gint row, const gchar *label); +gint ea_cell_table_get_index (EaCellTable *cell_data, + gint row, gint column); diff --git a/widgets/misc/e-config-page.c b/widgets/misc/ea-widgets.c index 922a26960c..9deede235e 100644 --- a/widgets/misc/e-config-page.c +++ b/widgets/misc/ea-widgets.c @@ -14,35 +14,19 @@ * * * Authors: - * Ettore Perazzoli <ettore@ximian.com> + * Bolian Yin <bolian.yin@sun.com> * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif +#include "a11y/ea-factory.h" +#include "ea-calendar-item.h" +#include "ea-widgets.h" -#include "e-config-page.h" +EA_FACTORY_GOBJECT (EA_TYPE_CALENDAR_ITEM, ea_calendar_item, ea_calendar_item_new) -G_DEFINE_TYPE (EConfigPage, e_config_page, GTK_TYPE_EVENT_BOX) - -/* GObject methods. */ - -static void -e_config_page_class_init (EConfigPageClass *class) -{ -} - -static void -e_config_page_init (EConfigPage *page) +void e_calendar_item_a11y_init (void) { + EA_SET_FACTORY (e_calendar_item_get_type (), ea_calendar_item); } - -GtkWidget * -e_config_page_new (void) -{ - return g_object_new (e_config_page_get_type (), NULL); -} - diff --git a/widgets/table/table-test.h b/widgets/misc/ea-widgets.h index 8b179bafdf..495222ae05 100644 --- a/widgets/table/table-test.h +++ b/widgets/misc/ea-widgets.h @@ -15,13 +15,18 @@ * * * Authors: - * Miguel de Icaza (miguel@gnu.org) + * Bolian Yin <bolian.yin@sun.com> * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ -void table_browser_test (void); -void multi_cols_test (void); -void check_test (void); -void e_table_test (void); +/* Evolution Accessibility +*/ + +#ifndef _EA_WIDGETS_H__ +#define _EA_WIDGETS_H__ + +void e_calendar_item_a11y_init (void); + +#endif /* _EA_WIDGETS_H__ */ diff --git a/widgets/misc/test-calendar.c b/widgets/misc/test-calendar.c index c9cc8e7891..458d60f90a 100644 --- a/widgets/misc/test-calendar.c +++ b/widgets/misc/test-calendar.c @@ -114,7 +114,7 @@ on_date_range_changed (ECalendarItem *calitem) start_day, start_month + 1, start_year, end_day, end_month + 1, end_year); - /* These days should appear bold. Remember month is 0 to 11. */ + /* These days should windowear bold. Remember month is 0 to 11. */ e_calendar_item_mark_day (calitem, 2000, 7, 26, /* 26th Aug 2000. */ E_CALENDAR_ITEM_MARK_BOLD, FALSE); e_calendar_item_mark_day (calitem, 2000, 8, 13, /* 13th Sep 2000. */ diff --git a/widgets/misc/test-dropdown-button.c b/widgets/misc/test-dropdown-button.c deleted file mode 100644 index 7320fb9bac..0000000000 --- a/widgets/misc/test-dropdown-button.c +++ /dev/null @@ -1,99 +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> - * Damon Chaplin <damon@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <gtk/gtk.h> - -#include <libgnomeui/gnome-app.h> -#include <libgnomeui/gnome-app-helper.h> -#include <libgnomeui/gnome-ui-init.h> - -#include "e-dropdown-button.h" - - -/* (The following is shameless stolen from `testgnome.c'. */ - -static void -item_activated (GtkWidget *widget, - gpointer data) -{ - printf ("%s activated.\n", (gchar *) data); -} - -static GnomeUIInfo ui_info[] = { - { GNOME_APP_UI_ITEM, "_New", "Create a new file", item_activated, (gpointer) "file/new", NULL, - GNOME_APP_PIXMAP_STOCK, GTK_STOCK_NEW, 'n', GDK_CONTROL_MASK, NULL }, - { GNOME_APP_UI_ITEM, "_Open...", "Open an existing file", item_activated, (gpointer) "file/open", NULL, - GNOME_APP_PIXMAP_STOCK, GTK_STOCK_OPEN, 'o', GDK_CONTROL_MASK, NULL }, - { GNOME_APP_UI_ITEM, "_Save", "Save the current file", item_activated, (gpointer) "file/save", NULL, - GNOME_APP_PIXMAP_STOCK, GTK_STOCK_SAVE, 's', GDK_CONTROL_MASK, NULL }, - { GNOME_APP_UI_ITEM, "Save _as...", "Save the current file with a new name", item_activated, (gpointer) "file/save as", NULL, - GNOME_APP_PIXMAP_STOCK, GTK_STOCK_SAVE_AS, 0, 0, NULL }, - - GNOMEUIINFO_SEPARATOR, - - { GNOME_APP_UI_ITEM, "_Print...", "Print the current file", item_activated, (gpointer) "file/print", NULL, - GNOME_APP_PIXMAP_STOCK, GTK_STOCK_PRINT, 'p', GDK_CONTROL_MASK, NULL }, - - GNOMEUIINFO_SEPARATOR, - - { GNOME_APP_UI_ITEM, "_Close", "Close the current file", item_activated, (gpointer) "file/close", NULL, - GNOME_APP_PIXMAP_STOCK, GTK_STOCK_CLOSE, 0, 0, NULL }, - { GNOME_APP_UI_ITEM, "E_xit", "Exit the program", item_activated, (gpointer) "file/exit", NULL, - GNOME_APP_PIXMAP_STOCK, GTK_STOCK_QUIT, 'q', GDK_CONTROL_MASK, NULL }, - GNOMEUIINFO_END -}; - - -gint -main (gint argc, gchar **argv) -{ - GtkWidget *window; - GtkWidget *menu; - GtkWidget *dropdown_button; - - gnome_program_init ( - "test-dropdown-button", "0.0", LIBGNOMEUI_MODULE, - argc, argv, GNOME_PARAM_NONE); - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_default_size (GTK_WINDOW (window), 1, 1); - - menu = gtk_menu_new (); - - gnome_app_fill_menu (GTK_MENU_SHELL (menu), ui_info, NULL, TRUE, 0); - - dropdown_button = e_dropdown_button_new ("Me_nu", GTK_MENU (menu)); - gtk_container_add (GTK_CONTAINER (window), dropdown_button); - - gtk_widget_show (window); - gtk_widget_show (dropdown_button); - - gtk_main (); - - return 0; -} diff --git a/widgets/misc/test-error.c b/widgets/misc/test-error.c deleted file mode 100644 index a7d584bf6c..0000000000 --- a/widgets/misc/test-error.c +++ /dev/null @@ -1,61 +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 "e-error.h" - -gint -main (gint argc, gchar **argv) -{ - gtk_init (&argc, &argv); - - argc--; - switch (argc) { - case 1: - e_error_run(NULL, argv[1], NULL); - break; - case 2: - e_error_run(NULL, argv[1], argv[2], NULL); - break; - case 3: - e_error_run(NULL, argv[1], argv[2], argv[3], NULL); - break; - case 4: - e_error_run(NULL, argv[1], argv[2], argv[3], argv[4], NULL); - break; - case 5: - e_error_run(NULL, argv[1], argv[2], argv[3], argv[4], argv[5], NULL); - break; - case 6: - e_error_run(NULL, argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], NULL); - break; - default: - printf("Error: too many or too few arguments\n"); - printf("Usage:\n %s domain:error-id [ args ... ]\n", argv[0]); - } - - return 0; -} diff --git a/widgets/misc/test-info-label.c b/widgets/misc/test-info-label.c deleted file mode 100644 index 0f292a0487..0000000000 --- a/widgets/misc/test-info-label.c +++ /dev/null @@ -1,75 +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) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <gtk/gtk.h> -#include "e-info-label.h" - -static void -delete_event_cb (GtkWidget *widget, - GdkEventAny *event, - gpointer data) -{ - gtk_main_quit (); -} - -gint -main (gint argc, gchar **argv) -{ - GtkWidget *window; - GtkWidget *info_label; - GtkWidget *label; - GtkWidget *vbox; - - gtk_init (&argc, &argv); - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (window), "EInfoLabel Test"); - gtk_window_set_default_size (GTK_WINDOW (window), 400, 400); - gtk_window_set_resizable (GTK_WINDOW (window), TRUE); - - g_signal_connect (window, "delete_event", - G_CALLBACK (delete_event_cb), NULL); - - info_label = e_info_label_new ("stock_default-folder"); - e_info_label_set_info ((EInfoLabel *) info_label, "Component Name", "An annoyingly long component message"); - gtk_widget_show (info_label); - - label = gtk_label_new ("boo"); - gtk_widget_show (label); - - vbox = gtk_vbox_new (FALSE, 0); - gtk_box_pack_start (GTK_BOX (vbox), info_label, FALSE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); - gtk_widget_show (vbox); - - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (window); - - gtk_main (); - - return 0; -} diff --git a/widgets/misc/test-multi-config-dialog.c b/widgets/misc/test-preferences-window.c index 14327cd6ae..c5291cf755 100644 --- a/widgets/misc/test-multi-config-dialog.c +++ b/widgets/misc/test-preferences-window.c @@ -1,4 +1,6 @@ /* + * test-preferences-window.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 @@ -13,49 +15,38 @@ * 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 "e-multi-config-dialog.c" +#include "e-preferences-window.c" #include <gtk/gtk.h> - #define NUM_PAGES 10 - static void -add_pages (EMultiConfigDialog *multi_config_dialog) +add_pages (EPreferencesWindow *preferences_window) { gint i; for (i = 0; i < NUM_PAGES; i ++) { GtkWidget *widget; - GtkWidget *page; - gchar *string; - gchar *title; - gchar *description; + gchar *caption; + gchar *page_name; - string = g_strdup_printf ("This is page %d", i); - description = g_strdup_printf ("Description of page %d", i); - title = g_strdup_printf ("Title of page %d", i); + caption = g_strdup_printf ("Title of page %d", i); + page_name = g_strdup_printf ("page-%d", i); - widget = gtk_label_new (string); + widget = gtk_label_new (caption); gtk_widget_show (widget); - page = e_config_page_new (); - gtk_container_add (GTK_CONTAINER (page), widget); - - e_multi_config_dialog_add_page (multi_config_dialog, title, description, NULL, - E_CONFIG_PAGE (page)); + e_preferences_window_add_page ( + preferences_window, page_name, + "gtk-properties", caption, widget, i); - g_free (string); - g_free (title); - g_free (description); + g_free (caption); + g_free (page_name); } } @@ -69,23 +60,23 @@ delete_event_callback (GtkWidget *widget, return TRUE; } - gint main (gint argc, gchar **argv) { - GtkWidget *dialog; + GtkWidget *window; gtk_init (&argc, &argv); - dialog = e_multi_config_dialog_new (); + window = e_preferences_window_new (); + gtk_window_set_default_size (GTK_WINDOW (window), 400, 300); g_signal_connect( - dialog, "delete-event", + window, "delete-event", G_CALLBACK (delete_event_callback), NULL); - add_pages (E_MULTI_CONFIG_DIALOG (dialog)); + add_pages (E_PREFERENCES_WINDOW (window)); - gtk_widget_show (dialog); + gtk_widget_show (window); gtk_main (); diff --git a/widgets/table/Makefile.am b/widgets/table/Makefile.am index 4ae0861027..7a8a5c7fab 100644 --- a/widgets/table/Makefile.am +++ b/widgets/table/Makefile.am @@ -1,16 +1,11 @@ -if OS_WIN32 -WIN32_BOOTSTRAP_LIBS = \ - $(top_builddir)/win32/libemiscwidgets.la \ - $(top_builddir)/win32/libetext.la -endif - glade_DATA = \ e-table-config.glade \ e-table-field-chooser.glade AM_CPPFLAGS = \ - -I$(top_srcdir) \ - -I$(top_srcdir)/widgets \ + -I$(top_srcdir) \ + -I$(top_srcdir)/widgets \ + $(E_UTIL_CFLAGS) \ $(E_WIDGETS_CFLAGS) \ $(GNOME_PLATFORM_CFLAGS) \ -DEVOLUTION_GLADEDIR=\"$(gladedir)\" \ @@ -23,7 +18,9 @@ libetable_la_SOURCES = \ e-cell-checkbox.c \ e-cell-combo.c \ e-cell-date.c \ + e-cell-date-edit.c \ e-cell-number.c \ + e-cell-percent.c \ e-cell-pixbuf.c \ e-cell-popup.c \ e-cell-size.c \ @@ -75,7 +72,23 @@ libetable_la_SOURCES = \ e-tree-selection-model.c \ e-tree-sorted.c \ e-tree-table-adapter.c \ - e-tree.c + e-tree.c \ + gal-a11y-e-cell.c \ + gal-a11y-e-cell-popup.c \ + gal-a11y-e-cell-registry.c \ + gal-a11y-e-cell-text.c \ + gal-a11y-e-cell-toggle.c \ + gal-a11y-e-cell-tree.c \ + gal-a11y-e-cell-vbox.c \ + gal-a11y-e-table.c \ + gal-a11y-e-table-click-to-add.c \ + gal-a11y-e-table-click-to-add-factory.c \ + gal-a11y-e-table-column-header.c \ + gal-a11y-e-table-factory.c \ + gal-a11y-e-table-item.c \ + gal-a11y-e-table-item-factory.c \ + gal-a11y-e-tree.c \ + gal-a11y-e-tree-factory.c libetableincludedir = $(privincludedir)/table @@ -84,7 +97,9 @@ libetableinclude_HEADERS = \ e-cell-checkbox.h \ e-cell-combo.h \ e-cell-date.h \ + e-cell-date-edit.h \ e-cell-number.h \ + e-cell-percent.h \ e-cell-pixbuf.h \ e-cell-popup.h \ e-cell-size.h \ @@ -139,15 +154,34 @@ libetableinclude_HEADERS = \ e-tree-selection-model.h \ e-tree-sorted.h \ e-tree-table-adapter.h \ - e-tree.h + e-tree.h \ + gal-a11y-e-cell.h \ + gal-a11y-e-cell-popup.h \ + gal-a11y-e-cell-registry.h \ + gal-a11y-e-cell-text.h \ + gal-a11y-e-cell-toggle.h \ + gal-a11y-e-cell-tree.h \ + gal-a11y-e-cell-vbox.h \ + gal-a11y-e-table.h \ + gal-a11y-e-table-click-to-add.h \ + gal-a11y-e-table-click-to-add-factory.h \ + gal-a11y-e-table-column-header.h \ + gal-a11y-e-table-factory.h \ + gal-a11y-e-table-item.h \ + gal-a11y-e-table-item-factory.h \ + gal-a11y-e-tree.h \ + gal-a11y-e-tree-factory.h libetable_la_LDFLAGS = $(NO_UNDEFINED) libetable_la_LIBADD = \ - $(WIN32_BOOTSTRAP_LIBS) \ - $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/a11y/libevolution-a11y.la \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/widgets/misc/libemiscwidgets.la \ + $(top_builddir)/widgets/text/libetext.la \ + $(E_UTIL_LIBS) \ $(E_WIDGETS_LIBS) \ + $(MATH_LIB) \ $(GNOME_PLATFORM_LIBS) icons = \ diff --git a/widgets/table/e-cell-combo.c b/widgets/table/e-cell-combo.c index 988ba8e12f..af79261c64 100644 --- a/widgets/table/e-cell-combo.c +++ b/widgets/table/e-cell-combo.c @@ -62,7 +62,7 @@ #include <glib/gi18n.h> #include "e-util/e-util.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include "e-table-item.h" #include "e-cell-combo.h" diff --git a/widgets/misc/e-cell-date-edit.c b/widgets/table/e-cell-date-edit.c index dfbe183f88..1848b2808a 100644 --- a/widgets/misc/e-cell-date-edit.c +++ b/widgets/table/e-cell-date-edit.c @@ -38,15 +38,15 @@ #include <gdk/gdkkeysyms.h> #include <gtk/gtk.h> -#include <table/e-table-item.h> -#include <table/e-cell-text.h> +#include "e-table-item.h" +#include "e-cell-text.h" #include <glib/gi18n.h> #include <libedataserver/e-time-utils.h> /* This depends on ECalendar which is why I didn't put it in gal. */ -#include "e-calendar.h" +#include <misc/e-calendar.h> static void e_cell_date_edit_destroy (GtkObject *object); static void e_cell_date_edit_get_property (GObject *object, diff --git a/widgets/misc/e-cell-date-edit.h b/widgets/table/e-cell-date-edit.h index 72fe952e31..72fe952e31 100644 --- a/widgets/misc/e-cell-date-edit.h +++ b/widgets/table/e-cell-date-edit.h diff --git a/widgets/table/e-cell-date.c b/widgets/table/e-cell-date.c index 6e95a1f5ea..d9dcbbea3b 100644 --- a/widgets/table/e-cell-date.c +++ b/widgets/table/e-cell-date.c @@ -29,7 +29,7 @@ #include <glib/gi18n.h> #include "e-util/e-util.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include "e-cell-date.h" diff --git a/widgets/table/e-cell-hbox.c b/widgets/table/e-cell-hbox.c index 8fd82a9504..53d1b79934 100644 --- a/widgets/table/e-cell-hbox.c +++ b/widgets/table/e-cell-hbox.c @@ -32,8 +32,8 @@ #include <gtk/gtk.h> -/* #include "a11y/e-table/gal-a11y-e-cell-registry.h" */ -/* #include "a11y/e-table/gal-a11y-e-cell-vbox.h" */ +/* #include "a11y/gal-a11y-e-cell-registry.h" */ +/* #include "a11y/gal-a11y-e-cell-vbox.h" */ #include "e-util/e-util.h" #include "e-cell-hbox.h" diff --git a/widgets/misc/e-cell-percent.c b/widgets/table/e-cell-percent.c index 3ed995421b..3ed995421b 100644 --- a/widgets/misc/e-cell-percent.c +++ b/widgets/table/e-cell-percent.c diff --git a/widgets/misc/e-cell-percent.h b/widgets/table/e-cell-percent.h index 3ac15afab7..3ac15afab7 100644 --- a/widgets/misc/e-cell-percent.h +++ b/widgets/table/e-cell-percent.h diff --git a/widgets/table/e-cell-popup.c b/widgets/table/e-cell-popup.c index b427a0c24f..45c6d07377 100644 --- a/widgets/table/e-cell-popup.c +++ b/widgets/table/e-cell-popup.c @@ -33,8 +33,8 @@ #include <gdk/gdkkeysyms.h> -#include "a11y/e-table/gal-a11y-e-cell-popup.h" -#include "a11y/e-table/gal-a11y-e-cell-registry.h" +#include "gal-a11y-e-cell-popup.h" +#include "gal-a11y-e-cell-registry.h" #include "e-util/e-util.h" #include "e-cell-popup.h" diff --git a/widgets/table/e-cell-text.c b/widgets/table/e-cell-text.c index f960760189..9f7d7f113a 100644 --- a/widgets/table/e-cell-text.c +++ b/widgets/table/e-cell-text.c @@ -45,15 +45,15 @@ #include <libgnomecanvas/gnome-canvas.h> #include <libgnomecanvas/gnome-canvas-rect-ellipse.h> -#include "a11y/e-table/gal-a11y-e-cell-registry.h" -#include "a11y/e-table/gal-a11y-e-cell-text.h" +#include "gal-a11y-e-cell-registry.h" +#include "gal-a11y-e-cell-text.h" #include "text/e-text.h" #include <glib/gi18n.h> #include "e-util/e-text-event-processor.h" #include "e-util/e-text-event-processor-emacs-like.h" #include "e-util/e-util.h" #include "misc/e-canvas.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include "e-cell-text.h" #include "e-table-item.h" diff --git a/widgets/table/e-cell-toggle.c b/widgets/table/e-cell-toggle.c index 45e6c50651..db047f1220 100644 --- a/widgets/table/e-cell-toggle.c +++ b/widgets/table/e-cell-toggle.c @@ -28,8 +28,8 @@ #include <gtk/gtk.h> #include <libgnomecanvas/gnome-canvas.h> -#include "a11y/e-table/gal-a11y-e-cell-toggle.h" -#include "a11y/e-table/gal-a11y-e-cell-registry.h" +#include "gal-a11y-e-cell-toggle.h" +#include "gal-a11y-e-cell-registry.h" #include "e-util/e-util.h" #include "misc/e-hsv-utils.h" diff --git a/widgets/table/e-cell-tree.c b/widgets/table/e-cell-tree.c index 27698f8f67..a22cf6d04b 100644 --- a/widgets/table/e-cell-tree.c +++ b/widgets/table/e-cell-tree.c @@ -38,8 +38,8 @@ #include <gtk/gtk.h> #include <libgnomecanvas/gnome-canvas.h> -#include "a11y/e-table/gal-a11y-e-cell-registry.h" -#include "a11y/e-table/gal-a11y-e-cell-tree.h" +#include "gal-a11y-e-cell-registry.h" +#include "gal-a11y-e-cell-tree.h" #include "e-util/e-util.h" #include "e-cell-tree.h" diff --git a/widgets/table/e-cell-vbox.c b/widgets/table/e-cell-vbox.c index 7759203d32..db12ed14e9 100644 --- a/widgets/table/e-cell-vbox.c +++ b/widgets/table/e-cell-vbox.c @@ -29,8 +29,8 @@ #include <gtk/gtk.h> -#include "a11y/e-table/gal-a11y-e-cell-registry.h" -#include "a11y/e-table/gal-a11y-e-cell-vbox.h" +#include "gal-a11y-e-cell-registry.h" +#include "gal-a11y-e-cell-vbox.h" #include "e-util/e-util.h" #include "e-cell-vbox.h" diff --git a/widgets/table/e-table-click-to-add.c b/widgets/table/e-table-click-to-add.c index 3b9f6d7d8a..57769d1540 100644 --- a/widgets/table/e-table-click-to-add.c +++ b/widgets/table/e-table-click-to-add.c @@ -29,7 +29,7 @@ #include <libgnomecanvas/gnome-canvas-util.h> #include <gdk-pixbuf/gdk-pixbuf.h> -#include "a11y/e-table/gal-a11y-e-table-click-to-add.h" +#include "gal-a11y-e-table-click-to-add.h" #include "text/e-text.h" #include <glib/gi18n.h> #include "e-util/e-util.h" diff --git a/widgets/table/e-table-config.c b/widgets/table/e-table-config.c index 634cadafb3..375e2cf99f 100644 --- a/widgets/table/e-table-config.c +++ b/widgets/table/e-table-config.c @@ -38,7 +38,7 @@ #include <glib/gi18n.h> #include "e-util/e-util-private.h" #include "e-util/e-util.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include "e-table-config.h" #include "e-table-memory-store.h" diff --git a/widgets/table/e-table-example-1.c b/widgets/table/e-table-example-1.c deleted file mode 100644 index a45868bf72..0000000000 --- a/widgets/table/e-table-example-1.c +++ /dev/null @@ -1,305 +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 <stdio.h> -#include <string.h> -#include <gdk-pixbuf/gdk-pixbuf.h> - -#include "gal/e-util/e-cursors.h" -#include "e-table-simple.h" -#include "e-table-header.h" -#include "e-table-header-item.h" -#include "e-table-item.h" -#include "e-cell-text.h" -#include "e-cell-checkbox.h" -#include "e-table.h" - -#include "table-test.h" - -/* - * One way in which we make it simpler to build an ETableModel is through - * the ETableSimple class. Instead of creating your own ETableModel - * class, you simply create a new object of the ETableSimple class. You - * give it a bunch of functions that act as callbacks. - * - * You also get to pass a gpointer to ETableSimple and it gets passed to - * your callbacks. This would be for having multiple models of the same - * type. This is just an example though, so we statically define all the - * data and ignore the gpointer data parameter. - * - * In our example we will be creating a table model with 6 columns and 10 - * rows. This corresponds to having 6 different types of information and - * 10 different sets of data in our database. - * - * The headers will be hard coded, as will be the example data. - * - */ - -/* - * There are two different meanings to the word "column". The first is - * the model column. A model column corresponds to a specific type of - * data. This is very much like the usage in a database table where a - * column is a field in the database. - * - * The second type of column is a view column. A view column - * corresponds to a visually displayed column. Each view column - * corresponds to a specific model column, though a model column may - * have any number of view columns associated with it, from zero to - * greater than one. - * - * Also, a view column doesn't necessarily depend on only one model - * column. In some cases, the view column renderer can be given a - * reference to another column to get extra information about its - * display. -*/ - -#define ROWS 10 -#define COLS 4 - -#define IMPORTANCE_COLUMN 4 -#define COLOR_COLUMN 5 - -/* - * Here we define the initial layout of the table. This is an xml - * format that allows you to change the initial ordering of the - * columns or to do sorting or grouping initially. This specification - * shows all 5 columns, but moves the importance column nearer to the - * front. It also sorts by the "Full Name" column (ascending.) - * Sorting and grouping take the model column as their arguments - * (sorting is specified by the "column" argument to the leaf elemnt. - */ - -#define INITIAL_SPEC "<ETableSpecification> \ - <columns-shown> \ - <column> 0 </column> \ - <column> 4 </column> \ - <column> 1 </column> \ - <column> 2 </column> \ - <column> 3 </column> \ - </columns-shown> \ - <grouping> <leaf column=\"1\" ascending=\"true\"/> </grouping> \ -</ETableSpecification>" - -gchar *headers [COLS] = { - "Email", - "Full Name", - "Address", - "Phone" -}; - -/* - * Virtual Column list: - * 0 Email - * 1 Full Name - * 2 Address - * 3 Phone - */ - -gchar *table_data [ROWS] [COLS]; - -/* - * ETableSimple callbacks - * These are the callbacks that define the behavior of our custom model. - */ - -/* - * Since our model is a constant size, we can just return its size in - * the column and row count fields. - */ - -/* This function returns the number of columns in our ETableModel. */ -static gint -my_col_count (ETableModel *etc, gpointer data) -{ - return COLS; -} - -/* This function returns the number of rows in our ETableModel. */ -static gint -my_row_count (ETableModel *etc, gpointer data) -{ - return ROWS; -} - -/* This function returns the value at a particular point in our ETableModel. */ -static gpointer -my_value_at (ETableModel *etc, gint col, gint row, gpointer data) -{ - return (gpointer) table_data [row] [col]; -} - -/* This function sets the value at a particular point in our ETableModel. */ -static void -my_set_value_at (ETableModel *etc, gint col, gint row, gconstpointer val, gpointer data) -{ - g_free (table_data [row] [col]); - table_data [row] [col] = g_strdup (val); -} - -/* This function returns whether a particular cell is editable. */ -static gboolean -my_is_cell_editable (ETableModel *etc, gint col, gint row, gpointer data) -{ - return TRUE; -} - -/* This function duplicates the value passed to it. */ -static gpointer -my_duplicate_value (ETableModel *etc, gint col, gconstpointer value, gpointer data) -{ - return g_strdup (value); -} - -/* This function frees the value passed to it. */ -static void -my_free_value (ETableModel *etc, gint col, gpointer value, gpointer data) -{ - g_free (value); -} - -/* This function creates an empty value. */ -static gpointer -my_initialize_value (ETableModel *etc, gint col, gpointer data) -{ - return g_strdup (""); -} - -/* This function reports if a value is empty. */ -static gboolean -my_value_is_empty (ETableModel *etc, gint col, gconstpointer value, gpointer data) -{ - return !(value && *(gchar *)value); -} - -/* This function reports if a value is empty. */ -static gchar * -my_value_to_string (ETableModel *etc, gint col, gconstpointer value, gpointer data) -{ - return g_strdup(value); -} - -/* We create a window containing our new table. */ -static void -create_table (void) -{ - GtkWidget *e_table, *window, *frame; - ECell *cell_left_just; - ETableHeader *e_table_header; - gint i, j; - ETableModel *e_table_model = NULL; - - /* First we fill in the simple data. */ - for (i = 0; i < ROWS; i++) { - for (j = 0; j < COLS; j++) - table_data [i] [j] = g_strdup (""); - } - /* Next we create our model. This uses the functions we defined - earlier. */ - e_table_model = e_table_simple_new ( - my_col_count, my_row_count, my_value_at, - my_set_value_at, my_is_cell_editable, - my_duplicate_value, my_free_value, - my_initialize_value, my_value_is_empty, - my_value_to_string, - NULL); - /* - * Next we create a header. The ETableHeader is used in two - * different way. The first is the full_header. This is the - * list of possible columns in the view. The second use is - * completely internal. Many of the ETableHeader functions are - * for that purpose. The only functions we really need are - * e_table_header_new and e_table_header_add_col. - * - * First we create the header. - */ - e_table_header = e_table_header_new (); - - /* - * Next we have to build renderers for all of the columns. - * Since all our columns are text columns, we can simply use - * the same renderer over and over again. If we had different - * types of columns, we could use a different renderer for - * each column. - */ - cell_left_just = e_cell_text_new (e_table_model, NULL, GTK_JUSTIFY_LEFT); - - /* - * Next we create a column object for each view column and add - * them to the header. We don't create a column object for - * the importance column since it will not be shown. - */ - for (i = 0; i < COLS; i++) { - /* Create the column. */ - ETableCol *ecol = e_table_col_new ( - i, headers [i], - 1.0, 20, cell_left_just, - g_str_compare, TRUE); - /* Add it to the header. */ - e_table_header_add_column (e_table_header, ecol, i); - } - - /* - * Here we create a window for our new table. This window - * will get shown and the person will be able to test their - * item. - */ - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - /* This frame is simply to get a bevel around our table. */ - frame = gtk_frame_new (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. - */ - e_table = e_table_new (e_table_header, e_table_model, INITIAL_SPEC); - - /* Build the gtk widget hierarchy. */ - gtk_container_add (GTK_CONTAINER (frame), e_table); - gtk_container_add (GTK_CONTAINER (window), frame); - - /* Size the initial window. */ - gtk_widget_set_size_request (window, 200, 200); - - /* Show it all. */ - gtk_widget_show_all (window); -} - -/* This is the main function which just initializes gnome and call our create_table function */ - -gint -main (gint argc, gchar *argv []) -{ - gnome_init ("TableExample", "TableExample", argc, argv); - e_cursors_init (); - - gtk_widget_push_colormap (gdk_rgb_get_colormap ()); - - create_table (); - - gtk_main (); - - e_cursors_shutdown (); - return 0; -} - diff --git a/widgets/table/e-table-group-container.c b/widgets/table/e-table-group-container.c index 523e948a2d..43513ddc89 100644 --- a/widgets/table/e-table-group-container.c +++ b/widgets/table/e-table-group-container.c @@ -31,7 +31,7 @@ #include "e-util/e-util.h" #include "misc/e-canvas-utils.h" #include "misc/e-canvas.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include "e-table-defines.h" #include "e-table-group-container.h" diff --git a/widgets/table/e-table-header-item.c b/widgets/table/e-table-header-item.c index b3c68be346..d5a02f491a 100644 --- a/widgets/table/e-table-header-item.c +++ b/widgets/table/e-table-header-item.c @@ -912,7 +912,10 @@ ethi_unrealize (GnomeCanvasItem *item) { ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item); - pango_font_description_free (ethi->font_desc); + if (ethi->font_desc != NULL) { + pango_font_description_free (ethi->font_desc); + ethi->font_desc = NULL; + } g_signal_handler_disconnect (item->canvas, ethi->drag_motion_id); g_signal_handler_disconnect (item->canvas, ethi->drag_leave_id); diff --git a/widgets/table/e-table-header-utils.c b/widgets/table/e-table-header-utils.c index 3e3c7f44c9..c87ae40f79 100644 --- a/widgets/table/e-table-header-utils.c +++ b/widgets/table/e-table-header-utils.c @@ -29,7 +29,7 @@ #include <gtk/gtk.h> -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include "e-table-defines.h" #include "e-table-header-utils.h" diff --git a/widgets/table/e-table-item.c b/widgets/table/e-table-item.c index d009774dc9..c8809b6087 100644 --- a/widgets/table/e-table-item.c +++ b/widgets/table/e-table-item.c @@ -36,8 +36,8 @@ #include <gtk/gtk.h> #include <gdk/gdkkeysyms.h> -#include "a11y/e-table/gal-a11y-e-table-item-factory.h" -#include "a11y/e-table/gal-a11y-e-table-item.h" +#include "gal-a11y-e-table-item-factory.h" +#include "gal-a11y-e-table-item.h" #include <glib/gi18n.h> #include "e-util/e-util.h" #include "misc/e-canvas.h" diff --git a/widgets/table/e-table-tree.h b/widgets/table/e-table-tree.h deleted file mode 100644 index 178c2a3ba2..0000000000 --- a/widgets/table/e-table-tree.h +++ /dev/null @@ -1,48 +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) - * - */ - -#ifndef _E_TABLE_TREE_H_ -#define _E_TABLE_TREE_H_ - -#include <table/e-table-model.h> - -G_BEGIN_DECLS - -typedef struct { - gchar *title; - - union { - ETableModel *table; - GList *children; - } u; - - guint expanded :1; - guint is_leaf :1; -} ETableGroup; - -ETableGroup *e_table_group_new (const gchar *title, ETableModel *table); -ETableGroup *e_table_group_new_leaf (const gchar *title); - -G_END_DECLS - -#endif /* _E_TABLE_TREE_H_ */ diff --git a/widgets/table/e-table-utils.c b/widgets/table/e-table-utils.c index 784f1f5b66..03c8e17a33 100644 --- a/widgets/table/e-table-utils.c +++ b/widgets/table/e-table-utils.c @@ -27,7 +27,7 @@ #include <string.h> #include "e-util/e-util.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include "e-table-utils.h" #include "e-table-header-utils.h" diff --git a/widgets/table/e-table.c b/widgets/table/e-table.c index b25ae6a3ce..96e5e57d7b 100644 --- a/widgets/table/e-table.c +++ b/widgets/table/e-table.c @@ -36,13 +36,13 @@ #include <libgnomecanvas/gnome-canvas.h> #include <libgnomecanvas/gnome-canvas-rect-ellipse.h> -#include "a11y/e-table/gal-a11y-e-table.h" +#include "gal-a11y-e-table.h" #include <glib/gi18n.h> #include "e-util/e-util.h" #include "misc/e-canvas.h" #include "misc/e-canvas-background.h" #include "misc/e-canvas-vbox.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include "e-table.h" #include "e-table-click-to-add.h" diff --git a/widgets/table/e-tree.c b/widgets/table/e-tree.c index 8c8b05e2d4..38c7a5111b 100644 --- a/widgets/table/e-tree.c +++ b/widgets/table/e-tree.c @@ -30,7 +30,7 @@ #include <gtk/gtk.h> #include <libgnomecanvas/gnome-canvas-rect-ellipse.h> -#include "a11y/e-table/gal-a11y-e-tree.h" +#include "gal-a11y-e-tree.h" #include <glib/gi18n.h> #include "e-util/e-util.h" #include "misc/e-canvas.h" diff --git a/widgets/table/gal-a11y-e-cell-popup.c b/widgets/table/gal-a11y-e-cell-popup.c new file mode 100644 index 0000000000..141ce172a4 --- /dev/null +++ b/widgets/table/gal-a11y-e-cell-popup.c @@ -0,0 +1,144 @@ +/* + * 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: + * Yang Wu <yang.wu@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include <gdk/gdkkeysyms.h> +#include <gtk/gtk.h> + +#include "a11y/gal-a11y-util.h" +#include "table/e-cell-popup.h" +#include <glib/gi18n.h> + +#include "gal-a11y-e-cell-popup.h" +#include "gal-a11y-e-cell-registry.h" + +static AtkObjectClass *parent_class = NULL; +#define PARENT_TYPE (gal_a11y_e_cell_get_type ()) + +static void gal_a11y_e_cell_popup_class_init (GalA11yECellPopupClass *klass); +static void popup_cell_action (GalA11yECell *cell); + +/** + * gal_a11y_e_cell_popup_get_type: + * @void: + * + * Registers the &GalA11yECellPopup class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yECellPopup class. + **/ +GType +gal_a11y_e_cell_popup_get_type (void) +{ + static GType type = 0; + + if (!type) { + GTypeInfo info = { + sizeof (GalA11yECellPopupClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gal_a11y_e_cell_popup_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yECellPopup), + 0, + (GInstanceInitFunc) NULL, + NULL /* value_cell_popup */ + }; + + type = g_type_register_static (PARENT_TYPE, "GalA11yECellPopup", &info, 0); + gal_a11y_e_cell_type_add_action_interface (type); + } + + return type; +} + +static void +gal_a11y_e_cell_popup_class_init (GalA11yECellPopupClass *klass) +{ + parent_class = g_type_class_ref (PARENT_TYPE); +} + +AtkObject * +gal_a11y_e_cell_popup_new (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row) +{ + AtkObject *a11y; + GalA11yECell *cell; + ECellPopup *popupcell; + ECellView* child_view = NULL; + + popupcell= E_CELL_POPUP(cell_view->ecell); + + if (popupcell && popupcell->popup_cell_view) + child_view = popupcell->popup_cell_view->child_view; + + if (child_view && child_view->ecell) { + a11y = gal_a11y_e_cell_registry_get_object (NULL, + item, + child_view, + parent, + model_col, + view_col, + row); + } else { + a11y = g_object_new (GAL_A11Y_TYPE_E_CELL_POPUP, NULL); + gal_a11y_e_cell_construct (a11y, + item, + cell_view, + parent, + model_col, + view_col, + row); + } + g_return_val_if_fail (a11y != NULL, NULL); + cell = GAL_A11Y_E_CELL(a11y); + gal_a11y_e_cell_add_action (cell, + _("popup"), /* action name*/ + _("popup a child"), /* action description */ + "<Alt>Down", /* action keybinding */ + popup_cell_action); + + a11y->role = ATK_ROLE_TABLE_CELL; + return a11y; +} + +static void +popup_cell_action (GalA11yECell *cell) +{ + gint finished; + GdkEvent event; + + event.key.type = GDK_KEY_PRESS; + event.key.window = GTK_LAYOUT(GNOME_CANVAS_ITEM(cell->item)->canvas)->bin_window;; + event.key.send_event = TRUE; + event.key.time = GDK_CURRENT_TIME; + event.key.state = GDK_MOD1_MASK; + event.key.keyval = GDK_Down; + + g_signal_emit_by_name (cell->item, "event", &event, &finished); +} diff --git a/widgets/table/gal-a11y-e-cell-popup.h b/widgets/table/gal-a11y-e-cell-popup.h new file mode 100644 index 0000000000..9729e13e55 --- /dev/null +++ b/widgets/table/gal-a11y-e-cell-popup.h @@ -0,0 +1,61 @@ +/* + * + * 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: + * Yang Wu <yang.wu@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_CELL_POPUP_H__ +#define __GAL_A11Y_E_CELL_POPUP_H__ + +#include <glib-object.h> +#include <table/e-table-item.h> +#include <table/gal-a11y-e-cell.h> +#include <atk/atkgobjectaccessible.h> + +#define GAL_A11Y_TYPE_E_CELL_POPUP (gal_a11y_e_cell_popup_get_type ()) +#define GAL_A11Y_E_CELL_POPUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_POPUP, GalA11yECellPopup)) +#define GAL_A11Y_E_CELL_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL_POPUP, GalA11yECellPopupClass)) +#define GAL_A11Y_IS_E_CELL_POPUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_POPUP)) +#define GAL_A11Y_IS_E_CELL_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_POPUP)) + +typedef struct _GalA11yECellPopup GalA11yECellPopup; +typedef struct _GalA11yECellPopupClass GalA11yECellPopupClass; + +/* This struct should actually be larger as this isn't what we derive from. + * The GalA11yECellPopupPrivate comes right after the parent class structure. + **/ +struct _GalA11yECellPopup { + GalA11yECell object; +}; + +struct _GalA11yECellPopupClass { + GalA11yECellClass parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_cell_popup_get_type (void); +AtkObject *gal_a11y_e_cell_popup_new (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row); + +#endif /* ! __GAL_A11Y_E_CELL_POPUP_H__ */ diff --git a/widgets/table/gal-a11y-e-cell-registry.c b/widgets/table/gal-a11y-e-cell-registry.c new file mode 100644 index 0000000000..5c741e1955 --- /dev/null +++ b/widgets/table/gal-a11y-e-cell-registry.c @@ -0,0 +1,148 @@ +/* + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include "gal-a11y-e-cell.h" +#include "gal-a11y-e-cell-registry.h" + +static GObjectClass *parent_class; +static GalA11yECellRegistry *default_registry; +#define PARENT_TYPE (G_TYPE_OBJECT) + +struct _GalA11yECellRegistryPrivate { + GHashTable *table; +}; + +/* Static functions */ + +static void +gal_a11y_e_cell_registry_finalize (GObject *obj) +{ + GalA11yECellRegistry *registry = GAL_A11Y_E_CELL_REGISTRY (obj); + + g_hash_table_destroy (registry->priv->table); + g_free (registry->priv); + + G_OBJECT_CLASS (parent_class)->finalize (obj); +} + +static void +gal_a11y_e_cell_registry_class_init (GalA11yECellRegistryClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_ref (PARENT_TYPE); + + object_class->finalize = gal_a11y_e_cell_registry_finalize; +} + +static void +gal_a11y_e_cell_registry_init (GalA11yECellRegistry *registry) +{ + registry->priv = g_new (GalA11yECellRegistryPrivate, 1); + registry->priv->table = g_hash_table_new (NULL, NULL); +} + +/** + * gal_a11y_e_cell_registry_get_type: + * @void: + * + * Registers the &GalA11yECellRegistry class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yECellRegistry class. + **/ +GType +gal_a11y_e_cell_registry_get_type (void) +{ + static GType type = 0; + + if (!type) { + GTypeInfo info = { + sizeof (GalA11yECellRegistryClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gal_a11y_e_cell_registry_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yECellRegistry), + 0, + (GInstanceInitFunc) gal_a11y_e_cell_registry_init, + NULL /* value_cell */ + }; + + type = g_type_register_static (PARENT_TYPE, "GalA11yECellRegistry", &info, 0); + } + + return type; +} + +static void +init_default_registry (void) +{ + if (default_registry == NULL) { + default_registry = g_object_new (gal_a11y_e_cell_registry_get_type(), NULL); + } +} + +AtkObject * +gal_a11y_e_cell_registry_get_object (GalA11yECellRegistry *registry, + ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row) +{ + GalA11yECellRegistryFunc func = NULL; + GType type; + + if (registry == NULL) { + init_default_registry (); + registry = default_registry; + } + + type = GTK_OBJECT_TYPE (cell_view->ecell); + while (func == NULL && type != 0) { + func = g_hash_table_lookup (registry->priv->table, GINT_TO_POINTER (type)); + type = g_type_parent (type); + } + + if (func) + return func (item, cell_view, parent, model_col, view_col, row); + else + return gal_a11y_e_cell_new (item, cell_view, parent, model_col, view_col, row); +} + +void +gal_a11y_e_cell_registry_add_cell_type (GalA11yECellRegistry *registry, + GType type, + GalA11yECellRegistryFunc func) +{ + if (registry == NULL) { + init_default_registry (); + registry = default_registry; + } + + g_hash_table_insert (registry->priv->table, GINT_TO_POINTER (type), func); +} diff --git a/widgets/table/gal-a11y-e-cell-registry.h b/widgets/table/gal-a11y-e-cell-registry.h new file mode 100644 index 0000000000..85afdadf4e --- /dev/null +++ b/widgets/table/gal-a11y-e-cell-registry.h @@ -0,0 +1,71 @@ +/* + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_CELL_REGISTRY_H__ +#define __GAL_A11Y_E_CELL_REGISTRY_H__ + +#include <glib-object.h> +#include <atk/atkobject.h> +#include <table/e-table-item.h> +#include <table/e-cell.h> + +#define GAL_A11Y_TYPE_E_CELL_REGISTRY (gal_a11y_e_cell_registry_get_type ()) +#define GAL_A11Y_E_CELL_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_REGISTRY, GalA11yECellRegistry)) +#define GAL_A11Y_E_CELL_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL_REGISTRY, GalA11yECellRegistryClass)) +#define GAL_A11Y_IS_E_CELL_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_REGISTRY)) +#define GAL_A11Y_IS_E_CELL_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_REGISTRY)) + +typedef struct _GalA11yECellRegistry GalA11yECellRegistry; +typedef struct _GalA11yECellRegistryClass GalA11yECellRegistryClass; +typedef struct _GalA11yECellRegistryPrivate GalA11yECellRegistryPrivate; + +typedef AtkObject *(*GalA11yECellRegistryFunc) (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row); + +struct _GalA11yECellRegistry { + GObject object; + + GalA11yECellRegistryPrivate *priv; +}; + +struct _GalA11yECellRegistryClass { + GObjectClass parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_cell_registry_get_type (void); +AtkObject *gal_a11y_e_cell_registry_get_object (GalA11yECellRegistry *registry, + ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row); +void gal_a11y_e_cell_registry_add_cell_type (GalA11yECellRegistry *registry, + GType type, + GalA11yECellRegistryFunc func); + +#endif /* ! __GAL_A11Y_E_CELL_REGISTRY_H__ */ diff --git a/widgets/table/gal-a11y-e-cell-text.c b/widgets/table/gal-a11y-e-cell-text.c new file mode 100644 index 0000000000..26fffcb3e7 --- /dev/null +++ b/widgets/table/gal-a11y-e-cell-text.c @@ -0,0 +1,725 @@ +/* + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include <string.h> + +#include <atk/atk.h> + +#include "a11y/gal-a11y-util.h" +#include "table/e-cell-text.h" +#include <glib/gi18n.h> + +#include "gal-a11y-e-cell-text.h" + +#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yECellTextClass)) +static AtkObjectClass *parent_class; +#define PARENT_TYPE (gal_a11y_e_cell_get_type ()) + +/* Static functions */ +static void +ect_dispose (GObject *object) +{ + GObjectClass *g_class; + GalA11yECell *gaec = GAL_A11Y_E_CELL (object); + GalA11yECellText *gaet = GAL_A11Y_E_CELL_TEXT (object); + + if (gaet->inserted_id != 0) { + ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell); + + if (ect) { + g_signal_handler_disconnect (ect, gaet->inserted_id); + g_signal_handler_disconnect (ect, gaet->deleted_id); + } + + gaet->inserted_id = 0; + gaet->deleted_id = 0; + } + + g_class = (GObjectClass *)parent_class; + if (g_class->dispose) + g_class->dispose (object); + +} + +static gboolean +ect_check (gpointer a11y) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (a11y); + ETableItem *item = gaec->item; + + g_return_val_if_fail ((gaec->item != NULL), FALSE); + g_return_val_if_fail ((gaec->cell_view != NULL), FALSE); + g_return_val_if_fail ((gaec->cell_view->ecell != NULL), FALSE); + + if (atk_state_set_contains_state (gaec->state_set, ATK_STATE_DEFUNCT)) + return FALSE; + + if (gaec->row < 0 || gaec->row >= item->rows + || gaec->view_col <0 || gaec->view_col >= item->cols + || gaec->model_col <0 || gaec->model_col >= e_table_model_column_count (item->table_model)) + return FALSE; + + if (!E_IS_CELL_TEXT (gaec->cell_view->ecell)) + return FALSE; + + return TRUE; +} + +static G_CONST_RETURN gchar * +ect_get_name (AtkObject * a11y) +{ + GalA11yECell *gaec; + gchar *name; + + if (!ect_check (a11y)) + return NULL; + + gaec = GAL_A11Y_E_CELL (a11y); + name = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); + if (name != NULL) { + ATK_OBJECT_CLASS (parent_class)->set_name (a11y, name); + g_free (name); + } + + if (a11y->name != NULL && strcmp (a11y->name, "")) { + return a11y->name; + } else { + return parent_class->get_name (a11y); + } +} + +static gchar * +ect_get_text (AtkText *text, + gint start_offset, + gint end_offset) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (text); + gchar *full_text; + gchar *ret_val; + + if (!ect_check (text)) + return NULL; + + full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); + + if (end_offset == -1) + end_offset = strlen (full_text); + else + end_offset = g_utf8_offset_to_pointer (full_text, end_offset) - full_text; + + start_offset = g_utf8_offset_to_pointer (full_text, start_offset) - full_text; + + ret_val = g_strndup (full_text + start_offset, end_offset - start_offset); + + g_free (full_text); + + return ret_val; +} + +static gchar * +ect_get_text_after_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + /* Unimplemented */ + return NULL; +} + +static gchar * +ect_get_text_at_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + /* Unimplemented */ + return NULL; +} + +static gunichar +ect_get_character_at_offset (AtkText *text, + gint offset) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (text); + gunichar ret_val; + gchar *at_offset; + gchar *full_text; + + if (!ect_check (text)) + return -1; + + full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); + at_offset = g_utf8_offset_to_pointer (full_text, offset); + ret_val = g_utf8_get_char_validated (at_offset, -1); + g_free (full_text); + + return ret_val; +} + +static gchar * +ect_get_text_before_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + /* Unimplemented */ + return NULL; +} + +static gint +ect_get_caret_offset (AtkText *text) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (text); + gint start, end; + + if (!ect_check (text)) + return -1; + + if (e_cell_text_get_selection (gaec->cell_view, + gaec->view_col, gaec->row, + &start, &end)) { + gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); + end = g_utf8_pointer_to_offset (full_text, full_text + end); + g_free (full_text); + + return end; + } + else + return -1; +} + +static AtkAttributeSet* +ect_get_run_attributes (AtkText *text, + gint offset, + gint *start_offset, + gint *end_offset) +{ + /* Unimplemented */ + return NULL; +} + +static AtkAttributeSet* +ect_get_default_attributes (AtkText *text) +{ + /* Unimplemented */ + return NULL; +} + +static void +ect_get_character_extents (AtkText *text, + gint offset, + gint *x, + gint *y, + gint *width, + gint *height, + AtkCoordType coords) +{ + /* Unimplemented */ +} + +static gint +ect_get_character_count (AtkText *text) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (text); + gint ret_val; + gchar *full_text; + + if (!ect_check (text)) + return -1; + + full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); + + ret_val = g_utf8_strlen (full_text, -1); + g_free (full_text); + return ret_val; +} + +static gint +ect_get_offset_at_point (AtkText *text, + gint x, + gint y, + AtkCoordType coords) +{ + /* Unimplemented */ + return 0; +} + +static gint +ect_get_n_selections (AtkText *text) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (text); + gint selection_start, selection_end; + + if (!ect_check (text)) + return 0; + + if (e_cell_text_get_selection (gaec->cell_view, + gaec->view_col, gaec->row, + &selection_start, + &selection_end) + && selection_start != selection_end) + return 1; + return 0; +} + +static gchar * +ect_get_selection (AtkText *text, + gint selection_num, + gint *start_offset, + gint *end_offset) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (text); + gchar *ret_val; + gint selection_start, selection_end; + + if (selection_num == 0 + && e_cell_text_get_selection (gaec->cell_view, + gaec->view_col, gaec->row, + &selection_start, + &selection_end) + && selection_start != selection_end) { + gint real_start, real_end, len; + gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); + len = strlen (full_text); + real_start = MIN (selection_start, selection_end); + real_end = MAX (selection_start, selection_end); + real_start = MIN (MAX (0, real_start), len); + real_end = MIN (MAX (0, real_end), len); + + ret_val = g_strndup (full_text + real_start, real_end - real_start); + + real_start = g_utf8_pointer_to_offset (full_text, full_text + real_start); + real_end = g_utf8_pointer_to_offset (full_text, full_text + real_end); + + if (start_offset) + *start_offset = real_start; + if (end_offset) + *end_offset = real_end; + g_free (full_text); + } else { + if (start_offset) + *start_offset = 0; + if (end_offset) + *end_offset = 0; + ret_val = NULL; + } + + return ret_val; +} + +static gboolean +ect_add_selection (AtkText *text, + gint start_offset, + gint end_offset) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (text); + + if (start_offset != end_offset) { + gint real_start, real_end, len; + gchar *full_text = + e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); + + len = g_utf8_strlen (full_text, -1); + if (end_offset == -1) + end_offset = len; + + real_start = MIN (start_offset, end_offset); + real_end = MAX (start_offset, end_offset); + + real_start = MIN (MAX (0, real_start), len); + real_end = MIN (MAX (0, real_end), len); + + real_start = g_utf8_offset_to_pointer (full_text, real_start) - full_text; + real_end = g_utf8_offset_to_pointer (full_text, real_end) - full_text; + g_free (full_text); + + if (e_cell_text_set_selection (gaec->cell_view, + gaec->view_col, gaec->row, + real_start, real_end)) { + g_signal_emit_by_name (ATK_OBJECT(text), "text_selection_changed"); + return TRUE; + } + } + + return FALSE; +} + +static gboolean +ect_remove_selection (AtkText *text, + gint selection_num) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (text); + gint selection_start, selection_end; + + if (selection_num == 0 + && e_cell_text_get_selection (gaec->cell_view, + gaec->view_col, gaec->row, + &selection_start, + &selection_end) + && selection_start != selection_end + && e_cell_text_set_selection (gaec->cell_view, + gaec->view_col, gaec->row, + selection_end, selection_end)) { + g_signal_emit_by_name (ATK_OBJECT(text), "text_selection_changed"); + return TRUE; + } + else + return FALSE; +} + +static gboolean +ect_set_selection (AtkText *text, + gint selection_num, + gint start_offset, + gint end_offset) +{ + if (selection_num == 0) { + atk_text_add_selection (text, start_offset, end_offset); + return TRUE; + } + else + return FALSE; +} + +static gboolean +ect_set_caret_offset (AtkText *text, + gint offset) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (text); + gchar *full_text; + gint len; + + full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); + + len = g_utf8_strlen (full_text, -1); + if (offset == -1) + offset = len; + else + offset = MIN (MAX (0, offset), len); + + offset = g_utf8_offset_to_pointer (full_text, offset) - full_text; + + g_free (full_text); + + return e_cell_text_set_selection (gaec->cell_view, + gaec->view_col, gaec->row, + offset, offset); +} + +static gboolean +ect_set_run_attributes (AtkEditableText *text, + AtkAttributeSet *attrib_set, + gint start_offset, + gint end_offset) +{ + /* Unimplemented */ + return FALSE; +} + +static void +ect_set_text_contents (AtkEditableText *text, + const gchar *string) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (text); + ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell); + + e_cell_text_set_value (ect, gaec->item->table_model, gaec->model_col, gaec->row, string); + e_table_item_enter_edit (gaec->item, gaec->view_col, gaec->row); +} + +static void +ect_insert_text (AtkEditableText *text, + const gchar *string, + gint length, + gint *position) +{ + /* Utf8 unimplemented */ + GalA11yECell *gaec = GAL_A11Y_E_CELL (text); + ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell); + + gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); + gchar *result = g_strdup_printf ("%.*s%.*s%s", *position, full_text, length, string, full_text + *position); + + e_cell_text_set_value (ect, gaec->item->table_model, gaec->model_col, gaec->row, result); + + *position += length; + + g_free (result); + g_free (full_text); +} + +static void +ect_copy_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (text); + if (start_pos != end_pos + && atk_text_set_selection (ATK_TEXT (text), 0, start_pos, end_pos)) + e_cell_text_copy_clipboard (gaec->cell_view, + gaec->view_col, gaec->row); +} + +static void +ect_delete_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (text); + if (start_pos != end_pos + && atk_text_set_selection (ATK_TEXT (text), 0, start_pos, end_pos)) + e_cell_text_delete_selection (gaec->cell_view, + gaec->view_col, gaec->row); +} + +static void +ect_cut_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + ect_copy_text (text, start_pos, end_pos); + ect_delete_text (text, start_pos, end_pos); +} + +static void +ect_paste_text (AtkEditableText *text, + gint position) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (text); + + e_table_item_enter_edit (gaec->item, gaec->view_col, gaec->row); + + if (atk_text_set_caret_offset (ATK_TEXT (text), position)) + e_cell_text_paste_clipboard (gaec->cell_view, + gaec->view_col, gaec->row); +} + +static void +ect_do_action_edit (AtkAction *action) +{ + GalA11yECell *a11y = GAL_A11Y_E_CELL (action); + ETableModel *e_table_model = a11y->item->table_model; + + if (e_table_model_is_cell_editable(e_table_model, a11y->model_col, a11y->row)) { + e_table_item_enter_edit (a11y->item, a11y->view_col, a11y->row); + } +} + +/* text signal handlers */ +static void +ect_text_inserted_cb (ECellText *text, ECellView *cell_view, gint pos, gint len, gint row, gint model_col, gpointer data) +{ + GalA11yECellText *gaet; + GalA11yECell *gaec; + + if (!ect_check (data)) + return; + gaet = GAL_A11Y_E_CELL_TEXT (data); + gaec = GAL_A11Y_E_CELL (data); + + if (cell_view == gaec->cell_view && row == gaec->row && model_col == gaec->model_col) { + g_signal_emit_by_name (gaet, "text_changed::insert", pos, len); + + } +} + +static void +ect_text_deleted_cb (ECellText *text, ECellView *cell_view, gint pos, gint len, gint row, gint model_col, gpointer data) +{ + GalA11yECellText *gaet; + GalA11yECell *gaec; + if (!ect_check (data)) + return; + gaet = GAL_A11Y_E_CELL_TEXT (data); + gaec = GAL_A11Y_E_CELL (data); + if (cell_view == gaec->cell_view && row == gaec->row && model_col == gaec->model_col) { + g_signal_emit_by_name (gaet, "text_changed::delete", pos, len); + } +} + +static void +ect_atk_text_iface_init (AtkTextIface *iface) +{ + iface->get_text = ect_get_text; + iface->get_text_after_offset = ect_get_text_after_offset; + iface->get_text_at_offset = ect_get_text_at_offset; + iface->get_character_at_offset = ect_get_character_at_offset; + iface->get_text_before_offset = ect_get_text_before_offset; + iface->get_caret_offset = ect_get_caret_offset; + iface->get_run_attributes = ect_get_run_attributes; + iface->get_default_attributes = ect_get_default_attributes; + iface->get_character_extents = ect_get_character_extents; + iface->get_character_count = ect_get_character_count; + iface->get_offset_at_point = ect_get_offset_at_point; + iface->get_n_selections = ect_get_n_selections; + iface->get_selection = ect_get_selection; + iface->add_selection = ect_add_selection; + iface->remove_selection = ect_remove_selection; + iface->set_selection = ect_set_selection; + iface->set_caret_offset = ect_set_caret_offset; +} + +static void +ect_atk_editable_text_iface_init (AtkEditableTextIface *iface) +{ + iface->set_run_attributes = ect_set_run_attributes; + iface->set_text_contents = ect_set_text_contents; + iface->insert_text = ect_insert_text; + iface->copy_text = ect_copy_text; + iface->cut_text = ect_cut_text; + iface->delete_text = ect_delete_text; + iface->paste_text = ect_paste_text; +} + +static void +ect_class_init (GalA11yECellTextClass *klass) +{ + AtkObjectClass *a11y = ATK_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_ref (PARENT_TYPE); + a11y->get_name = ect_get_name; + object_class->dispose = ect_dispose; +} + +static void +ect_action_init (GalA11yECellText *a11y) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (a11y); + ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell); + if (ect->editable && e_table_model_is_cell_editable (gaec->cell_view->e_table_model, gaec->model_col, gaec->row)) + gal_a11y_e_cell_add_action (gaec, + _("edit"), + _("begin editing this cell"), + NULL, + (ACTION_FUNC) ect_do_action_edit); +} + +/** + * gal_a11y_e_cell_text_get_type: + * @void: + * + * Registers the &GalA11yECellText class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yECellText class. + **/ +GType +gal_a11y_e_cell_text_get_type (void) +{ + static GType type = 0; + + if (!type) { + GTypeInfo info = { + sizeof (GalA11yECellTextClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) ect_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yECellText), + 0, + (GInstanceInitFunc) NULL, + NULL /* value_cell_text */ + }; + + static const GInterfaceInfo atk_text_info = { + (GInterfaceInitFunc) ect_atk_text_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + static const GInterfaceInfo atk_editable_text_info = { + (GInterfaceInitFunc) ect_atk_editable_text_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + type = g_type_register_static (PARENT_TYPE, "GalA11yECellText", &info, 0); + g_type_add_interface_static (type, ATK_TYPE_TEXT, &atk_text_info); + g_type_add_interface_static (type, ATK_TYPE_EDITABLE_TEXT, &atk_editable_text_info); + gal_a11y_e_cell_type_add_action_interface (type); + } + + return type; +} + +static void +cell_text_destroyed (gpointer data) +{ + g_return_if_fail (GAL_A11Y_IS_E_CELL_TEXT (data)); + + g_object_unref (data); +} + +AtkObject * +gal_a11y_e_cell_text_new (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row) +{ + AtkObject *a11y; + GalA11yECell *gaec; + GalA11yECellText *gaet; + ECellText *ect; + + a11y = g_object_new (gal_a11y_e_cell_text_get_type (), NULL); + + gal_a11y_e_cell_construct (a11y, + item, + cell_view, + parent, + model_col, + view_col, + row); + gaet = GAL_A11Y_E_CELL_TEXT (a11y); + + /* will be unrefed in cell_text_destroyed */ + g_object_ref (a11y); + + gaet->inserted_id = g_signal_connect (E_CELL_TEXT (((ECellView *)cell_view)->ecell), + "text_inserted", G_CALLBACK (ect_text_inserted_cb), a11y); + gaet->deleted_id = g_signal_connect (E_CELL_TEXT (((ECellView *)cell_view)->ecell), + "text_deleted", G_CALLBACK (ect_text_deleted_cb), a11y); + + g_object_weak_ref (G_OBJECT (((ECellView *)cell_view)->ecell), + (GWeakNotify) cell_text_destroyed, + a11y); + + ect_action_init (gaet); + + ect = E_CELL_TEXT (cell_view->ecell); + gaec = GAL_A11Y_E_CELL (a11y); + if (ect->editable && e_table_model_is_cell_editable (gaec->cell_view->e_table_model, gaec->model_col, gaec->row)) + gal_a11y_e_cell_add_state (gaec, ATK_STATE_EDITABLE, FALSE); + else + gal_a11y_e_cell_remove_state (gaec, ATK_STATE_EDITABLE, FALSE); + + return a11y; +} diff --git a/widgets/table/gal-a11y-e-cell-text.h b/widgets/table/gal-a11y-e-cell-text.h new file mode 100644 index 0000000000..e5a95accad --- /dev/null +++ b/widgets/table/gal-a11y-e-cell-text.h @@ -0,0 +1,63 @@ +/* + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_CELL_TEXT_H__ +#define __GAL_A11Y_E_CELL_TEXT_H__ + +#include <glib-object.h> +#include <table/e-table-item.h> +#include <table/e-cell-text.h> +#include <table/gal-a11y-e-cell.h> + +#define GAL_A11Y_TYPE_E_CELL_TEXT (gal_a11y_e_cell_text_get_type ()) +#define GAL_A11Y_E_CELL_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_TEXT, GalA11yECellText)) +#define GAL_A11Y_E_CELL_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL_TEXT, GalA11yECellTextClass)) +#define GAL_A11Y_IS_E_CELL_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_TEXT)) +#define GAL_A11Y_IS_E_CELL_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_TEXT)) + +typedef struct _GalA11yECellText GalA11yECellText; +typedef struct _GalA11yECellTextClass GalA11yECellTextClass; +typedef struct _GalA11yECellTextPrivate GalA11yECellTextPrivate; + +/* This struct should actually be larger as this isn't what we derive from. + * The GalA11yECellTextPrivate comes right after the parent class structure. + **/ +struct _GalA11yECellText { + GalA11yECell object; + gint inserted_id; + gint deleted_id; +}; + +struct _GalA11yECellTextClass { + GalA11yECellClass parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_cell_text_get_type (void); +AtkObject *gal_a11y_e_cell_text_new (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row); + +#endif /* ! __GAL_A11Y_E_CELL_TEXT_H__ */ diff --git a/widgets/table/gal-a11y-e-cell-toggle.c b/widgets/table/gal-a11y-e-cell-toggle.c new file mode 100644 index 0000000000..fa23f6c6fd --- /dev/null +++ b/widgets/table/gal-a11y-e-cell-toggle.c @@ -0,0 +1,188 @@ +/* + * 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) + * + */ + +#include <gtk/gtk.h> + +#include "table/e-cell-toggle.h" +#include "table/e-table-model.h" +#include <glib/gi18n.h> + +#include "gal-a11y-e-cell-toggle.h" + +#define PARENT_TYPE (gal_a11y_e_cell_get_type ()) +static GObjectClass *parent_class; + +static void gal_a11y_e_cell_toggle_class_init (GalA11yECellToggleClass *klass); + +static void +gal_a11y_e_cell_toggle_dispose (GObject *object) +{ + GalA11yECellToggle *a11y = GAL_A11Y_E_CELL_TOGGLE (object); + + ETableModel *e_table_model = GAL_A11Y_E_CELL (a11y)->item->table_model; + + if (e_table_model && a11y->model_id > 0) { + g_signal_handler_disconnect (e_table_model, a11y->model_id); + a11y->model_id = 0; + } + + if (parent_class->dispose) + parent_class->dispose (object); +} + +GType +gal_a11y_e_cell_toggle_get_type (void) +{ + static GType type = 0; + + if (!type) + { + static const GTypeInfo tinfo = + { + sizeof (GalA11yECellToggleClass), + (GBaseInitFunc) NULL, /* base init */ + (GBaseFinalizeFunc) NULL, /* base finalize */ + (GClassInitFunc) gal_a11y_e_cell_toggle_class_init, /* class init */ + (GClassFinalizeFunc) NULL, /* class finalize */ + NULL, /* class data */ + sizeof (GalA11yECellToggle), /* instance size */ + 0, /* nb preallocs */ + NULL, /* instance init */ + NULL /* value table */ + }; + + type = g_type_register_static (GAL_A11Y_TYPE_E_CELL, + "GalA11yECellToggle", &tinfo, 0); + gal_a11y_e_cell_type_add_action_interface (type); + + } + return type; +} + +static void +gal_a11y_e_cell_toggle_class_init (GalA11yECellToggleClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = gal_a11y_e_cell_toggle_dispose; + parent_class = g_type_class_ref (PARENT_TYPE); +} + +static void +toggle_cell_action (GalA11yECell *cell) +{ + gint finished; + GdkEventButton event; + gint x, y, width, height; + gint row, col; + + row = cell->row; + col = cell->view_col; + + e_table_item_get_cell_geometry (cell->item, &row, &col, + &x, &y, &width, &height); + + event.x = x + width / 2 + (gint)(GNOME_CANVAS_ITEM (cell->item)->x1); + event.y = y + height / 2 + (gint)(GNOME_CANVAS_ITEM (cell->item)->y1); + + event.type = GDK_BUTTON_PRESS; + event.window = GTK_LAYOUT(GNOME_CANVAS_ITEM(cell->item)->canvas)->bin_window; + event.button = 1; + event.send_event = TRUE; + event.time = GDK_CURRENT_TIME; + event.axes = NULL; + + g_signal_emit_by_name (cell->item, "event", &event, &finished); +} + +static void +model_change_cb (ETableModel *etm, + gint col, + gint row, + GalA11yECell *cell) +{ + gint value; + + if (col == cell->model_col && row == cell->row) { + + value = GPOINTER_TO_INT ( + e_table_model_value_at (cell->cell_view->e_table_model, + cell->model_col, cell->row)); + /* Cheat gnopernicus, or it will ignore the state change signal */ + atk_focus_tracker_notify (ATK_OBJECT (cell)); + + if (value) + gal_a11y_e_cell_add_state (cell, ATK_STATE_CHECKED, TRUE); + else + gal_a11y_e_cell_remove_state (cell, ATK_STATE_CHECKED, TRUE); + } +} + +AtkObject* +gal_a11y_e_cell_toggle_new (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row) +{ + AtkObject *a11y; + GalA11yECell *cell; + GalA11yECellToggle *toggle_cell; + gint value; + + a11y = ATK_OBJECT(g_object_new (GAL_A11Y_TYPE_E_CELL_TOGGLE, NULL)); + + g_return_val_if_fail (a11y != NULL, NULL); + + cell = GAL_A11Y_E_CELL(a11y); + toggle_cell = GAL_A11Y_E_CELL_TOGGLE(a11y); + a11y->role = ATK_ROLE_TABLE_CELL; + + gal_a11y_e_cell_construct (a11y, + item, + cell_view, + parent, + model_col, + view_col, + row); + + gal_a11y_e_cell_add_action (cell, + _("toggle"), /* action name*/ + _("toggle the cell"), /* action description */ + NULL, /* action keybinding */ + toggle_cell_action); + + toggle_cell->model_id = g_signal_connect (item->table_model, + "model_cell_changed", + (GCallback) model_change_cb, + a11y); + + value = GPOINTER_TO_INT ( + e_table_model_value_at (cell->cell_view->e_table_model, + cell->model_col, cell->row)); + if (value) + gal_a11y_e_cell_add_state (cell, ATK_STATE_CHECKED, FALSE); + else + gal_a11y_e_cell_remove_state (cell, ATK_STATE_CHECKED, FALSE); + + return a11y; +} diff --git a/widgets/table/gal-a11y-e-cell-toggle.h b/widgets/table/gal-a11y-e-cell-toggle.h new file mode 100644 index 0000000000..3c29d777e3 --- /dev/null +++ b/widgets/table/gal-a11y-e-cell-toggle.h @@ -0,0 +1,63 @@ +/* + * 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 __GAL_A11Y_E_CELL_TOGGLE_H__ +#define __GAL_A11Y_E_CELL_TOGGLE_H__ + +#include <atk/atk.h> +#include "gal-a11y-e-cell.h" +#include "gal-a11y-e-cell-toggle.h" + +G_BEGIN_DECLS + +#define GAL_A11Y_TYPE_E_CELL_TOGGLE (gal_a11y_e_cell_toggle_get_type ()) +#define GAL_A11Y_E_CELL_TOGGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_TOGGLE, GalA11yECellToggle)) +#define GAL_A11Y_E_CELL_TOGGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_E_CELL_TOGGLE, GalA11yECellToggleClass)) +#define GAL_A11Y_IS_E_CELL_TOGGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_TOGGLE)) +#define GAL_A11Y_IS_E_CELL_TOGGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_TOGGLE)) +#define GAL_A11Y_E_CELL_TOGGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GAL_A11Y_TYPE_E_CELL_TOGGLE, GalA11yECellToggleClass)) + +typedef struct _GalA11yECellToggle GalA11yECellToggle; +typedef struct _GalA11yECellToggleClass GalA11yECellToggleClass; + +struct _GalA11yECellToggle +{ + GalA11yECell parent; + gint model_id; +}; + +GType gal_a11y_e_cell_toggle_get_type (void); + +struct _GalA11yECellToggleClass +{ + GalA11yECellClass parent_class; +}; + +AtkObject *gal_a11y_e_cell_toggle_new (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row); + +G_END_DECLS + +#endif /* __GAL_A11Y_E_CELL_TOGGLE_H__ */ diff --git a/widgets/table/gal-a11y-e-cell-tree.c b/widgets/table/gal-a11y-e-cell-tree.c new file mode 100644 index 0000000000..aaf490c726 --- /dev/null +++ b/widgets/table/gal-a11y-e-cell-tree.c @@ -0,0 +1,260 @@ +/* + * 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: + * Tim Wo <tim.wo@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include <atk/atk.h> + +#include "a11y/gal-a11y-util.h" +#include "table/e-cell-tree.h" +#include "table/e-table.h" +#include "table/e-tree-table-adapter.h" +#include <glib/gi18n.h> + +#include "gal-a11y-e-cell-tree.h" +#include "gal-a11y-e-cell-registry.h" + +#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yECellTreeClass)) +static AtkObjectClass *a11y_parent_class; +#define A11Y_PARENT_TYPE (gal_a11y_e_cell_get_type ()) + +#define d(x) + +static void +ectr_model_row_changed_cb (ETableModel *etm, + gint row, + GalA11yECell *a11y) +{ + ETreePath node; + ETreeModel *tree_model; + ETreeTableAdapter *tree_table_adapter; + + g_return_if_fail (a11y); + if (a11y->row != row) + return; + + node = e_table_model_value_at (etm, -1, a11y->row); + tree_model = e_table_model_value_at (etm, -2, a11y->row); + tree_table_adapter = e_table_model_value_at (etm, -3, a11y->row); + + if (e_tree_model_node_is_expandable (tree_model, node)) { + gboolean is_exp = e_tree_table_adapter_node_is_expanded (tree_table_adapter, node); + if (is_exp) + gal_a11y_e_cell_add_state (a11y, ATK_STATE_EXPANDED, TRUE); + else + gal_a11y_e_cell_remove_state (a11y, ATK_STATE_EXPANDED, TRUE); + } +} + +static void +kill_view_cb(ECellView *subcell_view, + gpointer psubcell_a11ies) +{ + GList *node; + GList *subcell_a11ies = (GList *) psubcell_a11ies; + GalA11yECell *subcell; + + for (node = subcell_a11ies; node != NULL; node = g_list_next (node)) + { + subcell = GAL_A11Y_E_CELL(node->data); + if (subcell && subcell->cell_view == subcell_view) + { + d(fprintf(stderr, "subcell_view %p deleted before the a11y object %p\n", subcell_view, subcell)); + subcell->cell_view = NULL; + } + } +} + +static void +ectr_subcell_weak_ref (GalA11yECellTree *a11y, + GalA11yECell *subcell_a11y) +{ + ECellView *subcell_view = subcell_a11y ? subcell_a11y->cell_view : NULL; + if (subcell_a11y && subcell_view && subcell_view->kill_view_cb_data) + subcell_view->kill_view_cb_data = g_list_remove(subcell_view->kill_view_cb_data, subcell_a11y); + + g_signal_handler_disconnect (GAL_A11Y_E_CELL (a11y)->item->table_model, + a11y->model_row_changed_id); + g_object_unref (a11y); +} + +static void +ectr_do_action_expand (AtkAction *action) +{ + GalA11yECell *a11y; + ETableModel *table_model; + ETreePath node; + ETreeModel *tree_model; + ETreeTableAdapter *tree_table_adapter; + + a11y = GAL_A11Y_E_CELL (action); + table_model = a11y->item->table_model; + node = e_table_model_value_at (table_model, -1, a11y->row); + tree_model = e_table_model_value_at (table_model, -2, a11y->row); + tree_table_adapter = e_table_model_value_at (table_model, -3, a11y->row); + + if (e_tree_model_node_is_expandable (tree_model, node)) { + e_tree_table_adapter_node_set_expanded (tree_table_adapter, + node, + TRUE); + gal_a11y_e_cell_add_state (a11y, ATK_STATE_EXPANDED, TRUE); + } +} + +static void +ectr_do_action_collapse (AtkAction *action) +{ + GalA11yECell *a11y; + ETableModel *table_model; + ETreePath node; + ETreeModel *tree_model; + ETreeTableAdapter *tree_table_adapter; + + a11y = GAL_A11Y_E_CELL (action); + table_model = a11y->item->table_model; + node = e_table_model_value_at (table_model, -1, a11y->row); + tree_model = e_table_model_value_at (table_model, -2, a11y->row); + tree_table_adapter = e_table_model_value_at (table_model, -3, a11y->row); + + if (e_tree_model_node_is_expandable (tree_model, node)) { + e_tree_table_adapter_node_set_expanded (tree_table_adapter, + node, + FALSE); + gal_a11y_e_cell_remove_state (a11y, ATK_STATE_EXPANDED, TRUE); + } +} + +static void +ectr_class_init (GalA11yECellTreeClass *klass) +{ + a11y_parent_class = g_type_class_ref (A11Y_PARENT_TYPE); +} + +static void +ectr_init (GalA11yECellTree *a11y) +{ +} + +GType +gal_a11y_e_cell_tree_get_type (void) +{ + static GType type = 0; + + if (!type) { + GTypeInfo info = { + sizeof (GalA11yECellTreeClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) ectr_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yECellTree), + 0, + (GInstanceInitFunc) ectr_init, + NULL /* value_cell_text */ + }; + + type = g_type_register_static (A11Y_PARENT_TYPE, "GalA11yECellTree", &info, 0); + gal_a11y_e_cell_type_add_action_interface (type); + } + + return type; +} + +AtkObject * +gal_a11y_e_cell_tree_new (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row) +{ + AtkObject *subcell_a11y; + GalA11yECellTree *a11y; + + ETreePath node; + ETreeModel *tree_model; + ETreeTableAdapter *tree_table_adapter; + + ECellView *subcell_view; + subcell_view = e_cell_tree_view_get_subcell_view (cell_view); + + if (subcell_view->ecell) { + subcell_a11y = gal_a11y_e_cell_registry_get_object (NULL, + item, + subcell_view, + parent, + model_col, + view_col, + row); + gal_a11y_e_cell_add_action (GAL_A11Y_E_CELL (subcell_a11y), + _("expand"), + _("expands the row in the ETree containing this cell"), + NULL, + (ACTION_FUNC)ectr_do_action_expand); + + gal_a11y_e_cell_add_action (GAL_A11Y_E_CELL (subcell_a11y), + _("collapse"), + _("collapses the row in the ETree containing this cell"), + NULL, + (ACTION_FUNC)ectr_do_action_collapse); + + /* init AtkStates for the cell's a11y object */ + node = e_table_model_value_at (item->table_model, -1, row); + tree_model = e_table_model_value_at (item->table_model, -2, row); + tree_table_adapter = e_table_model_value_at (item->table_model, -3, row); + if (e_tree_model_node_is_expandable (tree_model, node)) { + gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL (subcell_a11y), ATK_STATE_EXPANDABLE, FALSE); + if (e_tree_table_adapter_node_is_expanded (tree_table_adapter, node)) + gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL (subcell_a11y), ATK_STATE_EXPANDED, FALSE); + } + } + else + subcell_a11y = NULL; + + /* create a companion a11y object, this object has type GalA11yECellTree + and it connects to some signals to determine whether a tree cell is + expanded or collapsed */ + a11y = g_object_new (gal_a11y_e_cell_tree_get_type (), NULL); + gal_a11y_e_cell_construct (ATK_OBJECT (a11y), + item, + cell_view, + parent, + model_col, + view_col, + row); + a11y->model_row_changed_id = + g_signal_connect (item->table_model, "model_row_changed", + G_CALLBACK (ectr_model_row_changed_cb), + subcell_a11y); + + if (subcell_a11y && subcell_view) + { + subcell_view->kill_view_cb = kill_view_cb; + if (!g_list_find(subcell_view->kill_view_cb_data, subcell_a11y)) + subcell_view->kill_view_cb_data = g_list_append(subcell_view->kill_view_cb_data, subcell_a11y); + } + + g_object_weak_ref (G_OBJECT (subcell_a11y), (GWeakNotify) ectr_subcell_weak_ref, a11y); + + return subcell_a11y; +} diff --git a/widgets/table/gal-a11y-e-cell-tree.h b/widgets/table/gal-a11y-e-cell-tree.h new file mode 100644 index 0000000000..fa48c1486a --- /dev/null +++ b/widgets/table/gal-a11y-e-cell-tree.h @@ -0,0 +1,63 @@ +/* + * 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: + * Tim Wo <tim.wo@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_CELL_TREE_H__ +#define __GAL_A11Y_E_CELL_TREE_H__ + +#include <glib-object.h> +#include <table/e-table-item.h> +#include <table/e-cell-tree.h> +#include "gal-a11y-e-cell.h" + +#define GAL_A11Y_TYPE_E_CELL_TREE (gal_a11y_e_cell_tree_get_type ()) +#define GAL_A11Y_E_CELL_TREE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_TREE, GalA11yECellTree)) +#define GAL_A11Y_E_CELL_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL_TREE, GalA11yECellTreeClass)) +#define GAL_A11Y_IS_E_CELL_TREE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_TREE)) +#define GAL_A11Y_IS_E_CELL_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_TREE)) + +typedef struct _GalA11yECellTree GalA11yECellTree; +typedef struct _GalA11yECellTreeClass GalA11yECellTreeClass; +typedef struct _GalA11yECellTreePrivate GalA11yECellTreePrivate; + +/* This struct should actually be larger as this isn't what we derive from. + * The GalA11yECellTreePrivate comes right after the parent class structure. + **/ +struct _GalA11yECellTree { + GalA11yECell object; + + gint model_row_changed_id; +}; + +struct _GalA11yECellTreeClass { + GalA11yECellClass parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_cell_tree_get_type (void); +AtkObject *gal_a11y_e_cell_tree_new (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row); + +#endif /* ! __GAL_A11Y_E_CELL_TREE_H__ */ diff --git a/widgets/table/gal-a11y-e-cell-vbox.c b/widgets/table/gal-a11y-e-cell-vbox.c new file mode 100644 index 0000000000..b3f92a695a --- /dev/null +++ b/widgets/table/gal-a11y-e-cell-vbox.c @@ -0,0 +1,225 @@ +/* + * + * 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: + * Eric Zhao <eric.zhao@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * Copyright (C) 2004 Sun Microsystem, Inc. + * + */ + +#include <config.h> + +#include <atk/atk.h> + +#include "table/e-cell-vbox.h" + +#include "gal-a11y-e-cell-registry.h" +#include "gal-a11y-e-cell-vbox.h" + +static GObjectClass *parent_class; +static AtkComponentIface *component_parent_iface; +#define PARENT_TYPE (gal_a11y_e_cell_get_type ()) + +static gint +ecv_get_n_children (AtkObject *a11y) +{ + g_return_val_if_fail (GAL_A11Y_IS_E_CELL_VBOX (a11y), 0); + + return GAL_A11Y_E_CELL_VBOX (a11y)->a11y_subcell_count; +} + +static void +subcell_destroyed (gpointer data) +{ + GalA11yECell *cell; + AtkObject *parent; + GalA11yECellVbox *gaev; + + g_return_if_fail (GAL_A11Y_IS_E_CELL (data)); + cell = GAL_A11Y_E_CELL (data); + + parent = atk_object_get_parent (ATK_OBJECT (cell)); + g_return_if_fail (GAL_A11Y_IS_E_CELL_VBOX (parent)); + gaev = GAL_A11Y_E_CELL_VBOX (parent); + + if (cell->view_col < gaev->a11y_subcell_count) + gaev->a11y_subcells[cell->view_col] = NULL; +} + +static AtkObject* +ecv_ref_child (AtkObject *a11y, gint i) +{ + GalA11yECellVbox *gaev = GAL_A11Y_E_CELL_VBOX (a11y); + GalA11yECell *gaec = GAL_A11Y_E_CELL (a11y); + ECellVboxView *ecvv = (ECellVboxView *) (gaec->cell_view); + AtkObject *ret; + if (i < gaev->a11y_subcell_count) { + if (gaev->a11y_subcells[i] == NULL) { + ECellView *subcell_view; + gint model_col, row; + row = gaec->row; + model_col = ecvv->model_cols[i]; + subcell_view = ecvv->subcell_views[i]; + ret = gal_a11y_e_cell_registry_get_object (NULL, + gaec->item, + subcell_view, + a11y, + model_col, + gaec->view_col, /* FIXME should the view column use a fake one or the same as its parent? */ + row); + gaev->a11y_subcells[i] = ret; + g_object_ref (ret); + g_object_weak_ref (G_OBJECT (ret), + (GWeakNotify) subcell_destroyed, + ret); + } else { + ret = (AtkObject *) gaev->a11y_subcells[i]; + if (ATK_IS_OBJECT (ret)) + g_object_ref (ret); + else + ret = NULL; + } + } else { + ret = NULL; + } + + return ret; +} + +static void +ecv_dispose (GObject *object) +{ + GalA11yECellVbox *gaev = GAL_A11Y_E_CELL_VBOX (object); + if (gaev->a11y_subcells) + g_free (gaev->a11y_subcells); + + if (parent_class->dispose) + parent_class->dispose (object); +} + +/* AtkComponet interface */ +static AtkObject* +ecv_ref_accessible_at_point (AtkComponent *component, + gint x, + gint y, + AtkCoordType coord_type) +{ + gint x0, y0, width, height; + gint subcell_height, i; + + GalA11yECell *gaec = GAL_A11Y_E_CELL (component); + ECellVboxView *ecvv = (ECellVboxView *) (gaec->cell_view); + + atk_component_get_extents (component, &x0, &y0, &width, &height, coord_type); + x -= x0; + y -= y0; + if (x < 0 || x > width || y < 0 || y > height) + return NULL; + + for (i = 0; i < ecvv->subcell_view_count; i++) { + subcell_height = e_cell_height (ecvv->subcell_views[i], ecvv->model_cols[i], gaec->view_col, gaec->row); + if ( 0 <= y && y <= subcell_height) { + return ecv_ref_child ((AtkObject *)component, i); + } else + y -= subcell_height; + } + + return NULL; +} + +static void +ecv_class_init (GalA11yECellVboxClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + AtkObjectClass *a11y_class = ATK_OBJECT_CLASS (klass); + parent_class = g_type_class_ref (PARENT_TYPE); + + object_class->dispose = ecv_dispose; + + a11y_class->get_n_children = ecv_get_n_children; + a11y_class->ref_child = ecv_ref_child; +} + +static void +ecv_init (GalA11yECellVbox *a11y) +{ +} + +static void +ecv_atk_component_iface_init (AtkComponentIface *iface) +{ + component_parent_iface = g_type_interface_peek_parent (iface); + + iface->ref_accessible_at_point = ecv_ref_accessible_at_point; +} + +GType +gal_a11y_e_cell_vbox_get_type (void) +{ + static GType type = 0; + if (!type) { + GTypeInfo info = { + sizeof (GalA11yECellVboxClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) ecv_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yECellVbox), + 0, + (GInstanceInitFunc) ecv_init, + NULL /* value_cell */ + }; + + static const GInterfaceInfo atk_component_info = { + (GInterfaceInitFunc) ecv_atk_component_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + type = g_type_register_static (PARENT_TYPE, "GalA11yECellVbox", &info, 0); + gal_a11y_e_cell_type_add_action_interface (type); + g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info); + } + + return type; +} + +AtkObject *gal_a11y_e_cell_vbox_new (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row) +{ + AtkObject *a11y; + GalA11yECell *gaec; + GalA11yECellVbox *gaev; + ECellVboxView *ecvv; + + a11y = g_object_new (gal_a11y_e_cell_vbox_get_type (), NULL); + + gal_a11y_e_cell_construct (a11y, item, cell_view, parent, model_col, view_col, row); + + gaec = GAL_A11Y_E_CELL (a11y); + gaev = GAL_A11Y_E_CELL_VBOX (a11y); + ecvv = (ECellVboxView *) (gaec->cell_view); + gaev->a11y_subcell_count = ecvv->subcell_view_count; + gaev->a11y_subcells = g_malloc0 (sizeof(AtkObject *)*gaev->a11y_subcell_count); + return a11y; +} diff --git a/widgets/table/gal-a11y-e-cell-vbox.h b/widgets/table/gal-a11y-e-cell-vbox.h new file mode 100644 index 0000000000..657cb5d9a5 --- /dev/null +++ b/widgets/table/gal-a11y-e-cell-vbox.h @@ -0,0 +1,63 @@ +/* + * + * 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: + * Eric Zhao <eric.zhao@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * Copyright (C) 2004 Sun Microsystem, Inc. + * + */ + +#ifndef __GAL_A11Y_E_CELL_VBOX_H__ +#define __GAL_A11Y_E_CELL_VBOX_H__ + +#include "gal-a11y-e-cell.h" + +G_BEGIN_DECLS + +#define GAL_A11Y_TYPE_E_CELL_VBOX (gal_a11y_e_cell_vbox_get_type ()) +#define GAL_A11Y_E_CELL_VBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_VBOX, GalA11yECellVbox)) +#define GAL_A11Y_E_CELL_VBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_E_CELL_VBOX, GalA11yECellVboxClass)) +#define GAL_A11Y_IS_E_CELL_VBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_VBOX)) +#define GAL_A11Y_IS_E_CELL_VBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_VBOX)) +#define GAL_A11Y_E_CELL_VBOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GAL_A11Y_TYPE_E_CELL_VBOX, GalA11yECellVboxClass)) + +typedef struct _GalA11yECellVbox GalA11yECellVbox; +typedef struct _GalA11yECellVboxClass GalA11yECellVboxClass; + +struct _GalA11yECellVbox +{ + GalA11yECell object; + gint a11y_subcell_count; + gpointer *a11y_subcells; +}; + +struct _GalA11yECellVboxClass +{ + GalA11yECellClass parent_class; +}; + +GType gal_a11y_e_cell_vbox_get_type (void); +AtkObject *gal_a11y_e_cell_vbox_new (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row); + +G_END_DECLS +#endif /* __GAL_A11Y_E_CELL_VBOX_H__ */ diff --git a/widgets/table/gal-a11y-e-cell.c b/widgets/table/gal-a11y-e-cell.c new file mode 100644 index 0000000000..211afa401c --- /dev/null +++ b/widgets/table/gal-a11y-e-cell.c @@ -0,0 +1,639 @@ +/* + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include <string.h> + +#include <gtk/gtk.h> + +#include "a11y/gal-a11y-util.h" +#include "table/e-table.h" +#include "table/e-tree.h" +#include <glib/gi18n.h> + +#include "gal-a11y-e-cell.h" +#include "gal-a11y-e-cell-vbox.h" +#include "gal-a11y-e-table-item.h" + +#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yECellClass)) +static GObjectClass *parent_class; +#define PARENT_TYPE (atk_object_get_type ()) + +#if 0 +static void +unref_item (gpointer user_data, GObject *obj_loc) +{ + GalA11yECell *a11y = GAL_A11Y_E_CELL (user_data); + a11y->item = NULL; + g_object_unref (a11y); +} + +static void +unref_cell (gpointer user_data, GObject *obj_loc) +{ + GalA11yECell *a11y = GAL_A11Y_E_CELL (user_data); + a11y->cell_view = NULL; + g_object_unref (a11y); +} +#endif + +static gboolean +is_valid (AtkObject *cell) +{ + GalA11yECell *a11y = GAL_A11Y_E_CELL (cell); + GalA11yETableItem *a11yItem = GAL_A11Y_E_TABLE_ITEM (a11y->parent); + AtkStateSet *item_ss; + gboolean ret = TRUE; + + item_ss = atk_object_ref_state_set (ATK_OBJECT (a11yItem)); + if (atk_state_set_contains_state (item_ss, ATK_STATE_DEFUNCT)) + ret = FALSE; + + g_object_unref (item_ss); + + if (ret && atk_state_set_contains_state (a11y->state_set, ATK_STATE_DEFUNCT)) + ret = FALSE; + + return ret; +} + +static void +gal_a11y_e_cell_dispose (GObject *object) +{ + GalA11yECell *a11y = GAL_A11Y_E_CELL (object); + +#if 0 + if (a11y->item) + g_object_unref (G_OBJECT (a11y->item)); /*, unref_item, a11y); */ + if (a11y->cell_view) + g_object_unref (G_OBJECT (a11y->cell_view)); /*, unref_cell, a11y); */ + if (a11y->parent) + g_object_unref (a11y->parent); +#endif + + if (a11y->state_set) { + g_object_unref (a11y->state_set); + a11y->state_set = NULL; + } + + if (parent_class->dispose) + parent_class->dispose (object); + +} + +/* Static functions */ +static G_CONST_RETURN gchar * +gal_a11y_e_cell_get_name (AtkObject * a11y) +{ + GalA11yECell *cell = GAL_A11Y_E_CELL (a11y); + ETableCol *ecol; + + if (a11y->name != NULL && strcmp (a11y->name, "")) + return a11y->name; + + if (cell->item != NULL) { + ecol = e_table_header_get_column (cell->item->header, cell->view_col); + if (ecol != NULL) + return ecol->text; + } + + return _("Table Cell"); +} + +static AtkStateSet * +gal_a11y_e_cell_ref_state_set (AtkObject *accessible) +{ + GalA11yECell *cell = GAL_A11Y_E_CELL (accessible); + + g_return_val_if_fail (cell->state_set, NULL); + + g_object_ref(cell->state_set); + + return cell->state_set; +} + +static AtkObject* +gal_a11y_e_cell_get_parent (AtkObject *accessible) +{ + GalA11yECell *a11y = GAL_A11Y_E_CELL (accessible); + return a11y->parent; +} + +static gint +gal_a11y_e_cell_get_index_in_parent (AtkObject *accessible) +{ + GalA11yECell *a11y = GAL_A11Y_E_CELL (accessible); + + if (!is_valid (accessible)) + return -1; + + return (a11y->row + 1) * a11y->item->cols + a11y->view_col; +} + +/* Component IFace */ +static void +gal_a11y_e_cell_get_extents (AtkComponent *component, + gint *x, + gint *y, + gint *width, + gint *height, + AtkCoordType coord_type) +{ + GalA11yECell *a11y = GAL_A11Y_E_CELL (component); + GtkWidget *tableOrTree; + gint row; + gint col; + gint xval; + gint yval; + + row = a11y->row; + col = a11y->view_col; + + tableOrTree = gtk_widget_get_parent (GTK_WIDGET (a11y->item->parent.canvas)); + if (E_IS_TREE (tableOrTree)) { + e_tree_get_cell_geometry (E_TREE (tableOrTree), + row, col, &xval, &yval, + width, height); + } else { + e_table_get_cell_geometry (E_TABLE (tableOrTree), + row, col, &xval, &yval, + width, height); + } + + atk_component_get_position (ATK_COMPONENT (a11y->parent), + x, y, coord_type); + if (x && *x != G_MININT) + *x += xval; + if (y && *y != G_MININT) + *y += yval; +} + +static gboolean +gal_a11y_e_cell_grab_focus (AtkComponent *component) +{ + GalA11yECell *a11y; + gint index; + GtkWidget *toplevel; + GalA11yETableItem *a11yTableItem; + + a11y = GAL_A11Y_E_CELL (component); + + /* for e_cell_vbox's children, we just grab the e_cell_vbox */ + if (GAL_A11Y_IS_E_CELL_VBOX (a11y->parent)) { + return atk_component_grab_focus (ATK_COMPONENT (a11y->parent)); + } + + a11yTableItem = GAL_A11Y_E_TABLE_ITEM (a11y->parent); + index = atk_object_get_index_in_parent (ATK_OBJECT (a11y)); + + atk_selection_clear_selection (ATK_SELECTION (a11yTableItem)); + atk_selection_add_selection (ATK_SELECTION (a11yTableItem), index); + + gtk_widget_grab_focus (GTK_WIDGET (GNOME_CANVAS_ITEM (a11y->item)->canvas)); + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (GNOME_CANVAS_ITEM (a11y->item)->canvas)); + if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel)) + gtk_window_present (GTK_WINDOW (toplevel)); + + return TRUE; +} + +/* Table IFace */ + +static void +gal_a11y_e_cell_atk_component_iface_init (AtkComponentIface *iface) +{ + iface->get_extents = gal_a11y_e_cell_get_extents; + iface->grab_focus = gal_a11y_e_cell_grab_focus; +} + +static void +gal_a11y_e_cell_class_init (GalA11yECellClass *klass) +{ + AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_ref (PARENT_TYPE); + + object_class->dispose = gal_a11y_e_cell_dispose; + + atk_object_class->get_parent = gal_a11y_e_cell_get_parent; + atk_object_class->get_index_in_parent = gal_a11y_e_cell_get_index_in_parent; + atk_object_class->ref_state_set = gal_a11y_e_cell_ref_state_set; + atk_object_class->get_name = gal_a11y_e_cell_get_name; +} + +static void +gal_a11y_e_cell_init (GalA11yECell *a11y) +{ + a11y->item = NULL; + a11y->cell_view = NULL; + a11y->parent = NULL; + a11y->model_col = -1; + a11y->view_col = -1; + a11y->row = -1; + + a11y->state_set = atk_state_set_new (); + atk_state_set_add_state (a11y->state_set, ATK_STATE_TRANSIENT); + atk_state_set_add_state (a11y->state_set, ATK_STATE_ENABLED); + atk_state_set_add_state (a11y->state_set, ATK_STATE_SENSITIVE); + atk_state_set_add_state (a11y->state_set, ATK_STATE_SELECTABLE); + atk_state_set_add_state (a11y->state_set, ATK_STATE_SHOWING); + atk_state_set_add_state (a11y->state_set, ATK_STATE_FOCUSABLE); + atk_state_set_add_state (a11y->state_set, ATK_STATE_VISIBLE); +} + +static ActionInfo * +_gal_a11y_e_cell_get_action_info (GalA11yECell *cell, + gint index) +{ + GList *list_node; + + g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), NULL); + if (cell->action_list == NULL) + return NULL; + list_node = g_list_nth (cell->action_list, index); + if (!list_node) + return NULL; + return (ActionInfo *) (list_node->data); +} + +static void +_gal_a11y_e_cell_destroy_action_info (gpointer action_info, + gpointer user_data) +{ + ActionInfo *info = (ActionInfo *)action_info; + + g_return_if_fail (info != NULL); + g_free (info->name); + g_free (info->description); + g_free (info->keybinding); + g_free (info); +} + +gboolean +gal_a11y_e_cell_add_action ( GalA11yECell * cell, + const gchar *action_name, + const gchar *action_description, + const gchar *action_keybinding, + ACTION_FUNC action_func) +{ + ActionInfo *info; + g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), FALSE); + info = g_new (ActionInfo, 1); + + if (action_name != NULL) + info->name = g_strdup (action_name); + else + info->name = NULL; + + if (action_description != NULL) + info->description = g_strdup (action_description); + else + info->description = NULL; + if (action_keybinding != NULL) + info->keybinding = g_strdup (action_keybinding); + else + info->keybinding = NULL; + info->do_action_func = action_func; + + cell->action_list = g_list_append (cell->action_list, (gpointer) info); + return TRUE; +} + +gboolean +gal_a11y_e_cell_remove_action (GalA11yECell *cell, + gint action_index) +{ + GList *list_node; + + g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), FALSE); + list_node = g_list_nth (cell->action_list, action_index); + if (!list_node) + return FALSE; + g_return_val_if_fail (list_node->data != NULL, FALSE); + _gal_a11y_e_cell_destroy_action_info (list_node->data, NULL); + cell->action_list = g_list_remove_link (cell->action_list, list_node); + + return TRUE; +} + +gboolean +gal_a11y_e_cell_remove_action_by_name (GalA11yECell *cell, + const gchar *action_name) +{ + GList *list_node; + gboolean action_found= FALSE; + + g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), FALSE); + for (list_node = cell->action_list; list_node && !action_found; + list_node = list_node->next) { + if (!g_ascii_strcasecmp (((ActionInfo *)(list_node->data))->name, action_name)) { + action_found = TRUE; + break; + } + } + + g_return_val_if_fail (action_found, FALSE); + _gal_a11y_e_cell_destroy_action_info (list_node->data, NULL); + cell->action_list = g_list_remove_link (cell->action_list, list_node); + + return TRUE; +} + +static gint +gal_a11y_e_cell_action_get_n_actions (AtkAction *action) +{ + GalA11yECell *cell = GAL_A11Y_E_CELL(action); + if (cell->action_list != NULL) + return g_list_length (cell->action_list); + else + return 0; +} + +static G_CONST_RETURN gchar * +gal_a11y_e_cell_action_get_name (AtkAction *action, + gint index) +{ + GalA11yECell *cell = GAL_A11Y_E_CELL(action); + ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index); + + if (info == NULL) + return NULL; + return info->name; +} + +static G_CONST_RETURN gchar * +gal_a11y_e_cell_action_get_description (AtkAction *action, + gint index) +{ + GalA11yECell *cell = GAL_A11Y_E_CELL(action); + ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index); + + if (info == NULL) + return NULL; + return info->description; +} + +static gboolean +gal_a11y_e_cell_action_set_description (AtkAction *action, + gint index, + const gchar *desc) +{ + GalA11yECell *cell = GAL_A11Y_E_CELL(action); + ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index); + + if (info == NULL) + return FALSE; + g_free (info->description); + info->description = g_strdup (desc); + return TRUE; +} + +static G_CONST_RETURN gchar * +gal_a11y_e_cell_action_get_keybinding (AtkAction *action, + gint index) +{ + GalA11yECell *cell = GAL_A11Y_E_CELL(action); + ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index); + if (info == NULL) + return NULL; + + return info->keybinding; +} + +static gboolean +idle_do_action (gpointer data) +{ + GalA11yECell *cell; + + cell = GAL_A11Y_E_CELL (data); + + if (!is_valid (ATK_OBJECT (cell))) + return FALSE; + + cell->action_idle_handler = 0; + cell->action_func (cell); + g_object_unref (cell); + + return FALSE; +} + +static gboolean +gal_a11y_e_cell_action_do_action (AtkAction *action, + gint index) +{ + GalA11yECell *cell = GAL_A11Y_E_CELL(action); + ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index); + + if (!is_valid (ATK_OBJECT (action))) + return FALSE; + + if (info == NULL) + return FALSE; + g_return_val_if_fail (info->do_action_func, FALSE); + if (cell->action_idle_handler) + return FALSE; + cell->action_func = info->do_action_func; + g_object_ref (cell); + cell->action_idle_handler = g_idle_add (idle_do_action, cell); + + return TRUE; +} + +static void +gal_a11y_e_cell_atk_action_interface_init (AtkActionIface *iface) +{ + g_return_if_fail (iface != NULL); + + iface->get_n_actions = gal_a11y_e_cell_action_get_n_actions; + iface->do_action = gal_a11y_e_cell_action_do_action; + iface->get_name = gal_a11y_e_cell_action_get_name; + iface->get_description = gal_a11y_e_cell_action_get_description; + iface->set_description = gal_a11y_e_cell_action_set_description; + iface->get_keybinding = gal_a11y_e_cell_action_get_keybinding; +} + +void +gal_a11y_e_cell_type_add_action_interface (GType type) +{ + static const GInterfaceInfo atk_action_info = + { + (GInterfaceInitFunc) gal_a11y_e_cell_atk_action_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + g_type_add_interface_static (type, ATK_TYPE_ACTION, + &atk_action_info); +} + +gboolean +gal_a11y_e_cell_add_state (GalA11yECell *cell, + AtkStateType state_type, + gboolean emit_signal) +{ + if (!atk_state_set_contains_state (cell->state_set, state_type)) { + gboolean rc; + + rc = atk_state_set_add_state (cell->state_set, state_type); + /* + * The signal should only be generated if the value changed, + * not when the cell is set up. So states that are set + * initially should pass FALSE as the emit_signal argument. + */ + + if (emit_signal) { + atk_object_notify_state_change (ATK_OBJECT (cell), state_type, TRUE); + /* If state_type is ATK_STATE_VISIBLE, additional + notification */ + if (state_type == ATK_STATE_VISIBLE) + g_signal_emit_by_name (cell, "visible_data_changed"); + } + + return rc; + } + else + return FALSE; +} + +gboolean +gal_a11y_e_cell_remove_state (GalA11yECell *cell, + AtkStateType state_type, + gboolean emit_signal) +{ + if (atk_state_set_contains_state (cell->state_set, state_type)) { + gboolean rc; + + rc = atk_state_set_remove_state (cell->state_set, state_type); + /* + * The signal should only be generated if the value changed, + * not when the cell is set up. So states that are set + * initially should pass FALSE as the emit_signal argument. + */ + + if (emit_signal) { + atk_object_notify_state_change (ATK_OBJECT (cell), state_type, FALSE); + /* If state_type is ATK_STATE_VISIBLE, additional notification */ + if (state_type == ATK_STATE_VISIBLE) + g_signal_emit_by_name (cell, "visible_data_changed"); + } + + return rc; + } + else + return FALSE; +} + +/** + * gal_a11y_e_cell_get_type: + * @void: + * + * Registers the &GalA11yECell class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yECell class. + **/ +GType +gal_a11y_e_cell_get_type (void) +{ + static GType type = 0; + + if (!type) { + GTypeInfo info = { + sizeof (GalA11yECellClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gal_a11y_e_cell_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yECell), + 0, + (GInstanceInitFunc) gal_a11y_e_cell_init, + NULL /* value_cell */ + }; + + static const GInterfaceInfo atk_component_info = { + (GInterfaceInitFunc) gal_a11y_e_cell_atk_component_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + type = g_type_register_static (PARENT_TYPE, "GalA11yECell", &info, 0); + g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info); + } + + return type; +} + +AtkObject * +gal_a11y_e_cell_new (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row) +{ + AtkObject *a11y; + + a11y = g_object_new (gal_a11y_e_cell_get_type (), NULL); + + gal_a11y_e_cell_construct (a11y, + item, + cell_view, + parent, + model_col, + view_col, + row); + return a11y; +} + +void +gal_a11y_e_cell_construct (AtkObject *object, + ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row) +{ + GalA11yECell *a11y = GAL_A11Y_E_CELL (object); + a11y->item = item; + a11y->cell_view = cell_view; + a11y->parent = parent; + a11y->model_col = model_col; + a11y->view_col = view_col; + a11y->row = row; + ATK_OBJECT (a11y) ->role = ATK_ROLE_TABLE_CELL; + + if (item) + g_object_ref (G_OBJECT (item)); + +#if 0 + if (parent) + g_object_ref (parent); + + if (cell_view) + g_object_ref (G_OBJECT (cell_view)); + +#endif +} diff --git a/widgets/table/gal-a11y-e-cell.h b/widgets/table/gal-a11y-e-cell.h new file mode 100644 index 0000000000..4f2e536b8d --- /dev/null +++ b/widgets/table/gal-a11y-e-cell.h @@ -0,0 +1,109 @@ +/* + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_CELL_H__ +#define __GAL_A11Y_E_CELL_H__ + +#include <glib-object.h> +#include <table/e-table-item.h> +#include <table/e-cell.h> + +#define GAL_A11Y_TYPE_E_CELL (gal_a11y_e_cell_get_type ()) +#define GAL_A11Y_E_CELL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL, GalA11yECell)) +#define GAL_A11Y_E_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL, GalA11yECellClass)) +#define GAL_A11Y_IS_E_CELL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL)) +#define GAL_A11Y_IS_E_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL)) + +typedef struct _GalA11yECell GalA11yECell; +typedef struct _GalA11yECellClass GalA11yECellClass; +typedef struct _GalA11yECellPrivate GalA11yECellPrivate; +typedef struct _ActionInfo ActionInfo; +typedef void (*ACTION_FUNC) (GalA11yECell *cell); + +/* This struct should actually be larger as this isn't what we derive from. + * The GalA11yECellPrivate comes right after the parent class structure. + **/ +struct _GalA11yECell { + AtkObject object; + + ETableItem *item; + ECellView *cell_view; + AtkObject *parent; + gint model_col; + gint view_col; + gint row; + AtkStateSet *state_set; + GList *action_list; + gint action_idle_handler; + ACTION_FUNC action_func; +}; + +struct _GalA11yECellClass { + AtkObjectClass parent_class; +}; + +struct _ActionInfo { + gchar *name; + gchar *description; + gchar *keybinding; + ACTION_FUNC do_action_func; +}; + +/* Standard Glib function */ +GType gal_a11y_e_cell_get_type (void); +AtkObject *gal_a11y_e_cell_new (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row); +void gal_a11y_e_cell_construct (AtkObject *object, + ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + gint model_col, + gint view_col, + gint row); + +void gal_a11y_e_cell_type_add_action_interface (GType type); + +gboolean gal_a11y_e_cell_add_action (GalA11yECell *cell, + const gchar *action_name, + const gchar *action_description, + const gchar *action_keybinding, + ACTION_FUNC action_func); + +gboolean gal_a11y_e_cell_remove_action (GalA11yECell *cell, + gint action_id); + +gboolean gal_a11y_e_cell_remove_action_by_name (GalA11yECell *cell, + const gchar *action_name); + +gboolean gal_a11y_e_cell_add_state (GalA11yECell *cell, + AtkStateType state_type, + gboolean emit_signal); + +gboolean gal_a11y_e_cell_remove_state (GalA11yECell *cell, + AtkStateType state_type, + gboolean emit_signal); + +#endif /* ! __GAL_A11Y_E_CELL_H__ */ diff --git a/widgets/table/gal-a11y-e-table-click-to-add-factory.c b/widgets/table/gal-a11y-e-table-click-to-add-factory.c new file mode 100644 index 0000000000..0ebb3c4621 --- /dev/null +++ b/widgets/table/gal-a11y-e-table-click-to-add-factory.c @@ -0,0 +1,106 @@ +/* + * 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: + * Yuedong Du <yuedong.du@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include <atk/atk.h> + +#include "table/e-table.h" +#include "table/e-table-click-to-add.h" + +#include "gal-a11y-e-table.h" +#include "gal-a11y-e-table-click-to-add.h" +#include "gal-a11y-e-table-click-to-add-factory.h" + +#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETableClickToAddFactoryClass)) +static AtkObjectFactoryClass *parent_class; +#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY) + +/* Static functions */ + +static GType +gal_a11y_e_table_click_to_add_factory_get_accessible_type (void) +{ + return GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD; +} + +static AtkObject* +gal_a11y_e_table_click_to_add_factory_create_accessible (GObject *obj) +{ + AtkObject * atk_object; + + g_return_val_if_fail (E_IS_TABLE_CLICK_TO_ADD(obj), NULL); + + atk_object = gal_a11y_e_table_click_to_add_new (obj); + + return atk_object; +} + +static void +gal_a11y_e_table_click_to_add_factory_class_init (GalA11yETableClickToAddFactoryClass *klass) +{ + AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass); + + parent_class = g_type_class_ref (PARENT_TYPE); + + factory_class->create_accessible = gal_a11y_e_table_click_to_add_factory_create_accessible; + factory_class->get_accessible_type = gal_a11y_e_table_click_to_add_factory_get_accessible_type; +} + +static void +gal_a11y_e_table_click_to_add_factory_init (GalA11yETableClickToAddFactory *factory) +{ +} + +/** + * gal_a11y_e_table_factory_get_type: + * @void: + * + * Registers the &GalA11yETableFactory class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yETableFactory class. + **/ +GType +gal_a11y_e_table_click_to_add_factory_get_type (void) +{ + static GType type = 0; + + if (!type) { + GTypeInfo info = { + sizeof (GalA11yETableClickToAddFactoryClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gal_a11y_e_table_click_to_add_factory_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yETableClickToAddFactory), + 0, + (GInstanceInitFunc) gal_a11y_e_table_click_to_add_factory_init, + NULL /* value_table */ + }; + + type = g_type_register_static (PARENT_TYPE, "GalA11yETableClickToAddFactory", &info, 0); + } + + return type; +} diff --git a/widgets/table/gal-a11y-e-table-click-to-add-factory.h b/widgets/table/gal-a11y-e-table-click-to-add-factory.h new file mode 100644 index 0000000000..5321ccd241 --- /dev/null +++ b/widgets/table/gal-a11y-e-table-click-to-add-factory.h @@ -0,0 +1,49 @@ +/* + * 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: + * Yuedong Du <yuedong.du@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TABLE_CLICK_TO_ADD_FACTORY_H__ +#define __GAL_A11Y_E_TABLE_CLICK_TO_ADD_FACTORY_H__ + +#include <glib-object.h> +#include <atk/atkobjectfactory.h> + +#define GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY (gal_a11y_e_table_item_factory_get_type ()) +#define GAL_A11Y_E_TABLE_CLICK_TO_ADD_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY, GalA11yETableClickToAddFactory)) +#define GAL_A11Y_E_TABLE_CLICK_TO_ADD_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY, GalA11yETableClickToAddFactoryClass)) +#define GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY)) +#define GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY)) + +typedef struct _GalA11yETableClickToAddFactory GalA11yETableClickToAddFactory; +typedef struct _GalA11yETableClickToAddFactoryClass GalA11yETableClickToAddFactoryClass; + +struct _GalA11yETableClickToAddFactory { + AtkObject object; +}; + +struct _GalA11yETableClickToAddFactoryClass { + AtkObjectClass parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_table_click_to_add_factory_get_type (void); + +#endif diff --git a/widgets/table/gal-a11y-e-table-click-to-add.c b/widgets/table/gal-a11y-e-table-click-to-add.c new file mode 100644 index 0000000000..225f24c685 --- /dev/null +++ b/widgets/table/gal-a11y-e-table-click-to-add.c @@ -0,0 +1,338 @@ +/* + * 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: + * Yuedong Du <yuedong.du@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include <atk/atk.h> + +#include "a11y/gal-a11y-util.h" +#include "table/e-table-click-to-add.h" +#include "table/e-table-group.h" +#include "table/e-table-group-leaf.h" +#include <glib/gi18n.h> + +#include "gal-a11y-e-table-click-to-add.h" +#include "gal-a11y-e-table-click-to-add-factory.h" + +static AtkObjectClass *parent_class; +static GType parent_type; +static gint priv_offset; +#define GET_PRIVATE(object) ((GalA11yETableClickToAddPrivate *) (((gchar *) object) + priv_offset)) +#define PARENT_TYPE (parent_type) + +struct _GalA11yETableClickToAddPrivate { + gpointer rect; + gpointer row; +}; + +static gint +etcta_get_n_actions (AtkAction *action) +{ + return 1; +} + +static G_CONST_RETURN gchar * +etcta_get_description (AtkAction *action, + gint i) +{ + if (i == 0) + return _("click to add"); + + return NULL; +} + +static G_CONST_RETURN gchar * +etcta_action_get_name (AtkAction *action, gint i) +{ + if (i == 0) + return _("click"); + + return NULL; +} + +static gboolean +idle_do_action (gpointer data) +{ + GdkEventButton event; + ETableClickToAdd * etcta; + gint finished; + + g_return_val_if_fail ( data!= NULL, FALSE); + + etcta = E_TABLE_CLICK_TO_ADD (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (data))); + g_return_val_if_fail (etcta, FALSE); + + event.x = 0; + event.y = 0; + + event.type = GDK_BUTTON_PRESS; + event.window = GTK_LAYOUT(GNOME_CANVAS_ITEM(etcta)->canvas)->bin_window; + event.button = 1; + event.send_event = TRUE; + event.time = GDK_CURRENT_TIME; + event.axes = NULL; + + g_signal_emit_by_name (etcta, "event", &event, &finished); + + return FALSE; +} + +static gboolean +etcta_do_action (AtkAction * action, gint i) +{ + g_return_val_if_fail (i == 0, FALSE); + + g_idle_add (idle_do_action, action); + + return TRUE; +} + +static void +atk_action_interface_init (AtkActionIface *iface) +{ + g_return_if_fail (iface != NULL); + + iface->do_action = etcta_do_action; + iface->get_n_actions = etcta_get_n_actions; + iface->get_description = etcta_get_description; + iface->get_name = etcta_action_get_name; +} + +static G_CONST_RETURN gchar * +etcta_get_name (AtkObject *obj) +{ + ETableClickToAdd * etcta; + + g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD (obj), NULL); + + etcta = E_TABLE_CLICK_TO_ADD (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(obj))); + if (etcta && etcta->message != NULL) + return etcta->message; + + return _("click to add"); +} + +static gint +etcta_get_n_children (AtkObject *accessible) +{ + return 1; +} + +static AtkObject* +etcta_ref_child (AtkObject *accessible, + gint i) +{ + AtkObject * atk_obj = NULL; + ETableClickToAdd * etcta; + + if ( i != 0 ) + return NULL; + + etcta = E_TABLE_CLICK_TO_ADD(atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible))); + + g_return_val_if_fail (etcta, NULL); + + if (etcta->rect) { + atk_obj = atk_gobject_accessible_for_object (G_OBJECT(etcta->rect)); + } else if (etcta->row) { + atk_obj = atk_gobject_accessible_for_object (G_OBJECT(etcta->row)); + } + + g_object_ref (atk_obj); + + return atk_obj; +} + +static AtkStateSet * +etcta_ref_state_set (AtkObject *accessible) +{ + AtkStateSet * state_set = NULL; + + state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible); + if (state_set != NULL) { + atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE); + atk_state_set_add_state (state_set, ATK_STATE_SHOWING); + } + + return state_set; +} + +static void +etcta_class_init (GalA11yETableClickToAddClass *klass) +{ + AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass); + + parent_class = g_type_class_ref (PARENT_TYPE); + + atk_object_class->get_name = etcta_get_name; + atk_object_class->get_n_children = etcta_get_n_children; + atk_object_class->ref_child = etcta_ref_child; + atk_object_class->ref_state_set = etcta_ref_state_set; +} + +static void +etcta_init (GalA11yETableClickToAdd *a11y) +{ +} + +/** + * gal_a11y_e_table_click_to_add_get_type: + * @void: + * + * Registers the &GalA11yETableClickToAdd class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yETableClickToAdd class. + **/ +GType +gal_a11y_e_table_click_to_add_get_type (void) +{ + static GType type = 0; + + if (!type) { + AtkObjectFactory *factory; + + GTypeInfo info = { + sizeof (GalA11yETableClickToAddClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) etcta_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yETableClickToAdd), + 0, + (GInstanceInitFunc) etcta_init, + NULL /* value_table */ + }; + + static const GInterfaceInfo atk_action_info = { + (GInterfaceInitFunc) atk_action_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + factory = atk_registry_get_factory (atk_get_default_registry (), GNOME_TYPE_CANVAS_ITEM); + + parent_type = atk_object_factory_get_accessible_type (factory); + type = gal_a11y_type_register_static_with_private (PARENT_TYPE, + "GalA11yETableClickToAdd", &info, 0, + sizeof(GalA11yETableClickToAddPrivate), &priv_offset); + + g_type_add_interface_static (type, ATK_TYPE_ACTION, &atk_action_info); + + } + + return type; +} + +static gboolean +etcta_event (GnomeCanvasItem *item, GdkEvent *e, gpointer data) +{ + ETableClickToAdd *etcta = E_TABLE_CLICK_TO_ADD (item); + GalA11yETableClickToAdd *a11y; + GalA11yETableClickToAddPrivate *priv; + + g_return_val_if_fail (item, TRUE); + + g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD(data), FALSE); + a11y = GAL_A11Y_E_TABLE_CLICK_TO_ADD (data); + + priv = GET_PRIVATE (a11y); + + /* rect replaced by row. */ + if (etcta->rect == NULL && priv->rect != NULL) { + g_signal_emit_by_name (a11y, "children_changed::remove", 0, NULL, NULL); + + } + /* row inserted, and/or replaced by a new row. */ + if (etcta->row != NULL && priv->row == NULL) { + g_signal_emit_by_name (a11y, "children_changed::add", 0, NULL, NULL); + } else if (etcta->row != NULL && priv->row != NULL && etcta->row != priv->row) { + g_signal_emit_by_name (a11y, "children_changed::remove", 0, NULL, NULL); + g_signal_emit_by_name (a11y, "children_changed::add", 0, NULL, NULL); + } + + priv->rect = etcta->rect; + priv->row = etcta->row; + + return FALSE; +} + +static void +etcta_selection_cursor_changed (ESelectionModel *esm, gint row, gint col, + GalA11yETableClickToAdd *a11y) +{ + ETableClickToAdd *etcta; + AtkObject *row_a11y; + + etcta = E_TABLE_CLICK_TO_ADD (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(a11y))); + + if (etcta == NULL || etcta->row == NULL) + return; + + row_a11y = atk_gobject_accessible_for_object (G_OBJECT(etcta->row)); + if (row_a11y) { + AtkObject *cell_a11y = g_object_get_data (G_OBJECT(row_a11y), "gail-focus-object"); + if (cell_a11y) { + atk_focus_tracker_notify (cell_a11y); + } + } +} + +AtkObject * +gal_a11y_e_table_click_to_add_new (GObject *widget) +{ + GalA11yETableClickToAdd *a11y; + ETableClickToAdd * etcta; + GalA11yETableClickToAddPrivate *priv; + + g_return_val_if_fail (widget != NULL, NULL); + + a11y = g_object_new (gal_a11y_e_table_click_to_add_get_type (), NULL); + priv = GET_PRIVATE (a11y); + + etcta = E_TABLE_CLICK_TO_ADD(widget); + + atk_object_initialize (ATK_OBJECT (a11y), etcta); + + priv->rect = etcta->rect; + priv->row = etcta->row; + + g_signal_connect_after (G_OBJECT(widget), "event", + G_CALLBACK (etcta_event), a11y); + + g_signal_connect (etcta->selection, "cursor_changed", + G_CALLBACK (etcta_selection_cursor_changed), a11y); + + return ATK_OBJECT (a11y); +} + +void +gal_a11y_e_table_click_to_add_init (void) +{ + if (atk_get_root ()) + atk_registry_set_factory_type (atk_get_default_registry (), + E_TABLE_CLICK_TO_ADD_TYPE, + gal_a11y_e_table_click_to_add_factory_get_type ()); + +} + diff --git a/widgets/table/gal-a11y-e-table-click-to-add.h b/widgets/table/gal-a11y-e-table-click-to-add.h new file mode 100644 index 0000000000..17d6940d08 --- /dev/null +++ b/widgets/table/gal-a11y-e-table-click-to-add.h @@ -0,0 +1,55 @@ +/* + * 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 __GAL_A11Y_E_TABLE_CLICK_TO_ADD_H__ +#define __GAL_A11Y_E_TABLE_CLICK_TO_ADD_H__ + +#include <glib-object.h> +#include <table/e-table-item.h> +#include <atk/atkgobjectaccessible.h> + +#define GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD (gal_a11y_e_table_click_to_add_get_type ()) +#define GAL_A11Y_E_TABLE_CLICK_TO_ADD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD, GalA11yETableClickToAdd)) +#define GAL_A11Y_E_TABLE_CLICK_TO_ADD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD, GalA11yETableClickToAddClass)) +#define GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD)) +#define GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD)) + +typedef struct _GalA11yETableClickToAdd GalA11yETableClickToAdd; +typedef struct _GalA11yETableClickToAddClass GalA11yETableClickToAddClass; +typedef struct _GalA11yETableClickToAddPrivate GalA11yETableClickToAddPrivate; + +/* This struct should actually be larger as this isn't what we derive from. + * The GalA11yETableClickToAddPrivate comes right after the parent class structure. + **/ +struct _GalA11yETableClickToAdd { + AtkGObjectAccessible parent; +}; + +struct _GalA11yETableClickToAddClass { + AtkGObjectAccessibleClass parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_table_click_to_add_get_type (void); +AtkObject *gal_a11y_e_table_click_to_add_new (GObject *widget); + +void gal_a11y_e_table_click_to_add_init (void); +#endif /* ! __GAL_A11Y_E_TABLE_CLICK_TO_ADD_H__ */ diff --git a/widgets/table/gal-a11y-e-table-column-header.c b/widgets/table/gal-a11y-e-table-column-header.c new file mode 100644 index 0000000000..41e6ab0fca --- /dev/null +++ b/widgets/table/gal-a11y-e-table-column-header.c @@ -0,0 +1,229 @@ +/* + * + * 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: + * Li Yuan <li.yuan@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> +#include <glib/gi18n.h> +#include <atk/atkobject.h> +#include <atk/atkregistry.h> +#include "table/e-table-header-item.h" +#include "a11y/gal-a11y-util.h" +#include "gal-a11y-e-table-column-header.h" + +static GObjectClass *parent_class; +static gint priv_offset; + +#define GET_PRIVATE(object) ((GalA11yETableColumnHeaderPrivate *) (((gchar *) object) + priv_offset)) +#define PARENT_TYPE (atk_gobject_accessible_get_type ()) + +struct _GalA11yETableColumnHeaderPrivate { + ETableItem *item; + AtkObject *parent; + AtkStateSet *state_set; +}; + +static void +etch_init (GalA11yETableColumnHeader *a11y) +{ + GET_PRIVATE (a11y)->item = NULL; + GET_PRIVATE (a11y)->parent = NULL; + GET_PRIVATE (a11y)->state_set = NULL; +} + +static AtkStateSet * +gal_a11y_e_table_column_header_ref_state_set (AtkObject *accessible) +{ + GalA11yETableColumnHeaderPrivate *priv = GET_PRIVATE (accessible); + + g_return_val_if_fail (priv->state_set, NULL); + + g_object_ref(priv->state_set); + + return priv->state_set; +} + +static void +gal_a11y_e_table_column_header_real_initialize (AtkObject *obj, gpointer data) +{ + ATK_OBJECT_CLASS (parent_class)->initialize (obj, data); +} + +static void +gal_a11y_e_table_column_header_dispose (GObject *object) +{ + GalA11yETableColumnHeader *a11y = GAL_A11Y_E_TABLE_COLUMN_HEADER (object); + GalA11yETableColumnHeaderPrivate *priv = GET_PRIVATE (a11y); + + if (priv->state_set) { + g_object_unref (priv->state_set); + priv->state_set = NULL; + } + + if (parent_class->dispose) + parent_class->dispose (object); + +} + +static void +etch_class_init (GalA11yETableColumnHeaderClass *klass) +{ + AtkObjectClass *class = ATK_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_ref (PARENT_TYPE); + + object_class->dispose = gal_a11y_e_table_column_header_dispose; + + class->ref_state_set = gal_a11y_e_table_column_header_ref_state_set; + class->initialize = gal_a11y_e_table_column_header_real_initialize; +} + +inline static GObject * +etch_a11y_get_gobject (AtkGObjectAccessible *accessible) +{ + return atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)); +} + +static gboolean +gal_a11y_e_table_column_header_do_action (AtkAction *action, + gint i) +{ + gboolean return_value = TRUE; + GtkWidget *widget; + GalA11yETableColumnHeader *a11y; + ETableHeaderItem *ethi; + ETableItem *item; + ETableCol *col; + + switch (i) { + case 0: + a11y = GAL_A11Y_E_TABLE_COLUMN_HEADER (action); + col = E_TABLE_COL (etch_a11y_get_gobject (ATK_GOBJECT_ACCESSIBLE (a11y))); + item = GET_PRIVATE (a11y)->item; + widget = gtk_widget_get_parent (GTK_WIDGET (item->parent.canvas)); + if (E_IS_TREE (widget)) { + ethi = E_TABLE_HEADER_ITEM (e_tree_get_header_item (E_TREE (widget))); + } + else if (E_IS_TABLE (widget)) + ethi = E_TABLE_HEADER_ITEM (E_TABLE (widget)->header_item); + else + break; + ethi_change_sort_state (ethi, col); + default: + return_value = FALSE; + break; + } + return return_value; +} + +static gint +gal_a11y_e_table_column_header_get_n_actions (AtkAction *action) +{ + return 1; +} + +static G_CONST_RETURN gchar * +gal_a11y_e_table_column_header_action_get_name (AtkAction *action, + gint i) +{ + G_CONST_RETURN gchar *return_value; + + switch (i) { + case 0: + return_value = _("sort"); + break; + default: + return_value = NULL; + break; + } + return return_value; +} + +static void +atk_action_interface_init (AtkActionIface *iface) +{ + g_return_if_fail (iface != NULL); + + iface->do_action = gal_a11y_e_table_column_header_do_action; + iface->get_n_actions = gal_a11y_e_table_column_header_get_n_actions; + iface->get_name = gal_a11y_e_table_column_header_action_get_name; +} + +GType +gal_a11y_e_table_column_header_get_type (void) +{ + static GType type = 0; + + if (!type) { + GTypeInfo info = { + sizeof (GalA11yETableColumnHeaderClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) etch_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (GalA11yETableColumnHeader), + 0, + (GInstanceInitFunc) etch_init, + NULL + }; + static const GInterfaceInfo atk_action_info = { + (GInterfaceInitFunc) atk_action_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + type = gal_a11y_type_register_static_with_private (PARENT_TYPE, "GalA11yETableColumnHeader", &info, 0, + sizeof (GalA11yETableColumnHeaderPrivate), &priv_offset); + + g_type_add_interface_static (type, ATK_TYPE_ACTION, &atk_action_info); + } + + return type; +} + +AtkObject * +gal_a11y_e_table_column_header_new (ETableCol *ecol, ETableItem *item) +{ + GalA11yETableColumnHeader *a11y; + AtkObject *accessible; + + g_return_val_if_fail (E_IS_TABLE_COL (ecol), NULL); + + a11y = g_object_new (gal_a11y_e_table_column_header_get_type(), NULL); + accessible = ATK_OBJECT (a11y); + atk_object_initialize (accessible, ecol); + + GET_PRIVATE (a11y)->item = item; + GET_PRIVATE (a11y)->state_set = atk_state_set_new (); + + atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_VISIBLE); + atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_SHOWING); + atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_SENSITIVE); + atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_ENABLED); + + if (ecol->text) + atk_object_set_name (accessible, ecol->text); + atk_object_set_role (accessible, ATK_ROLE_TABLE_COLUMN_HEADER); + + return ATK_OBJECT (a11y); +} diff --git a/widgets/table/gal-a11y-e-table-column-header.h b/widgets/table/gal-a11y-e-table-column-header.h new file mode 100644 index 0000000000..0cf0695f75 --- /dev/null +++ b/widgets/table/gal-a11y-e-table-column-header.h @@ -0,0 +1,53 @@ +/* + * + * 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: + * Li Yuan <li.yuan@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TABLE_COLUMN_HEADER_H__ +#define __GAL_A11Y_E_TABLE_COLUMN_HEADER_H__ + +#include <glib-object.h> +#include <atk/atkgobjectaccessible.h> + +#define GAL_A11Y_TYPE_E_TABLE_COLUMN_HEADER (gal_a11y_e_table_column_header_get_type ()) +#define GAL_A11Y_E_TABLE_COLUMN_HEADER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_COLUMN_HEADER, GalA11yETableColumnHeader)) +#define GAL_A11Y_E_TABLE_COLUMN_HEADER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_COLUMN_HEADER, GalA11yETableColumnHeaderClass)) +#define GAL_A11Y_IS_E_TABLE_COLUMN_HEADER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_COLUMN_HEADER)) +#define GAL_A11Y_IS_E_TABLE_COLUMN_HEADER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_COLUMN_HEADER)) + +typedef struct _GalA11yETableColumnHeader GalA11yETableColumnHeader; +typedef struct _GalA11yETableColumnHeaderClass GalA11yETableColumnHeaderClass; +typedef struct _GalA11yETableColumnHeaderPrivate GalA11yETableColumnHeaderPrivate; + +struct _GalA11yETableColumnHeader { + AtkGObjectAccessible parent; +}; + +struct _GalA11yETableColumnHeaderClass { + AtkGObjectAccessibleClass parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_table_column_header_get_type (void); +AtkObject *gal_a11y_e_table_column_header_new (ETableCol *etc, ETableItem *item); +void gal_a11y_e_table_column_header_init (void); + +#endif /* ! __GAL_A11Y_E_TABLE_COLUMN_HEADER_H__ */ diff --git a/widgets/table/gal-a11y-e-table-factory.c b/widgets/table/gal-a11y-e-table-factory.c new file mode 100644 index 0000000000..f459f3b67c --- /dev/null +++ b/widgets/table/gal-a11y-e-table-factory.c @@ -0,0 +1,99 @@ +/* + * + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include "gal-a11y-e-table.h" +#include "gal-a11y-e-table-factory.h" + +#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETableFactoryClass)) +static AtkObjectFactoryClass *parent_class; +#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY) + +/* Static functions */ + +static GType +gal_a11y_e_table_factory_get_accessible_type (void) +{ + return GAL_A11Y_TYPE_E_TABLE; +} + +static AtkObject* +gal_a11y_e_table_factory_create_accessible (GObject *obj) +{ + AtkObject *accessible; + + accessible = gal_a11y_e_table_new (obj); + + return accessible; +} + +static void +gal_a11y_e_table_factory_class_init (GalA11yETableFactoryClass *klass) +{ + AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass); + + parent_class = g_type_class_ref (PARENT_TYPE); + + factory_class->create_accessible = gal_a11y_e_table_factory_create_accessible; + factory_class->get_accessible_type = gal_a11y_e_table_factory_get_accessible_type; +} + +static void +gal_a11y_e_table_factory_init (GalA11yETableFactory *factory) +{ +} + +/** + * gal_a11y_e_table_factory_get_type: + * @void: + * + * Registers the &GalA11yETableFactory class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yETableFactory class. + **/ +GType +gal_a11y_e_table_factory_get_type (void) +{ + static GType type = 0; + + if (!type) { + GTypeInfo info = { + sizeof (GalA11yETableFactoryClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gal_a11y_e_table_factory_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yETableFactory), + 0, + (GInstanceInitFunc) gal_a11y_e_table_factory_init, + NULL /* value_table */ + }; + + type = g_type_register_static (PARENT_TYPE, "GalA11yETableFactory", &info, 0); + } + + return type; +} diff --git a/widgets/table/gal-a11y-e-table-factory.h b/widgets/table/gal-a11y-e-table-factory.h new file mode 100644 index 0000000000..f0a1cecd0b --- /dev/null +++ b/widgets/table/gal-a11y-e-table-factory.h @@ -0,0 +1,50 @@ +/* + * + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TABLE_FACTORY_H__ +#define __GAL_A11Y_E_TABLE_FACTORY_H__ + +#include <glib-object.h> +#include <atk/atkobjectfactory.h> + +#define GAL_A11Y_TYPE_E_TABLE_FACTORY (gal_a11y_e_table_factory_get_type ()) +#define GAL_A11Y_E_TABLE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_FACTORY, GalA11yETableFactory)) +#define GAL_A11Y_E_TABLE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_FACTORY, GalA11yETableFactoryClass)) +#define GAL_A11Y_IS_E_TABLE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_FACTORY)) +#define GAL_A11Y_IS_E_TABLE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_FACTORY)) + +typedef struct _GalA11yETableFactory GalA11yETableFactory; +typedef struct _GalA11yETableFactoryClass GalA11yETableFactoryClass; + +struct _GalA11yETableFactory { + AtkObject object; +}; + +struct _GalA11yETableFactoryClass { + AtkObjectClass parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_table_factory_get_type (void); + +#endif /* ! __GAL_A11Y_E_TABLE_FACTORY_H__ */ diff --git a/widgets/table/gal-a11y-e-table-item-factory.c b/widgets/table/gal-a11y-e-table-item-factory.c new file mode 100644 index 0000000000..fa14652788 --- /dev/null +++ b/widgets/table/gal-a11y-e-table-item-factory.c @@ -0,0 +1,105 @@ +/* + * 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: + * Yuedong Du <yuedong.du@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include <atk/atk.h> + +#include "table/e-table.h" +#include "table/e-tree.h" + +#include "gal-a11y-e-table.h" +#include "gal-a11y-e-table-item.h" +#include "gal-a11y-e-table-item-factory.h" + +#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETableItemFactoryClass)) +static AtkObjectFactoryClass *parent_class; +#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY) + +/* Static functions */ + +static GType +gal_a11y_e_table_item_factory_get_accessible_type (void) +{ + return GAL_A11Y_TYPE_E_TABLE_ITEM; +} + +static AtkObject* +gal_a11y_e_table_item_factory_create_accessible (GObject *obj) +{ + AtkObject *accessible; + + g_return_val_if_fail (E_IS_TABLE_ITEM(obj), NULL); + accessible = gal_a11y_e_table_item_new (E_TABLE_ITEM (obj)); + + return accessible; +} + +static void +gal_a11y_e_table_item_factory_class_init (GalA11yETableItemFactoryClass *klass) +{ + AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass); + + parent_class = g_type_class_ref (PARENT_TYPE); + + factory_class->create_accessible = gal_a11y_e_table_item_factory_create_accessible; + factory_class->get_accessible_type = gal_a11y_e_table_item_factory_get_accessible_type; +} + +static void +gal_a11y_e_table_item_factory_init (GalA11yETableItemFactory *factory) +{ +} + +/** + * gal_a11y_e_table_factory_get_type: + * @void: + * + * Registers the &GalA11yETableFactory class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yETableFactory class. + **/ +GType +gal_a11y_e_table_item_factory_get_type (void) +{ + static GType type = 0; + + if (!type) { + GTypeInfo info = { + sizeof (GalA11yETableItemFactoryClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gal_a11y_e_table_item_factory_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yETableItemFactory), + 0, + (GInstanceInitFunc) gal_a11y_e_table_item_factory_init, + NULL /* value_table */ + }; + + type = g_type_register_static (PARENT_TYPE, "GalA11yETableItemFactory", &info, 0); + } + + return type; +} diff --git a/widgets/table/gal-a11y-e-table-item-factory.h b/widgets/table/gal-a11y-e-table-item-factory.h new file mode 100644 index 0000000000..5fdf7ce1ef --- /dev/null +++ b/widgets/table/gal-a11y-e-table-item-factory.h @@ -0,0 +1,49 @@ +/* + * 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: + * Yuedong Du <yuedong.du@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TABLE_ITEM_FACTORY_H__ +#define __GAL_A11Y_E_TABLE_ITEM_FACTORY_H__ + +#include <glib-object.h> +#include <atk/atkobjectfactory.h> + +#define GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY (gal_a11y_e_table_item_factory_get_type ()) +#define GAL_A11Y_E_TABLE_ITEM_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY, GalA11yETableItemFactory)) +#define GAL_A11Y_E_TABLE_ITEM_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY, GalA11yETableItemFactoryClass)) +#define GAL_A11Y_IS_E_TABLE_ITEM_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY)) +#define GAL_A11Y_IS_E_TABLE_ITEM_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY)) + +typedef struct _GalA11yETableItemFactory GalA11yETableItemFactory; +typedef struct _GalA11yETableItemFactoryClass GalA11yETableItemFactoryClass; + +struct _GalA11yETableItemFactory { + AtkObject object; +}; + +struct _GalA11yETableItemFactoryClass { + AtkObjectClass parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_table_item_factory_get_type (void); + +#endif /* ! __GAL_A11Y_E_TABLE_FACTORY_H__ */ diff --git a/widgets/table/gal-a11y-e-table-item.c b/widgets/table/gal-a11y-e-table-item.c new file mode 100644 index 0000000000..37f55f68c1 --- /dev/null +++ b/widgets/table/gal-a11y-e-table-item.c @@ -0,0 +1,1320 @@ +/* + * 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: + * Christopher James Lahey <clahey@ximian.com> + * Bolian Yin <bolian.yin@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include <string.h> + +#include <atk/atk.h> + +#include "a11y/gal-a11y-util.h" +#include "table/e-table-click-to-add.h" +#include "table/e-table-subset.h" +#include "table/e-table.h" +#include "table/e-tree.h" +#include "misc/e-canvas.h" +#include "misc/e-selection-model.h" + +#include "gal-a11y-e-table-item.h" +#include "gal-a11y-e-table-item-factory.h" +#include "gal-a11y-e-table-click-to-add.h" +#include "gal-a11y-e-cell-registry.h" +#include "gal-a11y-e-cell.h" +#include "gal-a11y-e-table-column-header.h" + +#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yETableItemClass)) +static GObjectClass *parent_class; +static AtkComponentIface *component_parent_iface; +static GType parent_type; +static gint priv_offset; +static GQuark quark_accessible_object = 0; +#define GET_PRIVATE(object) ((GalA11yETableItemPrivate *) (((gchar *) object) + priv_offset)) +#define PARENT_TYPE (parent_type) + +struct _GalA11yETableItemPrivate { + gint cols; + gint rows; + gint selection_change_id; + gint cursor_change_id; + ETableCol ** columns; + ESelectionModel *selection; + AtkStateSet *state_set; + GtkWidget *widget; +}; + +static gboolean gal_a11y_e_table_item_ref_selection (GalA11yETableItem *a11y, + ESelectionModel *selection); +static gboolean gal_a11y_e_table_item_unref_selection (GalA11yETableItem *a11y); + +static AtkObject* eti_ref_at (AtkTable *table, gint row, gint column); + +static void +item_destroyed (GtkObject *item, gpointer user_data) +{ + GalA11yETableItem *a11y = GAL_A11Y_E_TABLE_ITEM (user_data); + GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y); + + atk_state_set_add_state (priv->state_set, ATK_STATE_DEFUNCT); + atk_object_notify_state_change (ATK_OBJECT (a11y), ATK_STATE_DEFUNCT, TRUE); + + if (priv->selection) + gal_a11y_e_table_item_unref_selection (a11y); + +} + +static AtkStateSet * +eti_ref_state_set (AtkObject *accessible) +{ + GalA11yETableItemPrivate *priv = GET_PRIVATE (accessible); + + g_object_ref(priv->state_set); + + return priv->state_set; +} + +inline static gint +view_to_model_row(ETableItem *eti, gint row) +{ + if (eti->uses_source_model) { + ETableSubset *etss = E_TABLE_SUBSET(eti->table_model); + if (row >= 0 && row < etss->n_map) { + eti->row_guess = row; + return etss->map_table[row]; + } else + return -1; + } else + return row; +} + +inline static gint +view_to_model_col(ETableItem *eti, gint col) +{ + ETableCol *ecol = e_table_header_get_column (eti->header, col); + return ecol ? ecol->col_idx : -1; +} + +inline static gint +model_to_view_row(ETableItem *eti, gint row) +{ + gint i; + if (row == -1) + return -1; + if (eti->uses_source_model) { + ETableSubset *etss = E_TABLE_SUBSET(eti->table_model); + if (eti->row_guess >= 0 && eti->row_guess < etss->n_map) { + if (etss->map_table[eti->row_guess] == row) { + return eti->row_guess; + } + } + for (i = 0; i < etss->n_map; i++) { + if (etss->map_table[i] == row) + return i; + } + return -1; + } else + return row; +} + +inline static gint +model_to_view_col(ETableItem *eti, gint col) +{ + gint i; + if (col == -1) + return -1; + for (i = 0; i < eti->cols; i++) { + ETableCol *ecol = e_table_header_get_column (eti->header, i); + if (ecol->col_idx == col) + return i; + } + return -1; +} + +inline static GObject * +eti_a11y_get_gobject (AtkObject *accessible) +{ + return atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)); +} + +static void +eti_a11y_reset_focus_object (GalA11yETableItem *a11y, ETableItem *item, gboolean notify) +{ + ESelectionModel * esm; + gint cursor_row, cursor_col, view_row, view_col; + AtkObject *cell, *old_cell; + + esm = item->selection; + g_return_if_fail (esm); + + cursor_row = e_selection_model_cursor_row (esm); + cursor_col = e_selection_model_cursor_col (esm); + + view_row = model_to_view_row (item, cursor_row); + view_col = model_to_view_col (item, cursor_col); + + if (view_row == -1) + view_row = 0; + if (view_col == -1) + view_col = 0; + + old_cell = (AtkObject *)g_object_get_data (G_OBJECT (a11y), "gail-focus-object"); + if (old_cell && GAL_A11Y_IS_E_CELL (old_cell)) + gal_a11y_e_cell_remove_state (GAL_A11Y_E_CELL (old_cell), ATK_STATE_FOCUSED, FALSE); + if (old_cell) + g_object_unref (old_cell); + + cell = eti_ref_at (ATK_TABLE (a11y), view_row, view_col); + + if (cell != NULL) { + g_object_set_data (G_OBJECT (a11y), "gail-focus-object", cell); + gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL (cell), ATK_STATE_FOCUSED, FALSE); + } else + g_object_set_data (G_OBJECT (a11y), "gail-focus-object", NULL); + + if (notify && cell) + atk_focus_tracker_notify (cell); +} + +static void +eti_dispose (GObject *object) +{ + GalA11yETableItem *a11y = GAL_A11Y_E_TABLE_ITEM (object); + GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y); + + if (priv->columns) { + g_free(priv->columns); + priv->columns = NULL; + } + + if (parent_class->dispose) + parent_class->dispose (object); +} + +/* Static functions */ +static gint +eti_get_n_children (AtkObject *accessible) +{ + g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (accessible), 0); + if (!eti_a11y_get_gobject (accessible)) + return 0; + + return atk_table_get_n_columns (ATK_TABLE (accessible)) * + (atk_table_get_n_rows (ATK_TABLE (accessible)) + 1); +} + +static AtkObject* +eti_ref_child (AtkObject *accessible, gint index) +{ + ETableItem *item; + gint col, row; + + g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (accessible), NULL); + item = E_TABLE_ITEM (eti_a11y_get_gobject (accessible)); + if (!item) + return NULL; + + if (index < item->cols) { + ETableCol *ecol; + AtkObject *child; + + ecol = e_table_header_get_column (item->header, index); + child = gal_a11y_e_table_column_header_new (ecol, item); + return child; + } + index -= item->cols; + + col = index % item->cols; + row = index / item->cols; + + return eti_ref_at (ATK_TABLE (accessible), row, col); +} + +static void +eti_get_extents (AtkComponent *component, + gint *x, + gint *y, + gint *width, + gint *height, + AtkCoordType coord_type) +{ + ETableItem *item; + AtkObject *parent; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (component))); + if (!item) + return; + + parent = ATK_OBJECT (component)->accessible_parent; + if (parent && ATK_IS_COMPONENT (parent)) + atk_component_get_extents (ATK_COMPONENT (parent), x, y, + width, height, + coord_type); + + if (parent && GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD (parent)) { + ETableClickToAdd *etcta = E_TABLE_CLICK_TO_ADD (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (parent))); + if (etcta) { + *width = etcta->width; + *height = etcta->height; + } + } +} + +static AtkObject* +eti_ref_accessible_at_point (AtkComponent *component, + gint x, + gint y, + AtkCoordType coord_type) +{ + gint row = -1; + gint col = -1; + gint x_origin, y_origin; + ETableItem *item; + GtkWidget *tableOrTree; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (component))); + if (!item) + return NULL; + + atk_component_get_position (component, + &x_origin, + &y_origin, + coord_type); + x -= x_origin; + y -= y_origin; + + tableOrTree = gtk_widget_get_parent (GTK_WIDGET (item->parent.canvas)); + + if (E_IS_TREE(tableOrTree)) + e_tree_get_cell_at (E_TREE (tableOrTree), x, y, &row, &col); + else + e_table_get_cell_at (E_TABLE (tableOrTree), x, y, &row, &col); + + if (row != -1 && col != -1) { + return eti_ref_at (ATK_TABLE (component), row, col); + } else { + return NULL; + } +} + +static void +cell_destroyed (gpointer data) +{ + GalA11yECell * cell; + + g_return_if_fail (GAL_A11Y_IS_E_CELL (data)); + cell = GAL_A11Y_E_CELL (data); + + g_return_if_fail (cell->item && G_IS_OBJECT (cell->item)); + + if (cell->item) { + g_object_unref (cell->item); + cell->item = NULL; + } + +} + +/* atk table */ +static AtkObject* +eti_ref_at (AtkTable *table, gint row, gint column) +{ + ETableItem *item; + AtkObject* ret; + GalA11yETableItemPrivate *priv = GET_PRIVATE (table); + + if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) + return NULL; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); + if (!item) + return NULL; + + if (column >= 0 && + column < item->cols && + row >= 0 && + row < item->rows && + item->cell_views_realized) { + ECellView *cell_view = item->cell_views[column]; + ETableCol *ecol = e_table_header_get_column (item->header, column); + ret = gal_a11y_e_cell_registry_get_object (NULL, + item, + cell_view, + ATK_OBJECT (table), + ecol->col_idx, + column, + row); + if (ATK_IS_OBJECT (ret)) { + g_object_weak_ref (G_OBJECT (ret), + (GWeakNotify) cell_destroyed, + ret); + /* if current cell is focused, add FOCUSED state */ + if (e_selection_model_cursor_row (item->selection) == GAL_A11Y_E_CELL (ret)->row && + e_selection_model_cursor_col (item->selection) == GAL_A11Y_E_CELL (ret)->model_col) + gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL (ret), ATK_STATE_FOCUSED, FALSE); + } else + ret = NULL; + + return ret; + } + + return NULL; +} + +static gint +eti_get_index_at (AtkTable *table, gint row, gint column) +{ + ETableItem *item; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); + if (!item) + return -1; + + return column + (row + 1) * item->cols; +} + +static gint +eti_get_column_at_index (AtkTable *table, gint index) +{ + ETableItem *item; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); + if (!item) + return -1; + + return index % item->cols; +} + +static gint +eti_get_row_at_index (AtkTable *table, gint index) +{ + ETableItem *item; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); + if (!item) + return -1; + + return index / item->cols - 1; +} + +static gint +eti_get_n_columns (AtkTable *table) +{ + ETableItem *item; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); + if (!item) + return -1; + + return item->cols; +} + +static gint +eti_get_n_rows (AtkTable *table) +{ + ETableItem *item; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); + if (!item) + return -1; + + return item->rows; +} + +static gint +eti_get_column_extent_at (AtkTable *table, + gint row, + gint column) +{ + ETableItem *item; + gint width; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); + if (!item) + return -1; + + e_table_item_get_cell_geometry (item, + &row, + &column, + NULL, + NULL, + &width, + NULL); + + return width; +} + +static gint +eti_get_row_extent_at (AtkTable *table, + gint row, + gint column) +{ + ETableItem *item; + gint height; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); + if (!item) + return -1; + + e_table_item_get_cell_geometry (item, + &row, + &column, + NULL, + NULL, + NULL, + &height); + + return height; +} + +static AtkObject * +eti_get_caption (AtkTable *table) +{ + /* Unimplemented */ + return NULL; +} + +static G_CONST_RETURN gchar * +eti_get_column_description (AtkTable *table, + gint column) +{ + ETableItem *item; + ETableCol *ecol; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); + if (!item) + return NULL; + + ecol = e_table_header_get_column (item->header, column); + + return ecol->text; +} + +static AtkObject * +eti_get_column_header (AtkTable *table, gint column) +{ + ETableItem *item; + ETableCol *ecol; + AtkObject *atk_obj = NULL; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); + if (!item) + return NULL; + + ecol = e_table_header_get_column (item->header, column); + if (ecol) { + atk_obj = gal_a11y_e_table_column_header_new (ecol, item); + } + + return atk_obj; +} + +static G_CONST_RETURN gchar * +eti_get_row_description (AtkTable *table, + gint row) +{ + /* Unimplemented */ + return NULL; +} + +static AtkObject * +eti_get_row_header (AtkTable *table, + gint row) +{ + /* Unimplemented */ + return NULL; +} + +static AtkObject * +eti_get_summary (AtkTable *table) +{ + /* Unimplemented */ + return NULL; +} + +static gboolean +table_is_row_selected (AtkTable *table, gint row) +{ + ETableItem *item; + GalA11yETableItemPrivate *priv = GET_PRIVATE (table); + + if (row < 0) + return FALSE; + + if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) + return FALSE; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); + if (!item) + return FALSE; + + return e_selection_model_is_row_selected(item->selection, view_to_model_row (item, row)); +} + +static gboolean +table_is_selected (AtkTable *table, gint row, gint column) +{ + return table_is_row_selected (table, row); +} + +static gint +table_get_selected_rows (AtkTable *table, gint **rows_selected) +{ + ETableItem *item; + gint n_selected, row, index_selected; + GalA11yETableItemPrivate *priv = GET_PRIVATE (table); + + if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) + return 0; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); + if (!item) + return 0; + + n_selected = e_selection_model_selected_count (item->selection); + if (rows_selected) { + *rows_selected = (gint *) g_malloc (n_selected * sizeof (gint)); + + index_selected = 0; + for (row = 0; row < item->rows && index_selected < n_selected; ++row) { + if (atk_table_is_row_selected (table, row)) { + (*rows_selected)[index_selected] = row; + ++index_selected; + } + } + } + return n_selected; +} + +static gboolean +table_add_row_selection (AtkTable *table, gint row) +{ + ETableItem *item; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); + if (!item) + return FALSE; + + if (table_is_row_selected (table, row)) + return TRUE; + e_selection_model_toggle_single_row (item->selection, + view_to_model_row (item, row)); + + return TRUE; +} + +static gboolean +table_remove_row_selection (AtkTable *table, gint row) +{ + ETableItem *item; + GalA11yETableItemPrivate *priv = GET_PRIVATE (table); + + if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) + return FALSE; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); + if (!item) + return FALSE; + + if (!atk_table_is_row_selected (table, row)) + return TRUE; + e_selection_model_toggle_single_row (item->selection, view_to_model_row (item, row)); + return TRUE; +} + +static void +eti_atk_table_iface_init (AtkTableIface *iface) +{ + iface->ref_at = eti_ref_at; + iface->get_index_at = eti_get_index_at; + iface->get_column_at_index = eti_get_column_at_index; + iface->get_row_at_index = eti_get_row_at_index; + iface->get_n_columns = eti_get_n_columns; + iface->get_n_rows = eti_get_n_rows; + iface->get_column_extent_at = eti_get_column_extent_at; + iface->get_row_extent_at = eti_get_row_extent_at; + iface->get_caption = eti_get_caption; + iface->get_column_description = eti_get_column_description; + iface->get_column_header = eti_get_column_header; + iface->get_row_description = eti_get_row_description; + iface->get_row_header = eti_get_row_header; + iface->get_summary = eti_get_summary; + + iface->is_row_selected = table_is_row_selected; + iface->is_selected = table_is_selected; + iface->get_selected_rows = table_get_selected_rows; + iface->add_row_selection = table_add_row_selection; + iface->remove_row_selection = table_remove_row_selection; +} + +static void +eti_atk_component_iface_init (AtkComponentIface *iface) +{ + component_parent_iface = g_type_interface_peek_parent (iface); + + iface->ref_accessible_at_point = eti_ref_accessible_at_point; + iface->get_extents = eti_get_extents; +} + +static void +eti_rows_inserted (ETableModel * model, gint row, gint count, + AtkObject * table_item) +{ + gint n_cols,n_rows,i,j; + GalA11yETableItem * item_a11y; + gint old_nrows; + + g_return_if_fail (table_item); + item_a11y = GAL_A11Y_E_TABLE_ITEM (table_item); + + n_cols = atk_table_get_n_columns (ATK_TABLE(table_item)); + n_rows = atk_table_get_n_rows (ATK_TABLE(table_item)); + + old_nrows = GET_PRIVATE(item_a11y)->rows; + + g_return_if_fail (n_cols > 0 && n_rows > 0); + g_return_if_fail (old_nrows == n_rows - count); + + GET_PRIVATE(table_item)->rows = n_rows; + + g_signal_emit_by_name (table_item, "row-inserted", row, + count, NULL); + + for (i = row; i < (row + count); i ++) { + for (j = 0; j < n_cols; j ++) { + g_signal_emit_by_name (table_item, + "children_changed::add", + ( ((i + 1)*n_cols) + j), NULL, NULL); + } + } + + g_signal_emit_by_name (table_item, "visible-data-changed"); +} + +static void +eti_rows_deleted (ETableModel * model, gint row, gint count, + AtkObject * table_item) +{ + gint i,j, n_rows, n_cols, old_nrows; + ETableItem *item = E_TABLE_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (table_item))); + + n_rows = atk_table_get_n_rows (ATK_TABLE(table_item)); + n_cols = atk_table_get_n_columns (ATK_TABLE(table_item)); + + old_nrows = GET_PRIVATE(table_item)->rows; + + g_return_if_fail ( row+count <= old_nrows); + g_return_if_fail (old_nrows == n_rows + count); + GET_PRIVATE(table_item)->rows = n_rows; + + g_signal_emit_by_name (table_item, "row-deleted", row, + count, NULL); + + for (i = row; i < (row + count); i ++) { + for (j = 0; j < n_cols; j ++) { + g_signal_emit_by_name (table_item, + "children_changed::remove", + ( ((i + 1)*n_cols) + j), NULL, NULL); + } + } + g_signal_emit_by_name (table_item, "visible-data-changed"); + eti_a11y_reset_focus_object ((GalA11yETableItem *)table_item, item, TRUE); +} + +static void +eti_tree_model_node_changed_cb (ETreeModel *model, ETreePath node, ETableItem *eti) +{ + AtkObject *atk_obj; + GalA11yETableItem *a11y; + + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti)); + a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj); + + /* we can't figure out which rows are changed, so just send out a signal ... */ + if (GET_PRIVATE (a11y)->rows > 0) + g_signal_emit_by_name (a11y, "visible-data-changed"); +} + +enum { + ETI_HEADER_UNCHANGED = 0, + ETI_HEADER_REORDERED, + ETI_HEADER_NEW_ADDED, + ETI_HEADER_REMOVED +}; + +/* + * 1. Check what actually happened: column reorder, remove or add + * 2. Update cache + * 3. Emit signals + */ +static void +eti_header_structure_changed (ETableHeader *eth, AtkObject *a11y) +{ + + gboolean reorder_found=FALSE, added_found=FALSE, removed_found=FALSE; + GalA11yETableItem * a11y_item; + ETableCol ** cols, **prev_cols; + GalA11yETableItemPrivate *priv; + gint *state = NULL, *prev_state = NULL, *reorder = NULL; + gint i,j,n_rows,n_cols, prev_n_cols; + + a11y_item = GAL_A11Y_E_TABLE_ITEM (a11y); + priv = GET_PRIVATE (a11y_item); + + /* Assume rows do not changed. */ + n_rows = priv->rows; + + prev_n_cols = priv->cols; + prev_cols = priv->columns; + + cols = e_table_header_get_columns (eth); + n_cols = eth->col_count; + + g_return_if_fail (cols && prev_cols && n_cols > 0); + + /* Init to ETI_HEADER_UNCHANGED. */ + state = g_malloc0 (sizeof (gint) * n_cols); + prev_state = g_malloc0 (sizeof (gint) * prev_n_cols); + reorder = g_malloc0 (sizeof (gint) * n_cols); + + /* Compare with previously saved column headers. */ + for ( i = 0; i < n_cols && cols[i]; i ++ ) { + for ( j = 0; j < prev_n_cols && prev_cols[j]; j ++ ) { + if ( prev_cols [j] == cols[i] && i != j ) { + + reorder_found = TRUE; + state [i] = ETI_HEADER_REORDERED; + reorder [i] = j; + + break; + } else if (prev_cols[j] == cols[i]) { + /* OK, this column is not changed. */ + break; + } + } + + /* cols[i] is new added column. */ + if ( j == prev_n_cols ) { + added_found = TRUE; + state[i] = ETI_HEADER_NEW_ADDED; + } + } + + /* Now try to find if there are removed columns. */ + for (i = 0; i < prev_n_cols && prev_cols[i]; i ++) { + for (j = 0; j < n_cols && cols[j]; j ++) + if ( prev_cols [j] == cols[i] ) + break; + + /* Removed columns found. */ + if ( j == n_cols ) { + removed_found = TRUE; + prev_state[j] = ETI_HEADER_REMOVED; + } + } + + /* If nothing interesting just return. */ + if (!reorder_found && !added_found && !removed_found) + return; + + /* Emit signals */ + if (reorder_found) + g_signal_emit_by_name (G_OBJECT(a11y_item), "column_reordered"); + + if (removed_found) { + for (i = 0; i < prev_n_cols; i ++ ) { + if (prev_state[i] == ETI_HEADER_REMOVED) { + g_signal_emit_by_name (G_OBJECT(a11y_item), "column-deleted", i, 1); + for (j = 0; j < n_rows; j ++) + g_signal_emit_by_name (G_OBJECT(a11y_item), "children_changed::remove", ((j+1)*prev_n_cols+i), NULL, NULL); + } + } + } + + if (added_found) { + for ( i = 0; i < n_cols; i ++ ) { + if (state[i] == ETI_HEADER_NEW_ADDED) { + g_signal_emit_by_name (G_OBJECT(a11y_item), "column-inserted", i, 1); + for (j = 0; j < n_rows; j ++) + g_signal_emit_by_name (G_OBJECT(a11y_item), "children_changed::add", ((j+1)*n_cols+i), NULL, NULL); + } + } + } + + priv->cols = n_cols; + + g_free (state); + g_free (reorder); + g_free (prev_state); + + g_free (priv->columns); + priv->columns = cols; +} + +static void +eti_real_initialize (AtkObject *obj, + gpointer data) +{ + ETableItem * eti; + ETableModel * model; + + ATK_OBJECT_CLASS (parent_class)->initialize (obj, data); + eti = E_TABLE_ITEM (data); + + model = eti->table_model; + + g_signal_connect (model, "model-rows-inserted", + G_CALLBACK (eti_rows_inserted), + obj); + g_signal_connect (model, "model-rows-deleted", + G_CALLBACK (eti_rows_deleted), + obj); + g_signal_connect (G_OBJECT (eti->header), "structure_change", + G_CALLBACK (eti_header_structure_changed), obj); + +} + +static void +eti_class_init (GalA11yETableItemClass *klass) +{ + AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + quark_accessible_object = g_quark_from_static_string ("gtk-accessible-object"); + + parent_class = g_type_class_ref (PARENT_TYPE); + + object_class->dispose = eti_dispose; + + atk_object_class->get_n_children = eti_get_n_children; + atk_object_class->ref_child = eti_ref_child; + atk_object_class->initialize = eti_real_initialize; + atk_object_class->ref_state_set = eti_ref_state_set; +} + +static void +eti_init (GalA11yETableItem *a11y) +{ + GalA11yETableItemPrivate *priv; + + priv = GET_PRIVATE (a11y); + + priv->selection_change_id = 0; + priv->cursor_change_id = 0; + priv->selection = NULL; +} + +/* atk selection */ + +static void atk_selection_interface_init (AtkSelectionIface *iface); +static gboolean selection_add_selection (AtkSelection *selection, + gint i); +static gboolean selection_clear_selection (AtkSelection *selection); +static AtkObject* selection_ref_selection (AtkSelection *selection, + gint i); +static gint selection_get_selection_count (AtkSelection *selection); +static gboolean selection_is_child_selected (AtkSelection *selection, + gint i); + +/* callbacks */ +static void eti_a11y_selection_model_removed_cb (ETableItem *eti, + ESelectionModel *selection, + gpointer data); +static void eti_a11y_selection_model_added_cb (ETableItem *eti, + ESelectionModel *selection, + gpointer data); +static void eti_a11y_selection_changed_cb (ESelectionModel *selection, + GalA11yETableItem *a11y); +static void eti_a11y_cursor_changed_cb (ESelectionModel *selection, + gint row, gint col, + GalA11yETableItem *a11y); + +/** + * gal_a11y_e_table_item_get_type: + * @void: + * + * Registers the &GalA11yETableItem class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yETableItem class. + **/ +GType +gal_a11y_e_table_item_get_type (void) +{ + static GType type = 0; + + if (!type) { + AtkObjectFactory *factory; + + GTypeInfo info = { + sizeof (GalA11yETableItemClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) eti_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yETableItem), + 0, + (GInstanceInitFunc) eti_init, + NULL /* value_table_item */ + }; + + static const GInterfaceInfo atk_component_info = { + (GInterfaceInitFunc) eti_atk_component_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + static const GInterfaceInfo atk_table_info = { + (GInterfaceInitFunc) eti_atk_table_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + static const GInterfaceInfo atk_selection_info = { + (GInterfaceInitFunc) atk_selection_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + factory = atk_registry_get_factory (atk_get_default_registry (), GNOME_TYPE_CANVAS_ITEM); + parent_type = atk_object_factory_get_accessible_type (factory); + + type = gal_a11y_type_register_static_with_private (PARENT_TYPE, "GalA11yETableItem", &info, 0, + sizeof (GalA11yETableItemPrivate), &priv_offset); + + g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info); + g_type_add_interface_static (type, ATK_TYPE_TABLE, &atk_table_info); + g_type_add_interface_static (type, ATK_TYPE_SELECTION, &atk_selection_info); + } + + return type; +} + +AtkObject * +gal_a11y_e_table_item_new (ETableItem *item) +{ + GalA11yETableItem *a11y; + AtkObject *accessible; + ESelectionModel * esm; + AtkObject *parent; + const gchar *name; + + g_return_val_if_fail (item && item->cols >= 0 && item->rows >= 0, NULL); + a11y = g_object_new (gal_a11y_e_table_item_get_type (), NULL); + + atk_object_initialize (ATK_OBJECT (a11y), item); + + GET_PRIVATE (a11y)->state_set = atk_state_set_new (); + + atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_TRANSIENT); + atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_ENABLED); + atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_SENSITIVE); + atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_SHOWING); + atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_VISIBLE); + + accessible = ATK_OBJECT(a11y); + + /* Initialize cell data. */ + GET_PRIVATE (a11y)->cols = item->cols; + GET_PRIVATE (a11y)->rows = item->rows; + + GET_PRIVATE (a11y)->columns = e_table_header_get_columns (item->header); + if ( GET_PRIVATE (a11y)->columns == NULL) + return NULL; + + if (item) { + g_signal_connect (G_OBJECT(item), "selection_model_removed", + G_CALLBACK (eti_a11y_selection_model_removed_cb), NULL); + g_signal_connect (G_OBJECT(item), "selection_model_added", + G_CALLBACK (eti_a11y_selection_model_added_cb), NULL); + if (item->selection) + gal_a11y_e_table_item_ref_selection (a11y, + item->selection); + + /* find the TableItem's parent: table or tree */ + GET_PRIVATE (a11y)->widget = gtk_widget_get_parent (GTK_WIDGET (item->parent.canvas)); + parent = gtk_widget_get_accessible (GET_PRIVATE (a11y)->widget); + name = atk_object_get_name (parent); + if (name) + atk_object_set_name (accessible, name); + atk_object_set_parent (accessible, parent); + + if (E_IS_TREE (GET_PRIVATE (a11y)->widget)) { + ETreeModel *model; + model = e_tree_get_model (E_TREE (GET_PRIVATE (a11y)->widget)); + g_signal_connect (G_OBJECT(model), "node_changed", + G_CALLBACK (eti_tree_model_node_changed_cb), item); + accessible->role = ATK_ROLE_TREE_TABLE; + } else if (E_IS_TABLE (GET_PRIVATE (a11y)->widget)) { + accessible->role = ATK_ROLE_TABLE; + } + } + + if (item) + g_signal_connect (G_OBJECT (item), "destroy", + G_CALLBACK (item_destroyed), + a11y); + esm = item->selection; + + if (esm != NULL) { + eti_a11y_reset_focus_object (a11y, item, FALSE); + } + + return ATK_OBJECT (a11y); +} + +static gboolean +gal_a11y_e_table_item_ref_selection (GalA11yETableItem *a11y, + ESelectionModel *selection) +{ + GalA11yETableItemPrivate *priv; + + g_return_val_if_fail (a11y && selection, FALSE); + + priv = GET_PRIVATE (a11y); + priv->selection_change_id = g_signal_connect ( + G_OBJECT(selection), "selection_changed", + G_CALLBACK (eti_a11y_selection_changed_cb), a11y); + priv->cursor_change_id = g_signal_connect ( + G_OBJECT(selection), "cursor_changed", + G_CALLBACK (eti_a11y_cursor_changed_cb), a11y); + + priv->selection = selection; + g_object_ref (selection); + + return TRUE; +} + +static gboolean +gal_a11y_e_table_item_unref_selection (GalA11yETableItem *a11y) +{ + GalA11yETableItemPrivate *priv; + + g_return_val_if_fail (a11y, FALSE); + + priv = GET_PRIVATE (a11y); + + g_return_val_if_fail (priv->selection_change_id != 0, FALSE); + g_return_val_if_fail (priv->cursor_change_id != 0, FALSE); + + g_signal_handler_disconnect (priv->selection, + priv->selection_change_id); + g_signal_handler_disconnect (priv->selection, + priv->cursor_change_id); + priv->cursor_change_id = 0; + priv->selection_change_id = 0; + + g_object_unref (priv->selection); + priv->selection = NULL; + + return TRUE; +} + +/* callbacks */ + +static void +eti_a11y_selection_model_removed_cb (ETableItem *eti, ESelectionModel *selection, + gpointer data) +{ + AtkObject *atk_obj; + GalA11yETableItem *a11y; + + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + g_return_if_fail (E_IS_SELECTION_MODEL (selection)); + + atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti)); + a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj); + + if (selection == GET_PRIVATE (a11y)->selection) + gal_a11y_e_table_item_unref_selection (a11y); +} + +static void +eti_a11y_selection_model_added_cb (ETableItem *eti, ESelectionModel *selection, + gpointer data) +{ + AtkObject *atk_obj; + GalA11yETableItem *a11y; + + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + g_return_if_fail (E_IS_SELECTION_MODEL (selection)); + + atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti)); + a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj); + + if (GET_PRIVATE (a11y)->selection) + gal_a11y_e_table_item_unref_selection (a11y); + gal_a11y_e_table_item_ref_selection (a11y, selection); +} + +static void +eti_a11y_selection_changed_cb (ESelectionModel *selection, GalA11yETableItem *a11y) +{ + GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y); + + if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) + return; + + g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y)); + + g_signal_emit_by_name (a11y, "selection_changed"); +} + +static void +eti_a11y_cursor_changed_cb (ESelectionModel *selection, + gint row, gint col, GalA11yETableItem *a11y) +{ + ETableItem *item; + GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y); + + g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y)); + + if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) + return; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (a11y))); + + g_return_if_fail (item); + + if (row == -1 && col == -1) + return; + eti_a11y_reset_focus_object (a11y, item, TRUE); +} + +/* atk selection */ + +static void atk_selection_interface_init (AtkSelectionIface *iface) +{ + g_return_if_fail (iface != NULL); + iface->add_selection = selection_add_selection; + iface->clear_selection = selection_clear_selection; + iface->ref_selection = selection_ref_selection; + iface->get_selection_count = selection_get_selection_count; + iface->is_child_selected = selection_is_child_selected; +} + +static gboolean +selection_add_selection (AtkSelection *selection, gint index) +{ + AtkTable *table; + gint row, col, cursor_row, cursor_col, model_row, model_col; + ETableItem *item; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (selection))); + if (!item) + return FALSE; + + table = ATK_TABLE (selection); + + row = atk_table_get_row_at_index (table, index); + col = atk_table_get_column_at_index (table, index); + + model_row = view_to_model_row (item, row); + model_col = view_to_model_col (item, col); + + cursor_row = e_selection_model_cursor_row (item->selection); + cursor_col = e_selection_model_cursor_col (item->selection); + + /* check whether is selected already */ + if (model_row == cursor_row && model_col == cursor_col) + return TRUE; + + if (model_row != cursor_row) { + /* we need to make the item get focus */ + e_canvas_item_grab_focus (GNOME_CANVAS_ITEM (item), TRUE); + + /* FIXME, currently we only support single row selection */ + atk_selection_clear_selection (selection); + atk_table_add_row_selection (table, row); + } + + e_selection_model_change_cursor (item->selection, + model_row, + model_col); + e_selection_model_cursor_changed (item->selection, + model_row, + model_col); + e_selection_model_cursor_activated (item->selection, + model_row, + model_col); + return TRUE; +} + +static gboolean +selection_clear_selection (AtkSelection *selection) +{ + ETableItem *item; + + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (selection))); + if (!item) + return FALSE; + + e_selection_model_clear (item->selection); + return TRUE; +} + +static AtkObject * +selection_ref_selection (AtkSelection *selection, gint index) +{ + AtkTable *table; + gint row, col; + + table = ATK_TABLE (selection); + row = atk_table_get_row_at_index (table, index); + col = atk_table_get_column_at_index (table, index); + if (!atk_table_is_row_selected (table, row)) + return NULL; + + return eti_ref_at (table, row, col); +} + +static gint +selection_get_selection_count (AtkSelection *selection) +{ + AtkTable *table; + gint n_selected; + + table = ATK_TABLE (selection); + n_selected = atk_table_get_selected_rows (table, NULL); + if (n_selected > 0) + n_selected *= atk_table_get_n_columns (table); + return n_selected; +} + +static gboolean +selection_is_child_selected (AtkSelection *selection, gint i) +{ + gint row; + + row = atk_table_get_row_at_index (ATK_TABLE (selection), i); + return atk_table_is_row_selected (ATK_TABLE (selection), row); +} + +void +gal_a11y_e_table_item_init (void) +{ + if (atk_get_root ()) + atk_registry_set_factory_type (atk_get_default_registry (), + E_TABLE_ITEM_TYPE, + gal_a11y_e_table_item_factory_get_type ()); +} + diff --git a/widgets/table/gal-a11y-e-table-item.h b/widgets/table/gal-a11y-e-table-item.h new file mode 100644 index 0000000000..87773aae48 --- /dev/null +++ b/widgets/table/gal-a11y-e-table-item.h @@ -0,0 +1,58 @@ +/* + * + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TABLE_ITEM_H__ +#define __GAL_A11Y_E_TABLE_ITEM_H__ + +#include <glib-object.h> +#include <table/e-table-item.h> +#include <atk/atkgobjectaccessible.h> + +#define GAL_A11Y_TYPE_E_TABLE_ITEM (gal_a11y_e_table_item_get_type ()) +#define GAL_A11Y_E_TABLE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_ITEM, GalA11yETableItem)) +#define GAL_A11Y_E_TABLE_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_ITEM, GalA11yETableItemClass)) +#define GAL_A11Y_IS_E_TABLE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_ITEM)) +#define GAL_A11Y_IS_E_TABLE_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_ITEM)) + +typedef struct _GalA11yETableItem GalA11yETableItem; +typedef struct _GalA11yETableItemClass GalA11yETableItemClass; +typedef struct _GalA11yETableItemPrivate GalA11yETableItemPrivate; + +/* This struct should actually be larger as this isn't what we derive from. + * The GalA11yETableItemPrivate comes right after the parent class structure. + **/ +struct _GalA11yETableItem { + AtkGObjectAccessible parent; +}; + +struct _GalA11yETableItemClass { + AtkGObjectAccessibleClass parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_table_item_get_type (void); +AtkObject *gal_a11y_e_table_item_new (ETableItem *item); + +void gal_a11y_e_table_item_init (void); + +#endif /* ! __GAL_A11Y_E_TABLE_ITEM_H__ */ diff --git a/widgets/table/gal-a11y-e-table.c b/widgets/table/gal-a11y-e-table.c new file mode 100644 index 0000000000..bf75227af4 --- /dev/null +++ b/widgets/table/gal-a11y-e-table.c @@ -0,0 +1,308 @@ +/* + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include "a11y/gal-a11y-util.h" +#include "table/e-table.h" +#include "table/e-table-click-to-add.h" +#include "table/e-table-group.h" +#include "table/e-table-group-container.h" +#include "table/e-table-group-leaf.h" + +#include "gal-a11y-e-table.h" +#include "gal-a11y-e-table-factory.h" +#include "gal-a11y-e-table-item.h" + +#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yETableClass)) +static AtkObjectClass *parent_class; +static GType parent_type; +static gint priv_offset; +#define GET_PRIVATE(object) ((GalA11yETablePrivate *) (((gchar *) object) + priv_offset)) +#define PARENT_TYPE (parent_type) + +struct _GalA11yETablePrivate { + AtkObject *child_item; +}; + +/* Static functions */ +static ETableItem * +find_first_table_item (ETableGroup *group) +{ + GnomeCanvasGroup *cgroup; + GList *l; + + cgroup = GNOME_CANVAS_GROUP (group); + + for (l = cgroup->item_list; l; l = l->next) { + GnomeCanvasItem *i; + + i = GNOME_CANVAS_ITEM (l->data); + + if (E_IS_TABLE_GROUP (i)) + return find_first_table_item (E_TABLE_GROUP (i)); + else if (E_IS_TABLE_ITEM (i)) { + return E_TABLE_ITEM (i); + } + } + + return NULL; +} + +static AtkObject* +eti_get_accessible (ETableItem *eti, AtkObject *parent) +{ + AtkObject *a11y = NULL; + + g_return_val_if_fail (eti, NULL); + + a11y = atk_gobject_accessible_for_object (G_OBJECT (eti)); + g_return_val_if_fail (a11y, NULL); + + return a11y; +} + +static gboolean +init_child_item (GalA11yETable *a11y) +{ + ETable *table; + + if (!a11y || !GTK_IS_ACCESSIBLE (a11y)) + return FALSE; + + table = E_TABLE (GTK_ACCESSIBLE (a11y)->widget); + if (table && GTK_WIDGET_MAPPED (GTK_WIDGET (table)) && table->group && E_IS_TABLE_GROUP_CONTAINER(table->group)) { + ETableGroupContainer *etgc = (ETableGroupContainer *)table->group; + GList *list; + + for (list = etgc->children; list; list = g_list_next (list)) { + ETableGroupContainerChildNode *child_node = list->data; + ETableGroup *child = child_node->child; + ETableItem *eti = find_first_table_item (child); + + eti_get_accessible (eti, ATK_OBJECT (a11y)); + } + } + g_object_unref (a11y); + g_object_unref (table); + + return FALSE; +} + +static AtkObject* +et_ref_accessible_at_point (AtkComponent *component, + gint x, + gint y, + AtkCoordType coord_type) +{ + GalA11yETable *a11y = GAL_A11Y_E_TABLE (component); + if (GET_PRIVATE (a11y)->child_item) + g_object_ref (GET_PRIVATE (a11y)->child_item); + return GET_PRIVATE (a11y)->child_item; +} + +static gint +et_get_n_children (AtkObject *accessible) +{ + GalA11yETable *a11y = GAL_A11Y_E_TABLE (accessible); + ETable * et; + gint n = 0; + + et = E_TABLE(GTK_ACCESSIBLE (a11y)->widget); + + if (et->group) { + if (E_IS_TABLE_GROUP_LEAF (et->group)) + n = 1; + else if (E_IS_TABLE_GROUP_CONTAINER (et->group)) { + ETableGroupContainer *etgc = (ETableGroupContainer *)et->group; + n = g_list_length (etgc->children); + } + } + + if (et && et->use_click_to_add && et->click_to_add) { + n++; + } + return n; +} + +static AtkObject* +et_ref_child (AtkObject *accessible, + gint i) +{ + GalA11yETable *a11y = GAL_A11Y_E_TABLE (accessible); + ETable * et; + gint child_no; + + et = E_TABLE(GTK_ACCESSIBLE (a11y)->widget); + + child_no = et_get_n_children (accessible); + if (i == 0 || i < child_no - 1) { + if (E_IS_TABLE_GROUP_LEAF (et->group)) { + ETableItem *eti = find_first_table_item (et->group); + AtkObject *aeti = eti_get_accessible (eti, accessible); + if (aeti) + g_object_ref (aeti); + return aeti; + + } else if (E_IS_TABLE_GROUP_CONTAINER (et->group)) { + ETableGroupContainer *etgc = (ETableGroupContainer *) et->group; + ETableGroupContainerChildNode *child_node = g_list_nth_data (etgc->children, i); + if (child_node) { + ETableGroup *child = child_node->child; + ETableItem * eti = find_first_table_item (child); + AtkObject *aeti = eti_get_accessible (eti, accessible); + if (aeti) + g_object_ref (aeti); + return aeti; + } + } + } else if (i == child_no -1) { + ETableClickToAdd * etcta; + + if (et && et->use_click_to_add && et->click_to_add) { + etcta = E_TABLE_CLICK_TO_ADD(et->click_to_add); + accessible = atk_gobject_accessible_for_object (G_OBJECT(etcta)); + if (accessible) + g_object_ref (accessible); + return accessible; + } + } + + return NULL; +} + +static AtkLayer +et_get_layer (AtkComponent *component) +{ + return ATK_LAYER_WIDGET; +} + +static void +et_class_init (GalA11yETableClass *klass) +{ + AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass); + + parent_class = g_type_class_ref (PARENT_TYPE); + + atk_object_class->get_n_children = et_get_n_children; + atk_object_class->ref_child = et_ref_child; +} + +static void +et_atk_component_iface_init (AtkComponentIface *iface) +{ + iface->ref_accessible_at_point = et_ref_accessible_at_point; + iface->get_layer = et_get_layer; +} + +static void +et_init (GalA11yETable *a11y) +{ + GalA11yETablePrivate *priv; + + priv = GET_PRIVATE (a11y); + + priv->child_item = NULL; +} + +/** + * gal_a11y_e_table_get_type: + * @void: + * + * Registers the &GalA11yETable class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yETable class. + **/ +GType +gal_a11y_e_table_get_type (void) +{ + static GType type = 0; + + if (!type) { + AtkObjectFactory *factory; + + GTypeInfo info = { + sizeof (GalA11yETableClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) et_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yETable), + 0, + (GInstanceInitFunc) et_init, + NULL /* value_table */ + }; + + static const GInterfaceInfo atk_component_info = { + (GInterfaceInitFunc) et_atk_component_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + factory = atk_registry_get_factory (atk_get_default_registry (), GTK_TYPE_WIDGET); + parent_type = atk_object_factory_get_accessible_type (factory); + + type = gal_a11y_type_register_static_with_private (PARENT_TYPE, "GalA11yETable", &info, 0, + sizeof (GalA11yETablePrivate), &priv_offset); + g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info); + } + + return type; +} + +AtkObject * +gal_a11y_e_table_new (GObject *widget) +{ + GalA11yETable *a11y; + ETable *table; + + table = E_TABLE (widget); + + a11y = g_object_new (gal_a11y_e_table_get_type (), NULL); + + GTK_ACCESSIBLE (a11y)->widget = GTK_WIDGET (widget); + + /* we need to init all the children for multiple table items */ + if (table && GTK_WIDGET_MAPPED (GTK_WIDGET (table)) && table->group && E_IS_TABLE_GROUP_CONTAINER (table->group)) { + /* Ref it here so that it is still valid in the idle function */ + /* It will be unrefed in the idle function */ + g_object_ref (a11y); + g_object_ref (widget); + + g_idle_add ((GSourceFunc)init_child_item, a11y); + } + + return ATK_OBJECT (a11y); +} + +void +gal_a11y_e_table_init (void) +{ + if (atk_get_root ()) + atk_registry_set_factory_type (atk_get_default_registry (), + E_TABLE_TYPE, + gal_a11y_e_table_factory_get_type ()); + +} + diff --git a/widgets/table/gal-a11y-e-table.h b/widgets/table/gal-a11y-e-table.h new file mode 100644 index 0000000000..ba7c8adc03 --- /dev/null +++ b/widgets/table/gal-a11y-e-table.h @@ -0,0 +1,58 @@ +/* + * + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TABLE_H__ +#define __GAL_A11Y_E_TABLE_H__ + +#include <gtk/gtk.h> +#include <atk/atkobject.h> +#include <atk/atkcomponent.h> + +#define GAL_A11Y_TYPE_E_TABLE (gal_a11y_e_table_get_type ()) +#define GAL_A11Y_E_TABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE, GalA11yETable)) +#define GAL_A11Y_E_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE, GalA11yETableClass)) +#define GAL_A11Y_IS_E_TABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE)) +#define GAL_A11Y_IS_E_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE)) + +typedef struct _GalA11yETable GalA11yETable; +typedef struct _GalA11yETableClass GalA11yETableClass; +typedef struct _GalA11yETablePrivate GalA11yETablePrivate; + +/* This struct should actually be larger as this isn't what we derive from. + * The GalA11yETablePrivate comes right after the parent class structure. + **/ +struct _GalA11yETable { + GtkAccessible object; +}; + +struct _GalA11yETableClass { + GtkAccessibleClass parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_table_get_type (void); +AtkObject *gal_a11y_e_table_new (GObject *table); + +void gal_a11y_e_table_init (void); + +#endif /* ! __GAL_A11Y_E_TABLE_H__ */ diff --git a/widgets/table/gal-a11y-e-tree-factory.c b/widgets/table/gal-a11y-e-tree-factory.c new file mode 100644 index 0000000000..8dc06e2936 --- /dev/null +++ b/widgets/table/gal-a11y-e-tree-factory.c @@ -0,0 +1,98 @@ +/* + * 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: + * Yuedong Du <yuedong.du@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include "gal-a11y-e-tree.h" +#include "gal-a11y-e-tree-factory.h" + +#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETreeFactoryClass)) +static AtkObjectFactoryClass *parent_class; +#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY) + +/* Static functions */ + +static GType +gal_a11y_e_tree_factory_get_accessible_type (void) +{ + return GAL_A11Y_TYPE_E_TREE; +} + +static AtkObject* +gal_a11y_e_tree_factory_create_accessible (GObject *obj) +{ + AtkObject *accessible; + + accessible = gal_a11y_e_tree_new (obj); + + return accessible; +} + +static void +gal_a11y_e_tree_factory_class_init (GalA11yETreeFactoryClass *klass) +{ + AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass); + + parent_class = g_type_class_ref (PARENT_TYPE); + + factory_class->create_accessible = gal_a11y_e_tree_factory_create_accessible; + factory_class->get_accessible_type = gal_a11y_e_tree_factory_get_accessible_type; +} + +static void +gal_a11y_e_tree_factory_init (GalA11yETreeFactory *factory) +{ +} + +/** + * gal_a11y_e_tree_factory_get_type: + * @void: + * + * Registers the &GalA11yETreeFactory class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yETreeFactory class. + **/ +GType +gal_a11y_e_tree_factory_get_type (void) +{ + static GType type = 0; + + if (!type) { + GTypeInfo info = { + sizeof (GalA11yETreeFactoryClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gal_a11y_e_tree_factory_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yETreeFactory), + 0, + (GInstanceInitFunc) gal_a11y_e_tree_factory_init, + NULL /* value_tree */ + }; + + type = g_type_register_static (PARENT_TYPE, "GalA11yETreeFactory", &info, 0); + } + + return type; +} diff --git a/widgets/table/gal-a11y-e-tree-factory.h b/widgets/table/gal-a11y-e-tree-factory.h new file mode 100644 index 0000000000..36b4a61dc2 --- /dev/null +++ b/widgets/table/gal-a11y-e-tree-factory.h @@ -0,0 +1,49 @@ +/* + * 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: + * Yuedong Du <yuedong.du@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TREE_FACTORY_H__ +#define __GAL_A11Y_E_TREE_FACTORY_H__ + +#include <glib-object.h> +#include <atk/atkobjectfactory.h> + +#define GAL_A11Y_TYPE_E_TREE_FACTORY (gal_a11y_e_table_factory_get_type ()) +#define GAL_A11Y_E_TREE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TREE_FACTORY, GalA11yETreeFactory)) +#define GAL_A11Y_E_TREE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TREE_FACTORY, GalA11yETreeFactoryClass)) +#define GAL_A11Y_IS_E_TREE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TREE_FACTORY)) +#define GAL_A11Y_IS_E_TREE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TREE_FACTORY)) + +typedef struct _GalA11yETreeFactory GalA11yETreeFactory; +typedef struct _GalA11yETreeFactoryClass GalA11yETreeFactoryClass; + +struct _GalA11yETreeFactory { + AtkObject object; +}; + +struct _GalA11yETreeFactoryClass { + AtkObjectClass parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_tree_factory_get_type (void); + +#endif /* ! __GAL_A11Y_E_TREE_FACTORY_H__ */ diff --git a/widgets/table/gal-a11y-e-tree.c b/widgets/table/gal-a11y-e-tree.c new file mode 100644 index 0000000000..879b517aab --- /dev/null +++ b/widgets/table/gal-a11y-e-tree.c @@ -0,0 +1,191 @@ +/* + * 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: + * Yuedong Du <yuedong.du@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include "a11y/gal-a11y-util.h" +#include "table/e-table-item.h" +#include "table/e-tree.h" + +#include "gal-a11y-e-table-item.h" +#include "gal-a11y-e-tree.h" +#include "gal-a11y-e-tree-factory.h" + +#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yETreeClass)) +static AtkObjectClass *parent_class; +static GType parent_type; +static gint priv_offset; +#define GET_PRIVATE(object) ((GalA11yETreePrivate *) (((gchar *) object) + priv_offset)) +#define PARENT_TYPE (parent_type) + +struct _GalA11yETreePrivate { + AtkObject *child_item; +}; + +/* Static functions */ + +static void +init_child_item (GalA11yETree *a11y) +{ + GalA11yETreePrivate *priv = GET_PRIVATE (a11y); + ETree *tree = E_TREE (GTK_ACCESSIBLE (a11y)->widget); + ETableItem * eti; + + g_return_if_fail (tree); + eti = e_tree_get_item (tree); + if (priv->child_item == NULL) { + priv->child_item = atk_gobject_accessible_for_object (G_OBJECT (eti)); + } +} + +static AtkObject* +et_ref_accessible_at_point (AtkComponent *component, + gint x, + gint y, + AtkCoordType coord_type) +{ + GalA11yETree *a11y = GAL_A11Y_E_TREE (component); + init_child_item (a11y); + return GET_PRIVATE (a11y)->child_item; +} + +static gint +et_get_n_children (AtkObject *accessible) +{ + return 1; +} + +static AtkObject* +et_ref_child (AtkObject *accessible, + gint i) +{ + GalA11yETree *a11y = GAL_A11Y_E_TREE (accessible); + if (i != 0) + return NULL; + init_child_item (a11y); + g_object_ref (GET_PRIVATE (a11y)->child_item); + return GET_PRIVATE (a11y)->child_item; +} + +static AtkLayer +et_get_layer (AtkComponent *component) +{ + return ATK_LAYER_WIDGET; +} + +static void +et_class_init (GalA11yETreeClass *klass) +{ + AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass); + + parent_class = g_type_class_ref (PARENT_TYPE); + + atk_object_class->get_n_children = et_get_n_children; + atk_object_class->ref_child = et_ref_child; +} + +static void +et_atk_component_iface_init (AtkComponentIface *iface) +{ + iface->ref_accessible_at_point = et_ref_accessible_at_point; + iface->get_layer = et_get_layer; +} + +static void +et_init (GalA11yETree *a11y) +{ + GalA11yETreePrivate *priv; + + priv = GET_PRIVATE (a11y); + + priv->child_item = NULL; +} + +/** + * gal_a11y_e_tree_get_type: + * @void: + * + * Registers the &GalA11yETree class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yETree class. + **/ +GType +gal_a11y_e_tree_get_type (void) +{ + static GType type = 0; + + if (!type) { + AtkObjectFactory *factory; + + GTypeInfo info = { + sizeof (GalA11yETreeClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) et_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yETree), + 0, + (GInstanceInitFunc) et_init, + NULL /* value_tree */ + }; + + static const GInterfaceInfo atk_component_info = { + (GInterfaceInitFunc) et_atk_component_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + factory = atk_registry_get_factory (atk_get_default_registry (), GTK_TYPE_WIDGET); + parent_type = atk_object_factory_get_accessible_type (factory); + + type = gal_a11y_type_register_static_with_private (PARENT_TYPE, "GalA11yETree", &info, 0, + sizeof (GalA11yETreePrivate), &priv_offset); + g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info); + } + + return type; +} + +AtkObject * +gal_a11y_e_tree_new (GObject *widget) +{ + GalA11yETree *a11y; + + a11y = g_object_new (gal_a11y_e_tree_get_type (), NULL); + + GTK_ACCESSIBLE (a11y)->widget = GTK_WIDGET (widget); + + return ATK_OBJECT (a11y); +} + +void +gal_a11y_e_tree_init (void) +{ + if (atk_get_root ()) + atk_registry_set_factory_type (atk_get_default_registry (), + E_TREE_TYPE, + gal_a11y_e_tree_factory_get_type ()); + +} + diff --git a/widgets/table/gal-a11y-e-tree.h b/widgets/table/gal-a11y-e-tree.h new file mode 100644 index 0000000000..ef15dade36 --- /dev/null +++ b/widgets/table/gal-a11y-e-tree.h @@ -0,0 +1,57 @@ +/* + * 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: + * Yuedong Du <yuedong.du@sun.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TREE_H__ +#define __GAL_A11Y_E_TREE_H__ + +#include <gtk/gtk.h> +#include <atk/atkobject.h> +#include <atk/atkcomponent.h> + +#define GAL_A11Y_TYPE_E_TREE (gal_a11y_e_tree_get_type ()) +#define GAL_A11Y_E_TREE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TREE, GalA11yETree)) +#define GAL_A11Y_E_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TREE, GalA11yETreeClass)) +#define GAL_A11Y_IS_E_TREE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TREE)) +#define GAL_A11Y_IS_E_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TREE)) + +typedef struct _GalA11yETree GalA11yETree; +typedef struct _GalA11yETreeClass GalA11yETreeClass; +typedef struct _GalA11yETreePrivate GalA11yETreePrivate; + +/* This struct should actually be larger as this isn't what we derive from. + * The GalA11yETablePrivate comes right after the parent class structure. + **/ +struct _GalA11yETree { + GtkAccessible object; +}; + +struct _GalA11yETreeClass { + GtkAccessibleClass parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_tree_get_type (void); +AtkObject *gal_a11y_e_tree_new (GObject *tree); + +void gal_a11y_e_tree_init (void); + +#endif /* ! __GAL_A11Y_E_TREE_H__ */ diff --git a/widgets/text/Makefile.am b/widgets/text/Makefile.am index ad106158d9..ee426f4791 100644 --- a/widgets/text/Makefile.am +++ b/widgets/text/Makefile.am @@ -15,22 +15,29 @@ privsolib_LTLIBRARIES = libetext.la libetext_la_SOURCES = \ e-text-model-repos.c \ e-text-model.c \ - e-text.c + e-text.c \ + e-reflow.c \ + e-reflow-model.c \ + gal-a11y-e-text-factory.c \ + gal-a11y-e-text.c libetextincludedir = $(privincludedir)/text libetextinclude_HEADERS = \ e-text-model-repos.h \ e-text-model.h \ - e-text.h + e-text.h \ + e-reflow.h \ + e-reflow-model.h \ + gal-a11y-e-text-factory.h \ + gal-a11y-e-text.h libetext_la_LDFLAGS = $(NO_UNDEFINED) libetext_la_LIBADD = \ - $(WIN32_BOOTSTRAP_LIBS) \ - $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/a11y/libevolution-a11y.la \ - $(top_builddir)/widgets/table/libetable.la \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/widgets/misc/libemiscwidgets.la \ $(E_UTIL_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(REGEX_LIBS) diff --git a/widgets/misc/e-reflow-model.c b/widgets/text/e-reflow-model.c index 1eaccdad09..1eaccdad09 100644 --- a/widgets/misc/e-reflow-model.c +++ b/widgets/text/e-reflow-model.c diff --git a/widgets/misc/e-reflow-model.h b/widgets/text/e-reflow-model.h index ebbf3c1f75..ebbf3c1f75 100644 --- a/widgets/misc/e-reflow-model.h +++ b/widgets/text/e-reflow-model.h diff --git a/widgets/misc/e-reflow.c b/widgets/text/e-reflow.c index 794e650ea1..705678bbf8 100644 --- a/widgets/misc/e-reflow.c +++ b/widgets/text/e-reflow.c @@ -30,12 +30,12 @@ #include "text/e-text.h" #include <glib/gi18n.h> #include "e-util/e-util.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" -#include "e-canvas.h" -#include "e-canvas-utils.h" +#include "misc/e-canvas.h" +#include "misc/e-canvas-utils.h" #include "e-reflow.h" -#include "e-selection-model-simple.h" +#include "misc/e-selection-model-simple.h" static gboolean e_reflow_event (GnomeCanvasItem *item, GdkEvent *event); static void e_reflow_realize (GnomeCanvasItem *item); diff --git a/widgets/misc/e-reflow.h b/widgets/text/e-reflow.h index ab27051d40..1559ad6bc0 100644 --- a/widgets/misc/e-reflow.h +++ b/widgets/text/e-reflow.h @@ -24,7 +24,7 @@ #define __E_REFLOW_H__ #include <libgnomecanvas/gnome-canvas.h> -#include <misc/e-reflow-model.h> +#include <text/e-reflow-model.h> #include <misc/e-selection-model.h> #include <e-util/e-sorter-array.h> diff --git a/widgets/text/e-text.c b/widgets/text/e-text.c index 0fb9f926e1..b9c5e0cbe3 100644 --- a/widgets/text/e-text.c +++ b/widgets/text/e-text.c @@ -46,10 +46,10 @@ #include <gtk/gtk.h> #include <libgnomecanvas/gnome-canvas-rect-ellipse.h> -#include "a11y/e-text/gal-a11y-e-text.h" +#include "gal-a11y-e-text.h" #include "misc/e-canvas.h" #include "misc/e-canvas-utils.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include <glib/gi18n.h> #include "e-util/e-text-event-processor-emacs-like.h" #include "e-util/e-util.h" diff --git a/widgets/text/gal-a11y-e-text-factory.c b/widgets/text/gal-a11y-e-text-factory.c new file mode 100644 index 0000000000..2df9241014 --- /dev/null +++ b/widgets/text/gal-a11y-e-text-factory.c @@ -0,0 +1,101 @@ +/* + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> +#include "text/e-text.h" +#include "gal-a11y-e-text-factory.h" +#include "gal-a11y-e-text.h" + +#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETextFactoryClass)) +static AtkObjectFactoryClass *parent_class; +#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY) + +/* Static functions */ + +static GType +gal_a11y_e_text_factory_get_accessible_type (void) +{ + return GAL_A11Y_TYPE_E_TEXT; +} + +static AtkObject* +gal_a11y_e_text_factory_create_accessible (GObject *obj) +{ + AtkObject *atk_object; + + g_return_val_if_fail (E_IS_TEXT (obj), NULL); + + atk_object = g_object_new (GAL_A11Y_TYPE_E_TEXT, NULL); + atk_object_initialize (atk_object, obj); + + return atk_object; +} + +static void +gal_a11y_e_text_factory_class_init (GalA11yETextFactoryClass *klass) +{ + AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass); + + parent_class = g_type_class_ref (PARENT_TYPE); + + factory_class->create_accessible = gal_a11y_e_text_factory_create_accessible; + factory_class->get_accessible_type = gal_a11y_e_text_factory_get_accessible_type; +} + +static void +gal_a11y_e_text_factory_init (GalA11yETextFactory *factory) +{ +} + +/** + * gal_a11y_e_text_factory_get_type: + * @void: + * + * Registers the &GalA11yETextFactory class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yETextFactory class. + **/ +GType +gal_a11y_e_text_factory_get_type (void) +{ + static GType type = 0; + + if (!type) { + GTypeInfo info = { + sizeof (GalA11yETextFactoryClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gal_a11y_e_text_factory_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yETextFactory), + 0, + (GInstanceInitFunc) gal_a11y_e_text_factory_init, + NULL /* value_text */ + }; + + type = g_type_register_static (PARENT_TYPE, "GalA11yETextFactory", &info, 0); + } + + return type; +} diff --git a/widgets/text/gal-a11y-e-text-factory.h b/widgets/text/gal-a11y-e-text-factory.h new file mode 100644 index 0000000000..7e7f8e9f1a --- /dev/null +++ b/widgets/text/gal-a11y-e-text-factory.h @@ -0,0 +1,49 @@ +/* + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TEXT_FACTORY_H__ +#define __GAL_A11Y_E_TEXT_FACTORY_H__ + +#include <glib-object.h> +#include <atk/atkobjectfactory.h> + +#define GAL_A11Y_TYPE_E_TEXT_FACTORY (gal_a11y_e_text_factory_get_type ()) +#define GAL_A11Y_E_TEXT_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TEXT_FACTORY, GalA11yETextFactory)) +#define GAL_A11Y_E_TEXT_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TEXT_FACTORY, GalA11yETextFactoryClass)) +#define GAL_A11Y_IS_E_TEXT_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TEXT_FACTORY)) +#define GAL_A11Y_IS_E_TEXT_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TEXT_FACTORY)) + +typedef struct _GalA11yETextFactory GalA11yETextFactory; +typedef struct _GalA11yETextFactoryClass GalA11yETextFactoryClass; + +struct _GalA11yETextFactory { + AtkObjectFactory object; +}; + +struct _GalA11yETextFactoryClass { + AtkObjectFactoryClass parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_text_factory_get_type (void); + +#endif /* ! __GAL_A11Y_E_TEXT_FACTORY_H__ */ diff --git a/widgets/text/gal-a11y-e-text.c b/widgets/text/gal-a11y-e-text.c new file mode 100644 index 0000000000..113c503da9 --- /dev/null +++ b/widgets/text/gal-a11y-e-text.c @@ -0,0 +1,1122 @@ +/* + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include <string.h> + +#include <gtk/gtk.h> + +#include "a11y/gal-a11y-util.h" +#include "text/e-text.h" +#include "text/e-text-model-repos.h" + +#include "gal-a11y-e-text.h" +#include "gal-a11y-e-text-factory.h" + +#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yETextClass)) +static GObjectClass *parent_class; +static AtkComponentIface *component_parent_iface; +static GType parent_type; +static gint priv_offset; +static GQuark quark_accessible_object = 0; +#define GET_PRIVATE(object) ((GalA11yETextPrivate *) (((gchar *) object) + priv_offset)) +#define PARENT_TYPE (parent_type) + +struct _GalA11yETextPrivate { + gint dummy; +}; + +static void +et_dispose (GObject *object) +{ + if (parent_class->dispose) + parent_class->dispose (object); +} + +/* Static functions */ + +static void +et_get_extents (AtkComponent *component, + gint *x, + gint *y, + gint *width, + gint *height, + AtkCoordType coord_type) +{ + EText *item = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (component))); + double real_width; + double real_height; + gint fake_width; + gint fake_height; + + if (component_parent_iface && + component_parent_iface->get_extents) + component_parent_iface->get_extents (component, + x, + y, + &fake_width, + &fake_height, + coord_type); + + g_object_get (item, + "text_width", &real_width, + "text_height", &real_height, + NULL); + + if (width) + *width = real_width; + if (height) + *height = real_height; +} + +static const gchar * +et_get_full_text (AtkText *text) +{ + EText *etext = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text))); + ETextModel *model; + const gchar *full_text; + + g_object_get (etext, "model", &model, NULL); + + full_text = e_text_model_get_text (model); + + return full_text; +} + +static void +et_set_full_text (AtkEditableText *text, + const gchar *full_text) +{ + EText *etext = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text))); + ETextModel *model; + + g_object_get (etext, "model", &model, NULL); + + e_text_model_set_text (model, full_text); +} + +static gchar * +et_get_text (AtkText *text, + gint start_offset, + gint end_offset) +{ + gint start, end, real_start, real_end, len; + const gchar *full_text = et_get_full_text (text); + if (full_text == NULL) + return NULL; + len = g_utf8_strlen (full_text, -1); + + start = MIN (MAX (0, start_offset), len); + end = MIN (MAX (-1, end_offset), len); + + if (end_offset == -1) + end = strlen (full_text); + else + end = g_utf8_offset_to_pointer (full_text, end) - full_text; + + start = g_utf8_offset_to_pointer (full_text, start) - full_text; + + real_start = MIN (start, end); + real_end = MAX (start, end); + + return g_strndup (full_text + real_start, real_end - real_start); +} + +static gboolean +is_a_seperator (gunichar c) +{ + return g_unichar_ispunct(c) || g_unichar_isspace(c); +} + +static gint +find_word_start (const gchar *text, + gint begin_offset, + gint step) +{ + gint offset; + gchar *at_offset; + gunichar current, previous; + gint len; + + offset = begin_offset; + len = g_utf8_strlen (text, -1); + + while (offset > 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset); + current = g_utf8_get_char_validated (at_offset, -1); + at_offset = g_utf8_offset_to_pointer (text, offset-1); + previous = g_utf8_get_char_validated (at_offset, -1); + if ((! is_a_seperator (current)) && is_a_seperator (previous)) + break; + offset += step; + } + + return offset; +} + +static gint +find_word_end (const gchar *text, + gint begin_offset, + gint step) +{ + gint offset; + gchar *at_offset; + gunichar current, previous; + gint len; + + offset = begin_offset; + len = g_utf8_strlen (text, -1); + + while (offset > 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset); + current = g_utf8_get_char_validated (at_offset, -1); + at_offset = g_utf8_offset_to_pointer (text, offset-1); + previous = g_utf8_get_char_validated (at_offset, -1); + if (is_a_seperator (current) && (! is_a_seperator (previous))) + break; + offset += step; + } + + return offset; +} + +static gint +find_sentence_start (const gchar *text, + gint begin_offset, + gint step) +{ + gint offset, last_word_end, len; + gchar *at_offset; + gunichar ch; + gint i; + + offset = find_word_start (text, begin_offset, step); + len = g_utf8_strlen (text, -1); + + while (offset>0 && offset <len) { + last_word_end = find_word_end (text, offset - 1, -1); + if (last_word_end == 0) + break; + for (i = last_word_end; i < offset; i++) { + at_offset = g_utf8_offset_to_pointer (text, i); + ch = g_utf8_get_char_validated (at_offset, -1); + if (ch == '.' || ch == '!' || ch == '?') + return offset; + } + + offset = find_word_start (text, offset + step, step); + } + + return offset; +} + +static gint +find_sentence_end (const gchar *text, + gint begin_offset, + gint step) +{ + gint offset; + gchar *at_offset; + gunichar previous; + gint len; + + offset = begin_offset; + len = g_utf8_strlen (text, -1); + + while (offset > 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset - 1); + previous = g_utf8_get_char_validated (at_offset, -1); + if (previous == '.' || previous == '!' || previous == '?') + break; + offset += step; + } + + return offset; +} + +static gint +find_line_start (const gchar *text, + gint begin_offset, + gint step) +{ + gint offset; + gchar *at_offset; + gunichar previous; + gint len; + + offset = begin_offset; + len = g_utf8_strlen (text, -1); + + while (offset > 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset - 1); + previous = g_utf8_get_char_validated (at_offset, -1); + if (previous == '\n' || previous == '\r') + break; + offset += step; + } + + return offset; +} + +static gint +find_line_end (const gchar *text, + gint begin_offset, + gint step) +{ + gint offset; + gchar *at_offset; + gunichar current; + gint len; + + offset = begin_offset; + len = g_utf8_strlen (text, -1); + + while (offset >= 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset); + current = g_utf8_get_char_validated (at_offset, -1); + if (current == '\n' || current == '\r') + break; + offset += step; + } + + return offset; +} + +static gchar * +et_get_text_after_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + gint start, end, len; + const gchar *full_text = et_get_full_text (text); + g_return_val_if_fail (full_text, NULL); + + switch (boundary_type) + { + case ATK_TEXT_BOUNDARY_CHAR: + start = offset + 1; + end = offset + 2; + break; + case ATK_TEXT_BOUNDARY_WORD_START: + start = find_word_start (full_text, offset + 1, 1); + end = find_word_start (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_WORD_END: + start = find_word_end (full_text, offset + 1, 1); + end = find_word_end (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_START: + start = find_sentence_start (full_text, offset + 1, 1); + end = find_sentence_start (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_END: + start = find_sentence_end (full_text, offset + 1, 1); + end = find_sentence_end (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_LINE_START: + start = find_line_start (full_text, offset + 1, 1); + end = find_line_start (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_LINE_END: + start = find_line_end (full_text, offset + 1, 1); + end = find_line_end (full_text, start + 1, 1); + break; + default: + return NULL; + } + + len = g_utf8_strlen (full_text, -1); + if (start_offset) + *start_offset = MIN (MAX (0, start), len); + if (end_offset) + *end_offset = MIN (MAX (0, end), len); + return et_get_text (text, start, end); +} + +static gchar * +et_get_text_at_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + gint start, end, len; + const gchar *full_text = et_get_full_text (text); + g_return_val_if_fail (full_text, NULL); + + switch (boundary_type) + { + case ATK_TEXT_BOUNDARY_CHAR: + start = offset; + end = offset + 1; + break; + case ATK_TEXT_BOUNDARY_WORD_START: + start = find_word_start (full_text, offset - 1, -1); + end = find_word_start (full_text, offset, 1); + break; + case ATK_TEXT_BOUNDARY_WORD_END: + start = find_word_end (full_text, offset, -1); + end = find_word_end (full_text, offset + 1, 1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_START: + start = find_sentence_start (full_text, offset - 1, -1); + end = find_sentence_start (full_text, offset, 1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_END: + start = find_sentence_end (full_text, offset, -1); + end = find_sentence_end (full_text, offset + 1, 1); + break; + case ATK_TEXT_BOUNDARY_LINE_START: + start = find_line_start (full_text, offset - 1, -1); + end = find_line_start (full_text, offset, 1); + break; + case ATK_TEXT_BOUNDARY_LINE_END: + start = find_line_end (full_text, offset, -1); + end = find_line_end (full_text, offset + 1, 1); + break; + default: + return NULL; + } + + len = g_utf8_strlen (full_text, -1); + if (start_offset) + *start_offset = MIN (MAX (0, start), len); + if (end_offset) + *end_offset = MIN (MAX (0, end), len); + return et_get_text (text, start, end); +} + +static gunichar +et_get_character_at_offset (AtkText *text, + gint offset) +{ + const gchar *full_text = et_get_full_text (text); + gchar *at_offset; + + at_offset = g_utf8_offset_to_pointer (full_text, offset); + return g_utf8_get_char_validated (at_offset, -1); +} + +static gchar * +et_get_text_before_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + gint start, end, len; + const gchar *full_text = et_get_full_text (text); + g_return_val_if_fail (full_text, NULL); + + switch (boundary_type) + { + case ATK_TEXT_BOUNDARY_CHAR: + start = offset - 1; + end = offset; + break; + case ATK_TEXT_BOUNDARY_WORD_START: + end = find_word_start (full_text, offset - 1, -1); + start = find_word_start (full_text, end - 1, -1); + break; + case ATK_TEXT_BOUNDARY_WORD_END: + end = find_word_end (full_text, offset, -1); + start = find_word_end (full_text, end - 1, -1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_START: + end = find_sentence_start (full_text, offset, -1); + start = find_sentence_start (full_text, end - 1, -1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_END: + end = find_sentence_end (full_text, offset, -1); + start = find_sentence_end (full_text, end - 1, -1); + break; + case ATK_TEXT_BOUNDARY_LINE_START: + end = find_line_start (full_text, offset, -1); + start = find_line_start (full_text, end - 1, -1); + break; + case ATK_TEXT_BOUNDARY_LINE_END: + end = find_line_end (full_text, offset, -1); + start = find_line_end (full_text, end - 1, -1); + break; + default: + return NULL; + } + + len = g_utf8_strlen (full_text, -1); + if (start_offset) + *start_offset = MIN (MAX (0, start), len); + if (end_offset) + *end_offset = MIN (MAX (0, end), len); + return et_get_text (text, start, end); +} + +static gint +et_get_caret_offset (AtkText *text) +{ + GObject *obj; + EText *etext; + gint offset; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE(text), -1); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return -1; + + g_return_val_if_fail (E_IS_TEXT (obj), -1); + etext = E_TEXT (obj); + + g_object_get (etext, "cursor_pos", &offset, NULL); + return offset; +} + +static AtkAttributeSet* +et_get_run_attributes (AtkText *text, + gint offset, + gint *start_offset, + gint *end_offset) +{ + /* Unimplemented */ + return NULL; +} + +static AtkAttributeSet* +et_get_default_attributes (AtkText *text) +{ + /* Unimplemented */ + return NULL; +} + +static void +et_get_character_extents (AtkText *text, + gint offset, + gint *x, + gint *y, + gint *width, + gint *height, + AtkCoordType coords) +{ + GObject *obj; + EText *etext; + GnomeCanvas *canvas; + gint x_widget, y_widget, x_window, y_window; + GdkWindow *window; + GtkWidget *widget; + PangoRectangle pango_pos; + + g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE(text)); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return; + g_return_if_fail (E_IS_TEXT (obj)); + etext = E_TEXT(obj); + canvas = GNOME_CANVAS_ITEM(etext)->canvas; + widget = GTK_WIDGET(canvas); + window = widget->window; + gdk_window_get_origin (window, &x_widget, &y_widget); + + pango_layout_index_to_pos (etext->layout, offset, &pango_pos); + pango_pos.x = PANGO_PIXELS (pango_pos.x); + pango_pos.y = PANGO_PIXELS (pango_pos.y); + pango_pos.width = (pango_pos.width + PANGO_SCALE / 2) / PANGO_SCALE; + pango_pos.height = (pango_pos.height + PANGO_SCALE / 2) / PANGO_SCALE; + + *x = pango_pos.x + x_widget; + *y = pango_pos.y + y_widget; + + *width = pango_pos.width; + *height = pango_pos.height; + + if (etext->draw_borders) { + *x += 3; /*BORDER_INDENT;*/ + *y += 3; /*BORDER_INDENT;*/ + } + + *x += etext->xofs; + *y += etext->yofs; + + if (etext->editing) { + *x -= etext->xofs_edit; + *y -= etext->yofs_edit; + } + + *x += etext->cx; + *y += etext->cy; + + if (coords == ATK_XY_WINDOW) { + window = gdk_window_get_toplevel (window); + gdk_window_get_origin (window, &x_window, &y_window); + *x -= x_window; + *y -= y_window; + } + else if (coords == ATK_XY_SCREEN) { + } + else { + *x = 0; + *y = 0; + *height = 0; + *width = 0; + } +} + +static gint +et_get_character_count (AtkText *text) +{ + const gchar *full_text = et_get_full_text (text); + + return g_utf8_strlen (full_text, -1); +} + +static gint +et_get_offset_at_point (AtkText *text, + gint x, + gint y, + AtkCoordType coords) +{ + GObject *obj; + EText *etext; + GnomeCanvas *canvas; + gint x_widget, y_widget, x_window, y_window; + GdkWindow *window; + GtkWidget *widget; + gint index; + gint trailing; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE(text), -1); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return -1; + g_return_val_if_fail (E_IS_TEXT (obj), -1); + etext = E_TEXT(obj); + canvas = GNOME_CANVAS_ITEM(etext)->canvas; + widget = GTK_WIDGET(canvas); + window = widget->window; + gdk_window_get_origin (window, &x_widget, &y_widget); + + if (coords == ATK_XY_SCREEN) { + x = x - x_widget; + y = y - y_widget; + } + else if (coords == ATK_XY_WINDOW) { + window = gdk_window_get_toplevel (window); + gdk_window_get_origin (window, &x_window, &y_window); + x = x - x_widget + x_window; + y = y - y_widget + y_window; + } + else + return -1; + + if (etext->draw_borders) { + x -= 3; /*BORDER_INDENT;*/ + y -= 3; /*BORDER_INDENT;*/ + } + + x -= etext->xofs; + y -= etext->yofs; + + if (etext->editing) { + x += etext->xofs_edit; + y += etext->yofs_edit; + } + + x -= etext->cx; + y -= etext->cy; + + pango_layout_xy_to_index (etext->layout, + x * PANGO_SCALE - PANGO_SCALE / 2, + y * PANGO_SCALE - PANGO_SCALE / 2, + &index, + &trailing); + + return g_utf8_pointer_to_offset (etext->text, etext->text + index + trailing); +} + +static gint +et_get_n_selections (AtkText *text) +{ + EText *etext = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text))); + if (etext->selection_start != + etext->selection_end) + return 1; + return 0; +} + +static gchar * +et_get_selection (AtkText *text, + gint selection_num, + gint *start_offset, + gint *end_offset) +{ + gint start, end, real_start, real_end, len; + EText *etext; + if (selection_num == 0) { + const gchar *full_text = et_get_full_text (text); + if (full_text == NULL) + return NULL; + len = g_utf8_strlen (full_text, -1); + etext = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text))); + start = MIN (etext->selection_start, etext->selection_end); + end = MAX (etext->selection_start, etext->selection_end); + start = MIN (MAX (0, start), len); + end = MIN (MAX (0, end), len); + if (start != end) { + if (start_offset) + *start_offset = start; + if (end_offset) + *end_offset = end; + real_start = g_utf8_offset_to_pointer (full_text, start) - full_text; + real_end = g_utf8_offset_to_pointer (full_text, end) - full_text; + return g_strndup (full_text + real_start, real_end - real_start); + } + } + + return NULL; +} + +static gboolean +et_add_selection (AtkText *text, + gint start_offset, + gint end_offset) +{ + GObject *obj; + EText *etext; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return FALSE; + g_return_val_if_fail (E_IS_TEXT (obj), FALSE); + etext = E_TEXT (obj); + + g_return_val_if_fail (start_offset >= 0, FALSE); + g_return_val_if_fail (start_offset >= -1, FALSE); + if (end_offset == -1) + end_offset = et_get_character_count (text); + + if (start_offset != end_offset) { + gint real_start, real_end; + real_start = MIN (start_offset, end_offset); + real_end = MAX (start_offset, end_offset); + etext->selection_start = real_start; + etext->selection_end = real_end; + + gnome_canvas_item_grab_focus (GNOME_CANVAS_ITEM (etext)); + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (etext)); + + g_signal_emit_by_name (ATK_OBJECT (text), "text_selection_changed"); + + return TRUE; + } + + return FALSE; +} + +static gboolean +et_remove_selection (AtkText *text, + gint selection_num) +{ + GObject *obj; + EText *etext; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return FALSE; + g_return_val_if_fail (E_IS_TEXT (obj), FALSE); + etext = E_TEXT (obj); + + if (selection_num == 0 + && etext->selection_start != etext->selection_end) { + etext->selection_end = etext->selection_start; + g_signal_emit_by_name (ATK_OBJECT(text), "text_selection_changed"); + return TRUE; + } + + return FALSE; +} + +static gboolean +et_set_selection (AtkText *text, + gint selection_num, + gint start_offset, + gint end_offset) +{ + GObject *obj; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return FALSE; + g_return_val_if_fail (E_IS_TEXT (obj), FALSE); + if (selection_num == 0) + return et_add_selection (text, start_offset, end_offset); + return FALSE; +} + +static gboolean +et_set_caret_offset (AtkText *text, + gint offset) +{ + GObject *obj; + EText *etext; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return FALSE; + + g_return_val_if_fail (E_IS_TEXT (obj), FALSE); + etext = E_TEXT (obj); + + if (offset < -1) + return FALSE; + else { + ETextEventProcessorCommand command; + + if (offset == -1) + offset = et_get_character_count (text); + + command.action = E_TEP_MOVE; + command.position = E_TEP_VALUE; + command.value = offset; + command.time = GDK_CURRENT_TIME; + g_signal_emit_by_name (etext->tep, "command", &command); + return TRUE; + } +} + +static gboolean +et_set_run_attributes (AtkEditableText *text, + AtkAttributeSet *attrib_set, + gint start_offset, + gint end_offset) +{ + /* Unimplemented */ + return FALSE; +} + +static void +et_set_text_contents (AtkEditableText *text, + const gchar *string) +{ + et_set_full_text (text, string); +} + +static void +et_insert_text (AtkEditableText *text, + const gchar *string, + gint length, + gint *position) +{ + /* Utf8 unimplemented */ + gchar *result; + + const gchar *full_text = et_get_full_text (ATK_TEXT (text)); + if (full_text == NULL) + return; + + result = g_strdup_printf ("%.*s%.*s%s", *position, full_text, length, string, full_text + *position); + + et_set_full_text (text, result); + + *position += length; + + g_free (result); +} + +static void +et_copy_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + GObject *obj; + EText *etext; + + g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text)); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return; + + g_return_if_fail (E_IS_TEXT (obj)); + etext = E_TEXT (obj); + + if (start_pos != end_pos) { + etext->selection_start = start_pos; + etext->selection_end = end_pos; + e_text_copy_clipboard (etext); + } +} + +static void +et_delete_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + GObject *obj; + EText *etext; + + g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE(text)); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return; + + g_return_if_fail (E_IS_TEXT (obj)); + etext = E_TEXT (obj); + + etext->selection_start = start_pos; + etext->selection_end = end_pos; + + e_text_delete_selection (etext); +} + +static void +et_cut_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + et_copy_text (text, start_pos, end_pos); + et_delete_text (text, start_pos, end_pos); +} + +static void +et_paste_text (AtkEditableText *text, + gint position) +{ + GObject *obj; + EText *etext; + + g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text)); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return; + + g_return_if_fail (E_IS_TEXT (obj)); + etext = E_TEXT (obj); + + g_object_set (etext, "cursor_pos", position, NULL); + e_text_paste_clipboard (etext); +} + +static void +et_atk_component_iface_init (AtkComponentIface *iface) +{ + iface->get_extents = et_get_extents; +} + +static void +et_atk_text_iface_init (AtkTextIface *iface) +{ + iface->get_text = et_get_text; + iface->get_text_after_offset = et_get_text_after_offset; + iface->get_text_at_offset = et_get_text_at_offset; + iface->get_character_at_offset = et_get_character_at_offset; + iface->get_text_before_offset = et_get_text_before_offset; + iface->get_caret_offset = et_get_caret_offset; + iface->get_run_attributes = et_get_run_attributes; + iface->get_default_attributes = et_get_default_attributes; + iface->get_character_extents = et_get_character_extents; + iface->get_character_count = et_get_character_count; + iface->get_offset_at_point = et_get_offset_at_point; + iface->get_n_selections = et_get_n_selections; + iface->get_selection = et_get_selection; + iface->add_selection = et_add_selection; + iface->remove_selection = et_remove_selection; + iface->set_selection = et_set_selection; + iface->set_caret_offset = et_set_caret_offset; +} + +static void +et_atk_editable_text_iface_init (AtkEditableTextIface *iface) +{ + iface->set_run_attributes = et_set_run_attributes; + iface->set_text_contents = et_set_text_contents; + iface->insert_text = et_insert_text; + iface->copy_text = et_copy_text; + iface->cut_text = et_cut_text; + iface->delete_text = et_delete_text; + iface->paste_text = et_paste_text; +} + +static void +_et_reposition_cb (ETextModel *model, + ETextModelReposFn fn, + gpointer repos_data, + gpointer user_data) +{ + AtkObject *accessible; + AtkText *text; + + accessible = ATK_OBJECT (user_data); + text = ATK_TEXT (accessible); + + if (fn == e_repos_delete_shift) { + EReposDeleteShift *info = (EReposDeleteShift *) repos_data; + g_signal_emit_by_name (text, "text-changed::delete", info->pos, info->len); + } + else if (fn == e_repos_insert_shift) { + EReposInsertShift *info = (EReposInsertShift *) repos_data; + g_signal_emit_by_name (text, "text-changed::insert", info->pos, info->len); + } +} + +static void +_et_command_cb (ETextEventProcessor *tep, + ETextEventProcessorCommand *command, + gpointer user_data) +{ + AtkObject *accessible; + AtkText *text; + + accessible = ATK_OBJECT (user_data); + text = ATK_TEXT (accessible); + + switch (command->action) { + case E_TEP_MOVE: + g_signal_emit_by_name (text, "text-caret-moved", et_get_caret_offset (text)); + break; + case E_TEP_SELECT: + g_signal_emit_by_name (text, "text-selection-changed"); + break; + default: + break; + } +} + +static void +et_real_initialize (AtkObject *obj, + gpointer data) +{ + EText *etext; + + ATK_OBJECT_CLASS (parent_class)->initialize (obj, data); + + g_return_if_fail (GAL_A11Y_IS_E_TEXT (obj)); + g_return_if_fail (E_IS_TEXT (data)); + + etext = E_TEXT (data); + + /* Set up signal callbacks */ + g_signal_connect (etext->model, "reposition", + G_CALLBACK (_et_reposition_cb), obj); + + if (etext->tep) + g_signal_connect_after (etext->tep, "command", + (GCallback) _et_command_cb, obj); + + obj->role = ATK_ROLE_TEXT; +} + +static void +et_class_init (GalA11yETextClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass); + + quark_accessible_object = g_quark_from_static_string ("gtk-accessible-object"); + parent_class = g_type_class_ref (PARENT_TYPE); + component_parent_iface = g_type_interface_peek(parent_class, ATK_TYPE_COMPONENT); + object_class->dispose = et_dispose; + atk_class->initialize = et_real_initialize; +} + +static void +et_init (GalA11yEText *a11y) +{ +#if 0 + GalA11yETextPrivate *priv; + + priv = GET_PRIVATE (a11y); +#endif +} + +/** + * gal_a11y_e_text_get_type: + * @void: + * + * Registers the &GalA11yEText class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yEText class. + **/ +GType +gal_a11y_e_text_get_type (void) +{ + static GType type = 0; + + if (!type) { + AtkObjectFactory *factory; + + GTypeInfo info = { + sizeof (GalA11yETextClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) et_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yEText), + 0, + (GInstanceInitFunc) et_init, + NULL /* value_text */ + }; + + static const GInterfaceInfo atk_component_info = { + (GInterfaceInitFunc) et_atk_component_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + static const GInterfaceInfo atk_text_info = { + (GInterfaceInitFunc) et_atk_text_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + static const GInterfaceInfo atk_editable_text_info = { + (GInterfaceInitFunc) et_atk_editable_text_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + factory = atk_registry_get_factory (atk_get_default_registry (), GNOME_TYPE_CANVAS_ITEM); + parent_type = atk_object_factory_get_accessible_type (factory); + + type = gal_a11y_type_register_static_with_private (PARENT_TYPE, "GalA11yEText", &info, 0, + sizeof (GalA11yETextPrivate), &priv_offset); + + g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info); + g_type_add_interface_static (type, ATK_TYPE_TEXT, &atk_text_info); + g_type_add_interface_static (type, ATK_TYPE_EDITABLE_TEXT, &atk_editable_text_info); + } + + return type; +} + +void +gal_a11y_e_text_init (void) +{ + if (atk_get_root ()) + atk_registry_set_factory_type (atk_get_default_registry (), + E_TYPE_TEXT, + gal_a11y_e_text_factory_get_type ()); + +} + diff --git a/widgets/text/gal-a11y-e-text.h b/widgets/text/gal-a11y-e-text.h new file mode 100644 index 0000000000..ff55bdadc7 --- /dev/null +++ b/widgets/text/gal-a11y-e-text.h @@ -0,0 +1,56 @@ +/* + * + * 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: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TEXT_H__ +#define __GAL_A11Y_E_TEXT_H__ + +#include <glib-object.h> +#include <table/e-table-item.h> + +#define GAL_A11Y_TYPE_E_TEXT (gal_a11y_e_text_get_type ()) +#define GAL_A11Y_E_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TEXT, GalA11yEText)) +#define GAL_A11Y_E_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TEXT, GalA11yETextClass)) +#define GAL_A11Y_IS_E_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TEXT)) +#define GAL_A11Y_IS_E_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TEXT)) + +typedef struct _GalA11yEText GalA11yEText; +typedef struct _GalA11yETextClass GalA11yETextClass; +typedef struct _GalA11yETextPrivate GalA11yETextPrivate; + +/* This struct should actually be larger as this isn't what we derive from. + * The GalA11yETextPrivate comes right after the parent class structure. + **/ +struct _GalA11yEText { + AtkObject object; +}; + +struct _GalA11yETextClass { + AtkObject parent_class; +}; + +/* Standard Glib function */ +GType gal_a11y_e_text_get_type (void); + +void gal_a11y_e_text_init (void); + +#endif /* ! __GAL_A11Y_E_TEXT_H__ */ |