aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--addressbook/gui/widgets/e-addressbook-view.c90
-rw-r--r--addressbook/gui/widgets/e-addressbook-view.h4
-rw-r--r--calendar/gui/e-calendar-view.c90
-rw-r--r--calendar/gui/e-calendar-view.h4
-rw-r--r--calendar/gui/e-memo-table.c78
-rw-r--r--calendar/gui/e-memo-table.h4
-rw-r--r--calendar/gui/e-task-table.c84
-rw-r--r--calendar/gui/e-task-table.h8
-rw-r--r--composer/e-composer-private.c42
-rw-r--r--composer/e-composer-private.h5
-rw-r--r--composer/e-msg-composer.c134
-rw-r--r--configure.ac2
-rw-r--r--mail/message-list.c64
-rw-r--r--mail/message-list.h4
-rw-r--r--widgets/misc/e-focus-tracker.c14
-rw-r--r--widgets/misc/e-selectable.c58
-rw-r--r--widgets/misc/e-selectable.h4
-rw-r--r--widgets/misc/e-web-view.c243
-rw-r--r--widgets/misc/e-web-view.h10
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);