diff options
-rw-r--r-- | addressbook/gui/widgets/e-addressbook-view.c | 90 | ||||
-rw-r--r-- | addressbook/gui/widgets/e-addressbook-view.h | 4 | ||||
-rw-r--r-- | calendar/gui/e-calendar-view.c | 90 | ||||
-rw-r--r-- | calendar/gui/e-calendar-view.h | 4 | ||||
-rw-r--r-- | calendar/gui/e-memo-table.c | 78 | ||||
-rw-r--r-- | calendar/gui/e-memo-table.h | 4 | ||||
-rw-r--r-- | calendar/gui/e-task-table.c | 84 | ||||
-rw-r--r-- | calendar/gui/e-task-table.h | 8 | ||||
-rw-r--r-- | composer/e-composer-private.c | 42 | ||||
-rw-r--r-- | composer/e-composer-private.h | 5 | ||||
-rw-r--r-- | composer/e-msg-composer.c | 134 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | mail/message-list.c | 64 | ||||
-rw-r--r-- | mail/message-list.h | 4 | ||||
-rw-r--r-- | widgets/misc/e-focus-tracker.c | 14 | ||||
-rw-r--r-- | widgets/misc/e-selectable.c | 58 | ||||
-rw-r--r-- | widgets/misc/e-selectable.h | 4 | ||||
-rw-r--r-- | widgets/misc/e-web-view.c | 243 | ||||
-rw-r--r-- | widgets/misc/e-web-view.h | 10 |
19 files changed, 823 insertions, 119 deletions
diff --git a/addressbook/gui/widgets/e-addressbook-view.c b/addressbook/gui/widgets/e-addressbook-view.c index cc540c14c3..48058ad415 100644 --- a/addressbook/gui/widgets/e-addressbook-view.c +++ b/addressbook/gui/widgets/e-addressbook-view.c @@ -36,6 +36,7 @@ #include "addressbook/printing/e-contact-print.h" #include "ea-addressbook.h" +#include "e-util/e-binding.h" #include "e-util/e-print.h" #include "e-util/e-selection.h" #include "e-util/e-util.h" @@ -90,11 +91,16 @@ struct _EAddressbookViewPrivate { gchar *search_text; gint search_id; EFilterRule *advanced_search; + + GtkTargetList *copy_target_list; + GtkTargetList *paste_target_list; }; enum { PROP_0, + PROP_COPY_TARGET_LIST, PROP_MODEL, + PROP_PASTE_TARGET_LIST, PROP_SHELL_VIEW, PROP_SOURCE }; @@ -437,21 +443,38 @@ addressbook_view_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { + case PROP_COPY_TARGET_LIST: + g_value_set_boxed ( + value, + e_addressbook_view_get_copy_target_list ( + E_ADDRESSBOOK_VIEW (object))); + return; + case PROP_MODEL: g_value_set_object ( - value, e_addressbook_view_get_model ( + value, + e_addressbook_view_get_model ( + E_ADDRESSBOOK_VIEW (object))); + return; + + case PROP_PASTE_TARGET_LIST: + g_value_set_boxed ( + value, + e_addressbook_view_get_paste_target_list ( E_ADDRESSBOOK_VIEW (object))); return; case PROP_SHELL_VIEW: g_value_set_object ( - value, e_addressbook_view_get_shell_view ( + value, + e_addressbook_view_get_shell_view ( E_ADDRESSBOOK_VIEW (object))); return; case PROP_SOURCE: g_value_set_object ( - value, e_addressbook_view_get_source ( + value, + e_addressbook_view_get_source ( E_ADDRESSBOOK_VIEW (object))); return; } @@ -511,6 +534,16 @@ addressbook_view_dispose (GObject *object) priv->advanced_search = NULL; } + if (priv->copy_target_list != NULL) { + gtk_target_list_unref (priv->copy_target_list); + priv->copy_target_list = NULL; + } + + if (priv->paste_target_list != NULL) { + gtk_target_list_unref (priv->paste_target_list); + priv->paste_target_list = NULL; + } + /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -548,12 +581,14 @@ addressbook_view_update_actions (ESelectable *selectable, EAddressbookModel *model; ESelectionModel *selection_model; GtkAction *action; - gboolean clipboard_has_directory; + GtkTargetList *target_list; + gboolean can_paste = FALSE; gboolean source_is_editable; gboolean sensitive; const gchar *tooltip; gint n_contacts; gint n_selected; + gint ii; view = E_ADDRESSBOOK_VIEW (selectable); model = e_addressbook_view_get_model (view); @@ -565,9 +600,10 @@ addressbook_view_update_actions (ESelectable *selectable, n_selected = (selection_model != NULL) ? e_selection_model_selected_count (selection_model) : 0; - clipboard_has_directory = (clipboard_targets != NULL) && - e_targets_include_directory ( - clipboard_targets, n_clipboard_targets); + target_list = e_selectable_get_paste_target_list (selectable); + for (ii = 0; ii < n_clipboard_targets && !can_paste; ii++) + can_paste = gtk_target_list_find ( + target_list, clipboard_targets[ii], NULL); action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); sensitive = source_is_editable && (n_selected > 0); @@ -582,7 +618,7 @@ addressbook_view_update_actions (ESelectable *selectable, gtk_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); - sensitive = source_is_editable && clipboard_has_directory; + sensitive = source_is_editable && can_paste; tooltip = _("Paste contacts from the clipboard"); gtk_action_set_sensitive (action, sensitive); gtk_action_set_tooltip (action, tooltip); @@ -702,6 +738,12 @@ addressbook_view_class_init (EAddressbookViewClass *class) object_class->dispose = addressbook_view_dispose; object_class->constructed = addressbook_view_constructed; + /* Inherited from ESelectableInterface */ + g_object_class_override_property ( + object_class, + PROP_COPY_TARGET_LIST, + "copy-target-list"); + g_object_class_install_property ( object_class, PROP_MODEL, @@ -712,6 +754,12 @@ addressbook_view_class_init (EAddressbookViewClass *class) E_TYPE_ADDRESSBOOK_MODEL, G_PARAM_READABLE)); + /* Inherited from ESelectableInterface */ + g_object_class_override_property ( + object_class, + PROP_PASTE_TARGET_LIST, + "paste-target-list"); + g_object_class_install_property ( object_class, PROP_SHELL_VIEW, @@ -780,10 +828,20 @@ addressbook_view_class_init (EAddressbookViewClass *class) static void addressbook_view_init (EAddressbookView *view) { + GtkTargetList *target_list; + view->priv = E_ADDRESSBOOK_VIEW_GET_PRIVATE (view); view->priv->model = e_addressbook_model_new (); + target_list = gtk_target_list_new (NULL, 0); + e_target_list_add_directory_targets (target_list, 0); + view->priv->copy_target_list = target_list; + + target_list = gtk_target_list_new (NULL, 0); + e_target_list_add_directory_targets (target_list, 0); + view->priv->paste_target_list = target_list; + gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW (view), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); @@ -972,6 +1030,22 @@ e_addressbook_view_get_source (EAddressbookView *view) return view->priv->source; } +GtkTargetList * +e_addressbook_view_get_copy_target_list (EAddressbookView *view) +{ + g_return_val_if_fail (E_IS_ADDRESSBOOK_VIEW (view), NULL); + + return view->priv->copy_target_list; +} + +GtkTargetList * +e_addressbook_view_get_paste_target_list (EAddressbookView *view) +{ + g_return_val_if_fail (E_IS_ADDRESSBOOK_VIEW (view), NULL); + + return view->priv->paste_target_list; +} + static void status_message (EAddressbookView *view, const gchar *status) diff --git a/addressbook/gui/widgets/e-addressbook-view.h b/addressbook/gui/widgets/e-addressbook-view.h index 55f114a538..4b85293cd5 100644 --- a/addressbook/gui/widgets/e-addressbook-view.h +++ b/addressbook/gui/widgets/e-addressbook-view.h @@ -96,6 +96,10 @@ ESelectionModel * EShellView * e_addressbook_view_get_shell_view (EAddressbookView *view); ESource * e_addressbook_view_get_source (EAddressbookView *view); +GtkTargetList * e_addressbook_view_get_copy_target_list + (EAddressbookView *view); +GtkTargetList * e_addressbook_view_get_paste_target_list + (EAddressbookView *view); void e_addressbook_view_view (EAddressbookView *view); void e_addressbook_view_print (EAddressbookView *view, gboolean selection_only, diff --git a/calendar/gui/e-calendar-view.c b/calendar/gui/e-calendar-view.c index 57973828a3..fd8650edad 100644 --- a/calendar/gui/e-calendar-view.c +++ b/calendar/gui/e-calendar-view.c @@ -74,11 +74,16 @@ struct _ECalendarViewPrivate { /* The default category */ gchar *default_category; + + GtkTargetList *copy_target_list; + GtkTargetList *paste_target_list; }; enum { PROP_0, - PROP_MODEL + PROP_COPY_TARGET_LIST, + PROP_MODEL, + PROP_PASTE_TARGET_LIST }; /* FIXME Why are we emitting these event signals here? Can't the model just be listened to? */ @@ -268,11 +273,23 @@ calendar_view_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { + case PROP_COPY_TARGET_LIST: + g_value_set_boxed ( + value, e_calendar_view_get_copy_target_list ( + E_CALENDAR_VIEW (object))); + return; + case PROP_MODEL: g_value_set_object ( value, e_calendar_view_get_model ( E_CALENDAR_VIEW (object))); return; + + case PROP_PASTE_TARGET_LIST: + g_value_set_boxed ( + value, e_calendar_view_get_paste_target_list ( + E_CALENDAR_VIEW (object))); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -293,6 +310,16 @@ calendar_view_dispose (GObject *object) priv->model = NULL; } + if (priv->copy_target_list != NULL) { + gtk_target_list_unref (priv->copy_target_list); + priv->copy_target_list = NULL; + } + + if (priv->paste_target_list != NULL) { + gtk_target_list_unref (priv->paste_target_list); + priv->paste_target_list = NULL; + } + /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (e_calendar_view_parent_class)->dispose (object); } @@ -318,13 +345,15 @@ calendar_view_update_actions (ESelectable *selectable, { ECalendarView *view; GtkAction *action; + GtkTargetList *target_list; GList *list, *iter; + gboolean can_paste = FALSE; gboolean sources_are_editable = TRUE; - gboolean clipboard_has_calendar; gboolean recurring = FALSE; gboolean sensitive; const gchar *tooltip; gint n_selected; + gint ii; view = E_CALENDAR_VIEW (selectable); @@ -353,9 +382,10 @@ calendar_view_update_actions (ESelectable *selectable, g_list_free (list); - clipboard_has_calendar = (clipboard_targets != NULL) && - e_targets_include_calendar ( - clipboard_targets, n_clipboard_targets); + target_list = e_selectable_get_paste_target_list (selectable); + for (ii = 0; ii < n_clipboard_targets && !can_paste; ii++) + can_paste = gtk_target_list_find ( + target_list, clipboard_targets[ii], NULL); action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); sensitive = (n_selected > 0) && sources_are_editable; @@ -370,7 +400,7 @@ calendar_view_update_actions (ESelectable *selectable, gtk_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); - sensitive = sources_are_editable && clipboard_has_calendar; + sensitive = sources_are_editable && can_paste; tooltip = _("Paste events from the clipboard"); gtk_action_set_sensitive (action, sensitive); gtk_action_set_tooltip (action, tooltip); @@ -718,6 +748,12 @@ e_calendar_view_class_init (ECalendarViewClass *class) class->open_event = e_calendar_view_open_event; class->paste_text = NULL; + /* Inherited from ESelectableInterface */ + g_object_class_override_property ( + object_class, + PROP_COPY_TARGET_LIST, + "copy-target-list"); + g_object_class_install_property ( object_class, PROP_MODEL, @@ -729,6 +765,12 @@ e_calendar_view_class_init (ECalendarViewClass *class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + /* Inherited from ESelectableInterface */ + g_object_class_override_property ( + object_class, + PROP_PASTE_TARGET_LIST, + "paste-target-list"); + signals[POPUP_EVENT] = g_signal_new ( "popup-event", G_TYPE_FROM_CLASS (class), @@ -820,7 +862,17 @@ e_calendar_view_class_init (ECalendarViewClass *class) static void e_calendar_view_init (ECalendarView *calendar_view) { + GtkTargetList *target_list; + calendar_view->priv = E_CALENDAR_VIEW_GET_PRIVATE (calendar_view); + + target_list = gtk_target_list_new (NULL, 0); + e_target_list_add_calendar_targets (target_list, 0); + calendar_view->priv->copy_target_list = target_list; + + target_list = gtk_target_list_new (NULL, 0); + e_target_list_add_calendar_targets (target_list, 0); + calendar_view->priv->paste_target_list = target_list; } static void @@ -1017,7 +1069,8 @@ const gchar * e_calendar_view_get_default_category (ECalendarView *cal_view) { g_return_val_if_fail (E_IS_CALENDAR_VIEW (cal_view), NULL); - return (const gchar *) cal_view->priv->default_category; + + return cal_view->priv->default_category; } /** @@ -1029,16 +1082,31 @@ e_calendar_view_get_default_category (ECalendarView *cal_view) * components from the given calendar view. */ void -e_calendar_view_set_default_category (ECalendarView *cal_view, const gchar *category) +e_calendar_view_set_default_category (ECalendarView *cal_view, + const gchar *category) { g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view)); - if (cal_view->priv->default_category) - g_free (cal_view->priv->default_category); - + g_free (cal_view->priv->default_category); cal_view->priv->default_category = g_strdup (category); } +GtkTargetList * +e_calendar_view_get_copy_target_list (ECalendarView *cal_view) +{ + g_return_val_if_fail (E_IS_CALENDAR_VIEW (cal_view), NULL); + + return cal_view->priv->copy_target_list; +} + +GtkTargetList * +e_calendar_view_get_paste_target_list (ECalendarView *cal_view) +{ + g_return_val_if_fail (E_IS_CALENDAR_VIEW (cal_view), NULL); + + return cal_view->priv->paste_target_list; +} + GList * e_calendar_view_get_selected_events (ECalendarView *cal_view) { diff --git a/calendar/gui/e-calendar-view.h b/calendar/gui/e-calendar-view.h index d79a6fdc9d..62fcabcc37 100644 --- a/calendar/gui/e-calendar-view.h +++ b/calendar/gui/e-calendar-view.h @@ -159,6 +159,10 @@ void e_calendar_view_set_status_message (ECalendarView *cal_view, const gchar *message, gint percent); +GtkTargetList * e_calendar_view_get_copy_target_list + (ECalendarView *cal_view); +GtkTargetList * e_calendar_view_get_paste_target_list + (ECalendarView *cal_view); GList * e_calendar_view_get_selected_events (ECalendarView *cal_view); diff --git a/calendar/gui/e-memo-table.c b/calendar/gui/e-memo-table.c index 5f2cd26baf..11c74820a6 100644 --- a/calendar/gui/e-memo-table.c +++ b/calendar/gui/e-memo-table.c @@ -67,11 +67,16 @@ struct _EMemoTablePrivate { gpointer shell_view; /* weak pointer */ ECalModel *model; + + GtkTargetList *copy_target_list; + GtkTargetList *paste_target_list; }; enum { PROP_0, + PROP_COPY_TARGET_LIST, PROP_MODEL, + PROP_PASTE_TARGET_LIST, PROP_SHELL_VIEW }; @@ -300,12 +305,24 @@ memo_table_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { + case PROP_COPY_TARGET_LIST: + g_value_set_boxed ( + value, e_memo_table_get_copy_target_list ( + E_MEMO_TABLE (object))); + return; + case PROP_MODEL: g_value_set_object ( value, e_memo_table_get_model ( E_MEMO_TABLE (object))); return; + case PROP_PASTE_TARGET_LIST: + g_value_set_boxed ( + value, e_memo_table_get_paste_target_list ( + E_MEMO_TABLE (object))); + return; + case PROP_SHELL_VIEW: g_value_set_object ( value, e_memo_table_get_shell_view ( @@ -334,6 +351,16 @@ memo_table_dispose (GObject *object) priv->model = NULL; } + if (priv->copy_target_list != NULL) { + gtk_target_list_unref (priv->copy_target_list); + priv->copy_target_list = NULL; + } + + if (priv->paste_target_list != NULL) { + gtk_target_list_unref (priv->paste_target_list); + priv->paste_target_list = NULL; + } + /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -689,12 +716,14 @@ memo_table_update_actions (ESelectable *selectable, { EMemoTable *memo_table; GtkAction *action; + GtkTargetList *target_list; GSList *list, *iter; + gboolean can_paste = FALSE; gboolean sources_are_editable = TRUE; - gboolean clipboard_has_calendar; gboolean sensitive; const gchar *tooltip; gint n_selected; + gint ii; memo_table = E_MEMO_TABLE (selectable); n_selected = e_table_selected_count (E_TABLE (memo_table)); @@ -709,9 +738,10 @@ memo_table_update_actions (ESelectable *selectable, } g_slist_free (list); - clipboard_has_calendar = (clipboard_targets != NULL) && - e_targets_include_calendar ( - clipboard_targets, n_clipboard_targets); + target_list = e_selectable_get_paste_target_list (selectable); + for (ii = 0; ii < n_clipboard_targets && !can_paste; ii++) + can_paste = gtk_target_list_find ( + target_list, clipboard_targets[ii], NULL); action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); sensitive = (n_selected > 0) && sources_are_editable; @@ -726,7 +756,7 @@ memo_table_update_actions (ESelectable *selectable, gtk_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); - sensitive = sources_are_editable && clipboard_has_calendar; + sensitive = sources_are_editable && can_paste; tooltip = _("Paste memos from the clipboard"); gtk_action_set_sensitive (action, sensitive); gtk_action_set_tooltip (action, tooltip); @@ -1046,6 +1076,12 @@ memo_table_class_init (EMemoTableClass *class) table_class->double_click = memo_table_double_click; table_class->right_click = memo_table_right_click; + /* Inherited from ESelectableInterface */ + g_object_class_override_property ( + object_class, + PROP_COPY_TARGET_LIST, + "copy-target-list"); + g_object_class_install_property ( object_class, PROP_MODEL, @@ -1057,6 +1093,12 @@ memo_table_class_init (EMemoTableClass *class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + /* Inherited from ESelectableInterface */ + g_object_class_override_property ( + object_class, + PROP_PASTE_TARGET_LIST, + "paste-target-list"); + g_object_class_install_property ( object_class, PROP_SHELL_VIEW, @@ -1111,7 +1153,17 @@ memo_table_class_init (EMemoTableClass *class) static void memo_table_init (EMemoTable *memo_table) { + GtkTargetList *target_list; + memo_table->priv = E_MEMO_TABLE_GET_PRIVATE (memo_table); + + target_list = gtk_target_list_new (NULL, 0); + e_target_list_add_calendar_targets (target_list, 0); + memo_table->priv->copy_target_list = target_list; + + target_list = gtk_target_list_new (NULL, 0); + e_target_list_add_calendar_targets (target_list, 0); + memo_table->priv->paste_target_list = target_list; } static void @@ -1249,3 +1301,19 @@ e_memo_table_get_selected (EMemoTable *memo_table) return closure.objects; } + +GtkTargetList * +e_memo_table_get_copy_target_list (EMemoTable *memo_table) +{ + g_return_val_if_fail (E_IS_MEMO_TABLE (memo_table), NULL); + + return memo_table->priv->copy_target_list; +} + +GtkTargetList * +e_memo_table_get_paste_target_list (EMemoTable *memo_table) +{ + g_return_val_if_fail (E_IS_MEMO_TABLE (memo_table), NULL); + + return memo_table->priv->paste_target_list; +} diff --git a/calendar/gui/e-memo-table.h b/calendar/gui/e-memo-table.h index c891117203..b0e4ba6a6a 100644 --- a/calendar/gui/e-memo-table.h +++ b/calendar/gui/e-memo-table.h @@ -103,6 +103,10 @@ void e_memo_table_set_use_24_hour_format (EMemoTable *memo_table, gboolean use_24_hour_format); GSList * e_memo_table_get_selected (EMemoTable *memo_table); +GtkTargetList * e_memo_table_get_copy_target_list + (EMemoTable *memo_table); +GtkTargetList * e_memo_table_get_paste_target_list + (EMemoTable *memo_table); G_END_DECLS diff --git a/calendar/gui/e-task-table.c b/calendar/gui/e-task-table.c index 9f0962dcb8..4a378f2daf 100644 --- a/calendar/gui/e-task-table.c +++ b/calendar/gui/e-task-table.c @@ -69,11 +69,16 @@ struct _ETaskTablePrivate { gpointer shell_view; /* weak pointer */ ECalModel *model; + + GtkTargetList *copy_target_list; + GtkTargetList *paste_target_list; }; enum { PROP_0, + PROP_COPY_TARGET_LIST, PROP_MODEL, + PROP_PASTE_TARGET_LIST, PROP_SHELL_VIEW }; @@ -338,12 +343,24 @@ task_table_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { + case PROP_COPY_TARGET_LIST: + g_value_set_boxed ( + value, e_task_table_get_copy_target_list ( + E_TASK_TABLE (object))); + return; + case PROP_MODEL: g_value_set_object ( value, e_task_table_get_model ( E_TASK_TABLE (object))); return; + case PROP_PASTE_TARGET_LIST: + g_value_set_boxed ( + value, e_task_table_get_paste_target_list ( + E_TASK_TABLE (object))); + return; + case PROP_SHELL_VIEW: g_value_set_object ( value, e_task_table_get_shell_view ( @@ -372,6 +389,16 @@ task_table_dispose (GObject *object) priv->model = NULL; } + if (priv->copy_target_list != NULL) { + gtk_target_list_unref (priv->copy_target_list); + priv->copy_target_list = NULL; + } + + if (priv->paste_target_list != NULL) { + gtk_target_list_unref (priv->paste_target_list); + priv->paste_target_list = NULL; + } + /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -870,12 +897,14 @@ task_table_update_actions (ESelectable *selectable, { ETaskTable *task_table; GtkAction *action; + GtkTargetList *target_list; GSList *list, *iter; + gboolean can_paste = FALSE; gboolean sources_are_editable = TRUE; - gboolean clipboard_has_calendar; gboolean sensitive; const gchar *tooltip; gint n_selected; + gint ii; task_table = E_TASK_TABLE (selectable); n_selected = e_table_selected_count (E_TABLE (task_table)); @@ -890,9 +919,10 @@ task_table_update_actions (ESelectable *selectable, } g_slist_free (list); - clipboard_has_calendar = (clipboard_targets != NULL) && - e_targets_include_calendar ( - clipboard_targets, n_clipboard_targets); + target_list = e_selectable_get_paste_target_list (selectable); + for (ii = 0; ii < n_clipboard_targets && !can_paste; ii++) + can_paste = gtk_target_list_find ( + target_list, clipboard_targets[ii], NULL); action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); sensitive = (n_selected > 0) && sources_are_editable; @@ -907,7 +937,7 @@ task_table_update_actions (ESelectable *selectable, gtk_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); - sensitive = sources_are_editable && clipboard_has_calendar; + sensitive = sources_are_editable && can_paste; tooltip = _("Paste tasks from the clipboard"); gtk_action_set_sensitive (action, sensitive); gtk_action_set_tooltip (action, tooltip); @@ -1010,7 +1040,7 @@ clipboard_get_calendar_data (ETaskTable *task_table, icalcomponent_kind kind; const gchar *status_message; - g_return_if_fail (E_IS_CALENDAR_TABLE (task_table)); + g_return_if_fail (E_IS_TASK_TABLE (task_table)); if (!text || !*text) return; @@ -1305,6 +1335,12 @@ task_table_class_init (ETaskTableClass *class) table_class->double_click = task_table_double_click; table_class->right_click = task_table_right_click; + /* Inherited from ESelectableInterface */ + g_object_class_override_property ( + object_class, + PROP_COPY_TARGET_LIST, + "copy-target-list"); + g_object_class_install_property ( object_class, PROP_MODEL, @@ -1316,6 +1352,12 @@ task_table_class_init (ETaskTableClass *class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + /* Inherited from ESelectableInterface */ + g_object_class_override_property ( + object_class, + PROP_PASTE_TARGET_LIST, + "paste-target-list"); + g_object_class_install_property ( object_class, PROP_SHELL_VIEW, @@ -1370,7 +1412,17 @@ task_table_class_init (ETaskTableClass *class) static void task_table_init (ETaskTable *task_table) { + GtkTargetList *target_list; + task_table->priv = E_TASK_TABLE_GET_PRIVATE (task_table); + + target_list = gtk_target_list_new (NULL, 0); + e_target_list_add_calendar_targets (target_list, 0); + task_table->priv->copy_target_list = target_list; + + target_list = gtk_target_list_new (NULL, 0); + e_target_list_add_calendar_targets (target_list, 0); + task_table->priv->paste_target_list = target_list; } static void @@ -1451,7 +1503,7 @@ e_task_table_new (EShellView *shell_view, ECalModel * e_task_table_get_model (ETaskTable *task_table) { - g_return_val_if_fail (E_IS_CALENDAR_TABLE (task_table), NULL); + g_return_val_if_fail (E_IS_TASK_TABLE (task_table), NULL); return task_table->priv->model; } @@ -1459,7 +1511,7 @@ e_task_table_get_model (ETaskTable *task_table) EShellView * e_task_table_get_shell_view (ETaskTable *task_table) { - g_return_val_if_fail (E_IS_CALENDAR_TABLE (task_table), NULL); + g_return_val_if_fail (E_IS_TASK_TABLE (task_table), NULL); return task_table->priv->shell_view; } @@ -1506,6 +1558,22 @@ e_task_table_get_selected (ETaskTable *task_table) return closure.objects; } +GtkTargetList * +e_task_table_get_copy_target_list (ETaskTable *task_table) +{ + g_return_val_if_fail (E_IS_TASK_TABLE (task_table), NULL); + + return task_table->priv->copy_target_list; +} + +GtkTargetList * +e_task_table_get_paste_target_list (ETaskTable *task_table) +{ + g_return_val_if_fail (E_IS_TASK_TABLE (task_table), NULL); + + return task_table->priv->paste_target_list; +} + static void hide_completed_rows (ECalModel *model, GList *clients_list, diff --git a/calendar/gui/e-task-table.h b/calendar/gui/e-task-table.h index b23f128b87..a112e222f8 100644 --- a/calendar/gui/e-task-table.h +++ b/calendar/gui/e-task-table.h @@ -45,10 +45,10 @@ #define E_TASK_TABLE_CLASS(cls) \ (G_TYPE_CHECK_CLASS_CAST \ ((cls), E_TYPE_TASK_TABLE, ETaskTableClass)) -#define E_IS_CALENDAR_TABLE(obj) \ +#define E_IS_TASK_TABLE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE \ ((obj), E_TYPE_TASK_TABLE)) -#define E_IS_CALENDAR_TABLE_CLASS(cls) \ +#define E_IS_TASK_TABLE_CLASS(cls) \ (G_TYPE_CHECK_CLASS_TYPE \ ((cls), E_TYPE_TASK_TABLE)) #define E_TASK_TABLE_GET_CLASS(obj) \ @@ -93,6 +93,10 @@ GtkWidget * e_task_table_new (EShellView *shell_view, ECalModel * e_task_table_get_model (ETaskTable *task_table); EShellView * e_task_table_get_shell_view (ETaskTable *task_table); GSList * e_task_table_get_selected (ETaskTable *task_table); +GtkTargetList * e_task_table_get_copy_target_list + (ETaskTable *task_table); +GtkTargetList * e_task_table_get_paste_target_list + (ETaskTable *task_table); ECalModelComponent * e_task_table_get_selected_comp (ETaskTable *task_table); diff --git a/composer/e-composer-private.c b/composer/e-composer-private.c index b0bc0c999d..0f7ffbb64c 100644 --- a/composer/e-composer-private.c +++ b/composer/e-composer-private.c @@ -509,6 +509,27 @@ e_composer_get_default_charset (void) } gboolean +e_composer_paste_html (EMsgComposer *composer, + GtkClipboard *clipboard) +{ + GtkhtmlEditor *editor; + gchar *html; + + g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), FALSE); + g_return_val_if_fail (GTK_IS_CLIPBOARD (clipboard), FALSE); + + html = e_clipboard_wait_for_html (clipboard); + g_return_val_if_fail (html != NULL, FALSE); + + editor = GTKHTML_EDITOR (composer); + gtkhtml_editor_insert_html (editor, html); + + g_free (html); + + return TRUE; +} + +gboolean e_composer_paste_image (EMsgComposer *composer, GtkClipboard *clipboard) { @@ -583,6 +604,27 @@ exit: } gboolean +e_composer_paste_text (EMsgComposer *composer, + GtkClipboard *clipboard) +{ + GtkhtmlEditor *editor; + gchar *text; + + g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), FALSE); + g_return_val_if_fail (GTK_IS_CLIPBOARD (clipboard), FALSE); + + text = gtk_clipboard_wait_for_text (clipboard); + g_return_val_if_fail (text != NULL, FALSE); + + editor = GTKHTML_EDITOR (composer); + gtkhtml_editor_insert_text (editor, text); + + g_free (text); + + return TRUE; +} + +gboolean e_composer_paste_uris (EMsgComposer *composer, GtkClipboard *clipboard) { diff --git a/composer/e-composer-private.h b/composer/e-composer-private.h index 1711e0c17b..cac41aabe4 100644 --- a/composer/e-composer-private.h +++ b/composer/e-composer-private.h @@ -52,6 +52,7 @@ #include "e-util/e-binding.h" #include "e-util/e-charset.h" #include "e-util/e-mktemp.h" +#include "e-util/e-selection.h" #include "e-util/e-util.h" #include "e-util/gconf-bridge.h" #include "widgets/misc/e-attachment-icon-view.h" @@ -157,8 +158,12 @@ void e_composer_private_finalize (EMsgComposer *composer); void e_composer_actions_init (EMsgComposer *composer); gchar * e_composer_find_data_file (const gchar *basename); gchar * e_composer_get_default_charset (void); +gboolean e_composer_paste_html (EMsgComposer *composer, + GtkClipboard *clipboard); gboolean e_composer_paste_image (EMsgComposer *composer, GtkClipboard *clipboard); +gboolean e_composer_paste_text (EMsgComposer *composer, + GtkClipboard *clipboard); gboolean e_composer_paste_uris (EMsgComposer *composer, GtkClipboard *clipboard); diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index bdac5d44ab..b57bd156a5 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -1488,6 +1488,60 @@ msg_composer_account_changed_cb (EMsgComposer *composer) e_msg_composer_show_sig_file (composer); } +static void +msg_composer_paste_clipboard_targets_cb (GtkClipboard *clipboard, + GdkAtom *targets, + gint n_targets, + EMsgComposer *composer) +{ + GtkhtmlEditor *editor; + gboolean html_mode; + + editor = GTKHTML_EDITOR (composer); + html_mode = gtkhtml_editor_get_html_mode (editor); + + /* Order is important here to ensure common use cases are + * handled correctly. See GNOME bug #603715 for details. */ + + if (gtk_targets_include_uri (targets, n_targets)) { + e_composer_paste_uris (composer, clipboard); + return; + } + + /* Only paste HTML content in HTML mode. */ + if (html_mode) { + if (e_targets_include_html (targets, n_targets)) { + e_composer_paste_html (composer, clipboard); + return; + } + } + + if (gtk_targets_include_text (targets, n_targets)) { + e_composer_paste_text (composer, clipboard); + return; + } + + if (gtk_targets_include_image (targets, n_targets, TRUE)) { + e_composer_paste_image (composer, clipboard); + return; + } +} + +static void +msg_composer_paste_clipboard_cb (EWebView *web_view, + EMsgComposer *composer) +{ + GtkClipboard *clipboard; + + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + + gtk_clipboard_request_targets ( + clipboard, (GtkClipboardTargetsReceivedFunc) + msg_composer_paste_clipboard_targets_cb, composer); + + g_signal_stop_emission_by_name (web_view, "paste-clipboard"); +} + struct _drop_data { EMsgComposer *composer; @@ -1616,6 +1670,12 @@ msg_composer_constructed (GObject *object) shell_settings, "composer-request-receipt"); gtk_toggle_action_set_active (action, active); + /* Clipboard Support */ + + g_signal_connect ( + html, "paste-clipboard", + G_CALLBACK (msg_composer_paste_clipboard_cb), composer); + /* Drag-and-Drop Support */ target_list = e_attachment_view_get_target_list (view); @@ -1840,91 +1900,25 @@ msg_composer_drag_data_received (GtkWidget *widget, static void msg_composer_cut_clipboard (GtkhtmlEditor *editor) { - EMsgComposer *composer; - GtkWidget *parent; - GtkWidget *widget; - - composer = E_MSG_COMPOSER (editor); - widget = gtk_window_get_focus (GTK_WINDOW (editor)); - parent = gtk_widget_get_parent (widget); - - /* EFocusTracker handles the header widgets. */ - if (parent == composer->priv->header_table) - return; - - /* Chain up to parent's cut_clipboard() method. */ - GTKHTML_EDITOR_CLASS (parent_class)->cut_clipboard (editor); + /* Do nothing. EFocusTracker handles this. */ } static void msg_composer_copy_clipboard (GtkhtmlEditor *editor) { - EMsgComposer *composer; - GtkWidget *parent; - GtkWidget *widget; - - composer = E_MSG_COMPOSER (editor); - widget = gtk_window_get_focus (GTK_WINDOW (editor)); - parent = gtk_widget_get_parent (widget); - - /* EFocusTracker handles the header widgets. */ - if (parent == composer->priv->header_table) - return; - - /* Chain up to parent's copy_clipboard() method. */ - GTKHTML_EDITOR_CLASS (parent_class)->copy_clipboard (editor); + /* Do nothing. EFocusTracker handles this. */ } static void msg_composer_paste_clipboard (GtkhtmlEditor *editor) { - EMsgComposer *composer; - GtkClipboard *clipboard; - GtkWidget *parent; - GtkWidget *widget; - - composer = E_MSG_COMPOSER (editor); - - widget = gtk_window_get_focus (GTK_WINDOW (editor)); - parent = gtk_widget_get_parent (widget); - - /* EFocusTracker handles the header widgets. */ - if (parent == composer->priv->header_table) - return; - - clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD); - - if (gtk_clipboard_wait_is_image_available (clipboard)) { - e_composer_paste_image (composer, clipboard); - return; - } - - if (gtk_clipboard_wait_is_uris_available (clipboard)) { - e_composer_paste_uris (composer, clipboard); - return; - } - - /* Chain up to parent's paste_clipboard() method. */ - GTKHTML_EDITOR_CLASS (parent_class)->paste_clipboard (editor); + /* Do nothing. EFocusTracker handles this. */ } static void msg_composer_select_all (GtkhtmlEditor *editor) { - EMsgComposer *composer; - GtkWidget *parent; - GtkWidget *widget; - - composer = E_MSG_COMPOSER (editor); - widget = gtk_window_get_focus (GTK_WINDOW (editor)); - parent = gtk_widget_get_parent (widget); - - /* EFocusTracker handles the header widgets. */ - if (parent == composer->priv->header_table) - return; - - /* Chain up to the parent's select_all() method. */ - GTKHTML_EDITOR_CLASS (parent_class)->select_all (editor); + /* Do nothing. EFocusTracker handles this. */ } static void diff --git a/configure.ac b/configure.ac index e32b4295e3..826ac56b85 100644 --- a/configure.ac +++ b/configure.ac @@ -40,7 +40,7 @@ m4_define([gtk_minimum_version], [2.18.0]) m4_define([eds_minimum_version], [evo_version]) m4_define([gnome_icon_theme_minimum_version], [2.19.91]) m4_define([gnome_desktop_minimum_version], [2.26.0]) -m4_define([libgtkhtml_minimum_version], [3.29.5]) +m4_define([libgtkhtml_minimum_version], [3.29.6]) m4_define([gconf_minimum_version], [2.0.0]) dnl XXX Just a Guess m4_define([libsoup_minimum_version], [2.4.0]) dnl XXX Just a Guess m4_define([libgnomecanvas_minimum_version], [2.0.0]) dnl XXX Just a Guess diff --git a/mail/message-list.c b/mail/message-list.c index 288b4a5420..9046b69894 100644 --- a/mail/message-list.c +++ b/mail/message-list.c @@ -117,10 +117,15 @@ struct _MessageListPrivate { gboolean thread_latest; gboolean any_row_changed; /* save state before regen list when this is set to true */ + + GtkTargetList *copy_target_list; + GtkTargetList *paste_target_list; }; enum { PROP_0, + PROP_COPY_TARGET_LIST, + PROP_PASTE_TARGET_LIST, PROP_SHELL_BACKEND }; @@ -2295,6 +2300,7 @@ static void message_list_init (MessageList *message_list) { MessageListPrivate *p; + GtkTargetList *target_list; GdkAtom matom; message_list->priv = MESSAGE_LIST_GET_PRIVATE (message_list); @@ -2336,6 +2342,14 @@ message_list_init (MessageList *message_list) g_signal_connect(p->invisible, "selection_get", G_CALLBACK(ml_selection_get), message_list); g_signal_connect(p->invisible, "selection_clear_event", G_CALLBACK(ml_selection_clear_event), message_list); g_signal_connect(p->invisible, "selection_received", G_CALLBACK(ml_selection_received), message_list); + + /* FIXME This is currently unused. */ + target_list = gtk_target_list_new (NULL, 0); + message_list->priv->copy_target_list = target_list; + + /* FIXME This is currently unused. */ + target_list = gtk_target_list_new (NULL, 0); + message_list->priv->paste_target_list = target_list; } static void @@ -2418,6 +2432,18 @@ message_list_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { + case PROP_COPY_TARGET_LIST: + g_value_set_boxed ( + value, message_list_get_copy_target_list ( + MESSAGE_LIST (object))); + return; + + case PROP_PASTE_TARGET_LIST: + g_value_set_boxed ( + value, message_list_get_paste_target_list ( + MESSAGE_LIST (object))); + return; + case PROP_SHELL_BACKEND: g_value_set_object ( value, message_list_get_shell_backend ( @@ -2440,6 +2466,16 @@ message_list_dispose (GObject *object) priv->shell_backend = NULL; } + if (priv->copy_target_list != NULL) { + g_object_unref (priv->copy_target_list); + priv->copy_target_list = NULL; + } + + if (priv->paste_target_list != NULL) { + g_object_unref (priv->paste_target_list); + priv->paste_target_list = NULL; + } + /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -2533,6 +2569,18 @@ message_list_class_init (MessageListClass *class) class->message_list_built = message_list_built; + /* Inherited from ESelectableInterface */ + g_object_class_override_property ( + object_class, + PROP_COPY_TARGET_LIST, + "copy-target-list"); + + /* Inherited from ESelectableInterface */ + g_object_class_override_property ( + object_class, + PROP_PASTE_TARGET_LIST, + "paste-target-list"); + g_object_class_install_property ( object_class, PROP_SHELL_BACKEND, @@ -3614,6 +3662,22 @@ message_list_set_folder (MessageList *message_list, CamelFolder *folder, const g } } +GtkTargetList * +message_list_get_copy_target_list (MessageList *message_list) +{ + g_return_val_if_fail (IS_MESSAGE_LIST (message_list), NULL); + + return message_list->priv->copy_target_list; +} + +GtkTargetList * +message_list_get_paste_target_list (MessageList *message_list) +{ + g_return_val_if_fail (IS_MESSAGE_LIST (message_list), NULL); + + return message_list->priv->paste_target_list; +} + static gboolean on_cursor_activated_idle (gpointer data) { diff --git a/mail/message-list.h b/mail/message-list.h index 953a444e11..c7efc5dc14 100644 --- a/mail/message-list.h +++ b/mail/message-list.h @@ -189,6 +189,10 @@ void message_list_set_folder (MessageList *message_list, CamelFolder *camel_folder, const gchar *uri, gboolean outgoing); +GtkTargetList * message_list_get_copy_target_list + (MessageList *message_list); +GtkTargetList * message_list_get_paste_target_list + (MessageList *message_list); void message_list_freeze (MessageList *message_list); void message_list_thaw (MessageList *message_list); GPtrArray * message_list_get_uids (MessageList *message_list); diff --git a/widgets/misc/e-focus-tracker.c b/widgets/misc/e-focus-tracker.c index d1cb32adde..8eb1b25d56 100644 --- a/widgets/misc/e-focus-tracker.c +++ b/widgets/misc/e-focus-tracker.c @@ -360,6 +360,10 @@ focus_tracker_dispose (GObject *object) gtk_clipboard_get (GDK_SELECTION_PRIMARY), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object); + g_signal_handlers_disconnect_matched ( + gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), + G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object); + if (priv->window != NULL) { g_signal_handlers_disconnect_matched ( priv->window, G_SIGNAL_MATCH_DATA, @@ -427,6 +431,16 @@ focus_tracker_constructed (GObject *object) g_signal_connect_swapped ( clipboard, "owner-change", G_CALLBACK (e_focus_tracker_update_actions), object); + + /* Listen for "owner-change" signals from the default clipboard + * so we can update the paste action when the user cuts or copies + * something. This is how GEdit does it. */ + + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + + g_signal_connect_swapped ( + clipboard, "owner-change", + G_CALLBACK (e_focus_tracker_update_actions), object); } static void diff --git a/widgets/misc/e-selectable.c b/widgets/misc/e-selectable.c index bb5948cc13..da998d320d 100644 --- a/widgets/misc/e-selectable.c +++ b/widgets/misc/e-selectable.c @@ -21,6 +21,28 @@ #include "e-selectable.h" +static void +selectable_class_init (ESelectableInterface *interface) +{ + g_object_interface_install_property ( + interface, + g_param_spec_boxed ( + "copy-target-list", + "Copy Target List", + NULL, + GTK_TYPE_TARGET_LIST, + G_PARAM_READABLE)); + + g_object_interface_install_property ( + interface, + g_param_spec_boxed ( + "paste-target-list", + "Paste Target List", + NULL, + GTK_TYPE_TARGET_LIST, + G_PARAM_READABLE)); +} + GType e_selectable_get_type (void) { @@ -31,7 +53,7 @@ e_selectable_get_type (void) sizeof (ESelectableInterface), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, - (GClassInitFunc) NULL, + (GClassInitFunc) selectable_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ 0, /* instance_size */ @@ -43,7 +65,7 @@ e_selectable_get_type (void) type = g_type_register_static ( G_TYPE_INTERFACE, "ESelectable", &type_info, 0); - g_type_interface_add_prerequisite (type, G_TYPE_OBJECT); + g_type_interface_add_prerequisite (type, GTK_TYPE_WIDGET); } return type; @@ -131,3 +153,35 @@ e_selectable_select_all (ESelectable *selectable) if (interface->select_all != NULL) interface->select_all (selectable); } + +GtkTargetList * +e_selectable_get_copy_target_list (ESelectable *selectable) +{ + GtkTargetList *target_list; + + g_return_val_if_fail (E_IS_SELECTABLE (selectable), NULL); + + g_object_get (selectable, "copy-target-list", &target_list, NULL); + + /* We want to return a borrowed reference to the target + * list, so undo the reference that g_object_get() added. */ + gtk_target_list_unref (target_list); + + return target_list; +} + +GtkTargetList * +e_selectable_get_paste_target_list (ESelectable *selectable) +{ + GtkTargetList *target_list; + + g_return_val_if_fail (E_IS_SELECTABLE (selectable), NULL); + + g_object_get (selectable, "paste-target-list", &target_list, NULL); + + /* We want to return a borrowed reference to the target + * list, so undo the reference that g_object_get() added. */ + gtk_target_list_unref (target_list); + + return target_list; +} diff --git a/widgets/misc/e-selectable.h b/widgets/misc/e-selectable.h index fca400ce65..c9a0b6dded 100644 --- a/widgets/misc/e-selectable.h +++ b/widgets/misc/e-selectable.h @@ -70,6 +70,10 @@ void e_selectable_copy_clipboard (ESelectable *selectable); void e_selectable_paste_clipboard (ESelectable *selectable); void e_selectable_delete_selection (ESelectable *selectable); void e_selectable_select_all (ESelectable *selectable); +GtkTargetList * e_selectable_get_copy_target_list + (ESelectable *selectable); +GtkTargetList * e_selectable_get_paste_target_list + (ESelectable *selectable); G_END_DECLS diff --git a/widgets/misc/e-web-view.c b/widgets/misc/e-web-view.c index 31516bf04d..a5f98a4edc 100644 --- a/widgets/misc/e-web-view.c +++ b/widgets/misc/e-web-view.c @@ -50,6 +50,9 @@ struct _EWebViewPrivate { GtkAction *print_proxy; GtkAction *save_as_proxy; + GtkTargetList *copy_target_list; + GtkTargetList *paste_target_list; + /* Lockdown Options */ guint disable_printing : 1; guint disable_save_to_disk : 1; @@ -68,15 +71,21 @@ enum { PROP_0, PROP_ANIMATE, PROP_CARET_MODE, + PROP_COPY_TARGET_LIST, PROP_DISABLE_PRINTING, PROP_DISABLE_SAVE_TO_DISK, + PROP_EDITABLE, PROP_OPEN_PROXY, + PROP_PASTE_TARGET_LIST, PROP_PRINT_PROXY, PROP_SAVE_AS_PROXY, PROP_SELECTED_URI }; enum { + COPY_CLIPBOARD, + CUT_CLIPBOARD, + PASTE_CLIPBOARD, POPUP_EVENT, STATUS_MESSAGE, STOP_LOADING, @@ -488,6 +497,12 @@ web_view_set_property (GObject *object, g_value_get_boolean (value)); return; + case PROP_EDITABLE: + e_web_view_set_editable ( + E_WEB_VIEW (object), + g_value_get_boolean (value)); + return; + case PROP_OPEN_PROXY: e_web_view_set_open_proxy ( E_WEB_VIEW (object), @@ -535,6 +550,12 @@ web_view_get_property (GObject *object, E_WEB_VIEW (object))); return; + case PROP_COPY_TARGET_LIST: + g_value_set_boxed ( + value, e_web_view_get_copy_target_list ( + E_WEB_VIEW (object))); + return; + case PROP_DISABLE_PRINTING: g_value_set_boolean ( value, e_web_view_get_disable_printing ( @@ -547,12 +568,24 @@ web_view_get_property (GObject *object, E_WEB_VIEW (object))); return; + case PROP_EDITABLE: + g_value_set_boolean ( + value, e_web_view_get_editable ( + E_WEB_VIEW (object))); + return; + case PROP_OPEN_PROXY: g_value_set_object ( value, e_web_view_get_open_proxy ( E_WEB_VIEW (object))); return; + case PROP_PASTE_TARGET_LIST: + g_value_set_boxed ( + value, e_web_view_get_paste_target_list ( + E_WEB_VIEW (object))); + return; + case PROP_PRINT_PROXY: g_value_set_object ( value, e_web_view_get_print_proxy ( @@ -602,6 +635,16 @@ web_view_dispose (GObject *object) priv->save_as_proxy = NULL; } + if (priv->copy_target_list != NULL) { + gtk_target_list_unref (priv->copy_target_list); + priv->copy_target_list = NULL; + } + + if (priv->paste_target_list != NULL) { + gtk_target_list_unref (priv->paste_target_list); + priv->paste_target_list = NULL; + } + /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -765,6 +808,26 @@ web_view_extract_uri (EWebView *web_view, return uri; } +static void +web_view_copy_clipboard (EWebView *web_view) +{ + gtk_html_command (GTK_HTML (web_view), "copy"); +} + +static void +web_view_cut_clipboard (EWebView *web_view) +{ + if (e_web_view_get_editable (web_view)) + gtk_html_command (GTK_HTML (web_view), "cut"); +} + +static void +web_view_paste_clipboard (EWebView *web_view) +{ + if (e_web_view_get_editable (web_view)) + gtk_html_command (GTK_HTML (web_view), "paste"); +} + static gboolean web_view_popup_event (EWebView *web_view, GdkEventButton *event, @@ -865,39 +928,76 @@ web_view_selectable_update_actions (ESelectable *selectable, { EWebView *web_view; GtkAction *action; - const gchar *tooltip; + /*GtkTargetList *target_list;*/ + gboolean can_paste = FALSE; + gboolean editable; + gboolean have_selection; gboolean sensitive; + const gchar *tooltip; + /*gint ii;*/ web_view = E_WEB_VIEW (selectable); + editable = e_web_view_get_editable (web_view); + have_selection = e_web_view_is_selection_active (web_view); - /* Copy Clipboard */ - - action = e_web_view_get_action (web_view, "copy-clipboard"); - sensitive = gtk_action_get_sensitive (action); - tooltip = gtk_action_get_tooltip (action); + /* XXX GtkHtml implements its own clipboard instead of using + * GDK_SELECTION_CLIPBOARD, so we don't get notifications + * when the clipboard contents change. The logic below + * is what we would do if GtkHtml worked properly. + * Instead, we need to keep the Paste action sensitive so + * its accelerator overrides GtkHtml's key binding. */ +#if 0 + target_list = e_selectable_get_paste_target_list (selectable); + for (ii = 0; ii < n_clipboard_targets && !can_paste; ii++) + can_paste = gtk_target_list_find ( + target_list, clipboard_targets[ii], NULL); +#endif + can_paste = TRUE; + + action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); + sensitive = editable && have_selection; + tooltip = _("Cut the selection"); + gtk_action_set_sensitive (action, sensitive); + gtk_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_copy_clipboard_action (focus_tracker); + sensitive = have_selection; + tooltip = _("Copy the selection"); gtk_action_set_sensitive (action, sensitive); gtk_action_set_tooltip (action, tooltip); - /* Select All */ - - action = e_web_view_get_action (web_view, "select-all"); - sensitive = gtk_action_get_sensitive (action); - tooltip = gtk_action_get_tooltip (action); + action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); + sensitive = editable && can_paste; + tooltip = _("Paste the clipboard"); + gtk_action_set_sensitive (action, sensitive); + gtk_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_select_all_action (focus_tracker); + sensitive = TRUE; + tooltip = _("Select all text and images"); gtk_action_set_sensitive (action, sensitive); gtk_action_set_tooltip (action, tooltip); } static void +web_view_selectable_cut_clipboard (ESelectable *selectable) +{ + e_web_view_cut_clipboard (E_WEB_VIEW (selectable)); +} + +static void web_view_selectable_copy_clipboard (ESelectable *selectable) { e_web_view_copy_clipboard (E_WEB_VIEW (selectable)); } static void +web_view_selectable_paste_clipboard (ESelectable *selectable) +{ + e_web_view_paste_clipboard (E_WEB_VIEW (selectable)); +} + +static void web_view_selectable_select_all (ESelectable *selectable) { e_web_view_select_all (E_WEB_VIEW (selectable)); @@ -930,6 +1030,9 @@ web_view_class_init (EWebViewClass *class) html_class->iframe_created = web_view_iframe_created; class->extract_uri = web_view_extract_uri; + class->copy_clipboard = web_view_copy_clipboard; + class->cut_clipboard = web_view_cut_clipboard; + class->paste_clipboard = web_view_paste_clipboard; class->popup_event = web_view_popup_event; class->stop_loading = web_view_stop_loading; class->update_actions = web_view_update_actions; @@ -954,6 +1057,12 @@ web_view_class_init (EWebViewClass *class) FALSE, G_PARAM_READWRITE)); + /* Inherited from ESelectableInterface */ + g_object_class_override_property ( + object_class, + PROP_COPY_TARGET_LIST, + "copy-target-list"); + g_object_class_install_property ( object_class, PROP_DISABLE_PRINTING, @@ -976,6 +1085,16 @@ web_view_class_init (EWebViewClass *class) g_object_class_install_property ( object_class, + PROP_EDITABLE, + g_param_spec_boolean ( + "editable", + "Editable", + NULL, + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, PROP_OPEN_PROXY, g_param_spec_object ( "open-proxy", @@ -984,6 +1103,12 @@ web_view_class_init (EWebViewClass *class) GTK_TYPE_ACTION, G_PARAM_READWRITE)); + /* Inherited from ESelectableInterface */ + g_object_class_override_property ( + object_class, + PROP_PASTE_TARGET_LIST, + "paste-target-list"); + g_object_class_install_property ( object_class, PROP_PRINT_PROXY, @@ -1014,6 +1139,33 @@ web_view_class_init (EWebViewClass *class) NULL, G_PARAM_READWRITE)); + signals[COPY_CLIPBOARD] = g_signal_new ( + "copy-clipboard", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EWebViewClass, copy_clipboard), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[CUT_CLIPBOARD] = g_signal_new ( + "cut-clipboard", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EWebViewClass, cut_clipboard), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[PASTE_CLIPBOARD] = g_signal_new ( + "paste-clipboard", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EWebViewClass, paste_clipboard), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[POPUP_EVENT] = g_signal_new ( "popup-event", G_TYPE_FROM_CLASS (class), @@ -1058,7 +1210,9 @@ static void web_view_selectable_init (ESelectableInterface *interface) { interface->update_actions = web_view_selectable_update_actions; + interface->cut_clipboard = web_view_selectable_cut_clipboard; interface->copy_clipboard = web_view_selectable_copy_clipboard; + interface->paste_clipboard = web_view_selectable_paste_clipboard; interface->select_all = web_view_selectable_select_all; } @@ -1067,6 +1221,7 @@ web_view_init (EWebView *web_view) { GtkUIManager *ui_manager; GtkActionGroup *action_group; + GtkTargetList *target_list; EPopupAction *popup_action; const gchar *domain = GETTEXT_PACKAGE; const gchar *id; @@ -1081,6 +1236,12 @@ web_view_init (EWebView *web_view) ui_manager, "connect-proxy", G_CALLBACK (web_view_connect_proxy_cb), web_view); + target_list = gtk_target_list_new (NULL, 0); + web_view->priv->copy_target_list = target_list; + + target_list = gtk_target_list_new (NULL, 0); + web_view->priv->paste_target_list = target_list; + action_group = gtk_action_group_new ("uri"); gtk_action_group_set_translation_domain (action_group, domain); gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); @@ -1287,6 +1448,14 @@ e_web_view_set_caret_mode (EWebView *web_view, g_object_notify (G_OBJECT (web_view), "caret-mode"); } +GtkTargetList * +e_web_view_get_copy_target_list (EWebView *web_view) +{ + g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); + + return web_view->priv->copy_target_list; +} + gboolean e_web_view_get_disable_printing (EWebView *web_view) { @@ -1325,6 +1494,32 @@ e_web_view_set_disable_save_to_disk (EWebView *web_view, g_object_notify (G_OBJECT (web_view), "disable-save-to-disk"); } +gboolean +e_web_view_get_editable (EWebView *web_view) +{ + /* XXX This is just here to maintain symmetry + * with e_web_view_set_editable(). */ + + g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE); + + return gtk_html_get_editable (GTK_HTML (web_view)); +} + +void +e_web_view_set_editable (EWebView *web_view, + gboolean editable) +{ + /* XXX GtkHTML does not utilize GObject properties as well + * as it could. This just wraps gtk_html_set_editable() + * so we can get a "notify::editable" signal. */ + + g_return_if_fail (E_IS_WEB_VIEW (web_view)); + + gtk_html_set_editable (GTK_HTML (web_view), editable); + + g_object_notify (G_OBJECT (web_view), "editable"); +} + const gchar * e_web_view_get_selected_uri (EWebView *web_view) { @@ -1372,6 +1567,14 @@ e_web_view_set_open_proxy (EWebView *web_view, g_object_notify (G_OBJECT (web_view), "open-proxy"); } +GtkTargetList * +e_web_view_get_paste_target_list (EWebView *web_view) +{ + g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); + + return web_view->priv->paste_target_list; +} + GtkAction * e_web_view_get_print_proxy (EWebView *web_view) { @@ -1477,7 +1680,15 @@ e_web_view_copy_clipboard (EWebView *web_view) { g_return_if_fail (E_IS_WEB_VIEW (web_view)); - gtk_html_command (GTK_HTML (web_view), "copy"); + g_signal_emit (web_view, signals[COPY_CLIPBOARD], 0); +} + +void +e_web_view_cut_clipboard (EWebView *web_view) +{ + g_return_if_fail (E_IS_WEB_VIEW (web_view)); + + g_signal_emit (web_view, signals[CUT_CLIPBOARD], 0); } gboolean @@ -1488,6 +1699,14 @@ e_web_view_is_selection_active (EWebView *web_view) return gtk_html_command (GTK_HTML (web_view), "is-selection-active"); } +void +e_web_view_paste_clipboard (EWebView *web_view) +{ + g_return_if_fail (E_IS_WEB_VIEW (web_view)); + + g_signal_emit (web_view, signals[PASTE_CLIPBOARD], 0); +} + gboolean e_web_view_scroll_forward (EWebView *web_view) { diff --git a/widgets/misc/e-web-view.h b/widgets/misc/e-web-view.h index 123965c7d0..788eadb1b7 100644 --- a/widgets/misc/e-web-view.h +++ b/widgets/misc/e-web-view.h @@ -71,6 +71,9 @@ struct _EWebViewClass { GtkHTML *frame); /* Signals */ + void (*copy_clipboard) (EWebView *web_view); + void (*cut_clipboard) (EWebView *web_view); + void (*paste_clipboard) (EWebView *web_view); gboolean (*popup_event) (EWebView *web_view, GdkEventButton *event, const gchar *uri); @@ -91,6 +94,7 @@ void e_web_view_set_animate (EWebView *web_view, gboolean e_web_view_get_caret_mode (EWebView *web_view); void e_web_view_set_caret_mode (EWebView *web_view, gboolean caret_mode); +GtkTargetList * e_web_view_get_copy_target_list (EWebView *web_view); gboolean e_web_view_get_disable_printing (EWebView *web_view); void e_web_view_set_disable_printing (EWebView *web_view, gboolean disable_printing); @@ -99,12 +103,16 @@ gboolean e_web_view_get_disable_save_to_disk void e_web_view_set_disable_save_to_disk (EWebView *web_view, gboolean disable_save_to_disk); +gboolean e_web_view_get_editable (EWebView *web_view); +void e_web_view_set_editable (EWebView *web_view, + gboolean editable); const gchar * e_web_view_get_selected_uri (EWebView *web_view); void e_web_view_set_selected_uri (EWebView *web_view, const gchar *selected_uri); GtkAction * e_web_view_get_open_proxy (EWebView *web_view); void e_web_view_set_open_proxy (EWebView *web_view, GtkAction *open_proxy); +GtkTargetList * e_web_view_get_paste_target_list(EWebView *web_view); GtkAction * e_web_view_get_print_proxy (EWebView *web_view); void e_web_view_set_print_proxy (EWebView *web_view, GtkAction *print_proxy); @@ -119,7 +127,9 @@ gchar * e_web_view_extract_uri (EWebView *web_view, GdkEventButton *event, GtkHTML *frame); void e_web_view_copy_clipboard (EWebView *web_view); +void e_web_view_cut_clipboard (EWebView *web_view); gboolean e_web_view_is_selection_active (EWebView *web_view); +void e_web_view_paste_clipboard (EWebView *web_view); gboolean e_web_view_scroll_forward (EWebView *web_view); gboolean e_web_view_scroll_backward (EWebView *web_view); void e_web_view_select_all (EWebView *web_view); |