aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-html-editor-actions.c
diff options
context:
space:
mode:
Diffstat (limited to 'e-util/e-html-editor-actions.c')
-rw-r--r--e-util/e-html-editor-actions.c2028
1 files changed, 2028 insertions, 0 deletions
diff --git a/e-util/e-html-editor-actions.c b/e-util/e-html-editor-actions.c
new file mode 100644
index 0000000000..6db3ad48da
--- /dev/null
+++ b/e-util/e-html-editor-actions.c
@@ -0,0 +1,2028 @@
+/* e-html-editor-actions.c
+ *
+ * Copyright (C) 2012 Dan Vrátil <dvratil@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gio/gio.h>
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include <enchant/enchant.h>
+
+#include "e-html-editor.h"
+#include "e-html-editor-private.h"
+#include "e-html-editor-actions.h"
+#include "e-html-editor-utils.h"
+#include "e-emoticon-action.h"
+#include "e-emoticon-chooser.h"
+#include "e-image-chooser-dialog.h"
+#include "e-spell-checker.h"
+
+static void
+insert_html_file_ready_cb (GFile *file,
+ GAsyncResult *result,
+ EHTMLEditor *editor)
+{
+ EHTMLEditorSelection *selection;
+ gchar *contents = NULL;
+ gsize length;
+ GError *error = NULL;
+
+ g_file_load_contents_finish (
+ file, result, &contents, &length, NULL, &error);
+ if (error != NULL) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (editor))),
+ 0, GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE, _("Failed to insert HTML file."));
+ gtk_message_dialog_format_secondary_text (
+ GTK_MESSAGE_DIALOG (dialog), "%s.", error->message);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ g_clear_error (&error);
+ g_object_unref (editor);
+ return;
+ }
+
+ selection = e_html_editor_view_get_selection (
+ e_html_editor_get_view (editor));
+ e_html_editor_selection_insert_html (selection, contents);
+ g_free (contents);
+
+ g_object_unref (editor);
+}
+
+static void
+insert_text_file_ready_cb (GFile *file,
+ GAsyncResult *result,
+ EHTMLEditor *editor)
+{
+ EHTMLEditorSelection *selection;
+ gchar *contents;
+ gsize length;
+ GError *error = NULL;
+
+ g_file_load_contents_finish (
+ file, result, &contents, &length, NULL, &error);
+ if (error != NULL) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (editor))),
+ 0, GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE, _("Failed to insert text file."));
+ gtk_message_dialog_format_secondary_text (
+ GTK_MESSAGE_DIALOG (dialog), "%s.", error->message);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ g_clear_error (&error);
+ g_object_unref (editor);
+ return;
+ }
+
+ selection = e_html_editor_view_get_selection (
+ e_html_editor_get_view (editor));
+ e_html_editor_selection_insert_text (selection, contents);
+ g_free (contents);
+
+ g_object_unref (editor);
+}
+
+static void
+editor_update_static_spell_actions (EHTMLEditor *editor)
+{
+ ESpellChecker *checker;
+ EHTMLEditorView *view;
+ guint count;
+
+ view = e_html_editor_get_view (editor);
+ checker = e_html_editor_view_get_spell_checker (view);
+
+ count = e_spell_checker_count_active_languages (checker);
+
+ gtk_action_set_visible (ACTION (CONTEXT_SPELL_ADD), count == 1);
+ gtk_action_set_visible (ACTION (CONTEXT_SPELL_ADD_MENU), count > 1);
+ gtk_action_set_visible (ACTION (CONTEXT_SPELL_IGNORE), count > 0);
+
+ gtk_action_set_sensitive (ACTION (SPELL_CHECK), count > 0);
+}
+
+/*****************************************************************************
+ * Action Callbacks
+ *****************************************************************************/
+
+static void
+action_context_delete_cell_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ WebKitDOMNode *sibling;
+ WebKitDOMElement *cell;
+
+ g_return_if_fail (editor->priv->table_cell != NULL);
+
+ cell = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TD");
+ if (!cell) {
+ cell = e_html_editor_dom_node_find_parent_element (
+ editor->priv->table_cell, "TH");
+ }
+ g_return_if_fail (cell != NULL);
+
+ sibling = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (cell));
+ if (!sibling) {
+ sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (cell));
+ }
+
+ webkit_dom_node_remove_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (cell)),
+ WEBKIT_DOM_NODE (cell), NULL);
+
+ if (sibling) {
+ webkit_dom_html_table_cell_element_set_col_span (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (sibling),
+ webkit_dom_html_table_cell_element_get_col_span (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (sibling)) + 1);
+ }
+}
+
+static void
+action_context_delete_column_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ WebKitDOMElement *cell, *table;
+ WebKitDOMHTMLCollection *rows;
+ gulong index, length, ii;
+
+ g_return_if_fail (editor->priv->table_cell != NULL);
+
+ /* Find TD in which the selection starts */
+ cell = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TD");
+ if (!cell) {
+ cell = e_html_editor_dom_node_find_parent_element (
+ editor->priv->table_cell, "TH");
+ }
+ g_return_if_fail (cell != NULL);
+
+ table = e_html_editor_dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE");
+ g_return_if_fail (table != NULL);
+
+ rows = webkit_dom_html_table_element_get_rows (
+ WEBKIT_DOM_HTML_TABLE_ELEMENT (table));
+ length = webkit_dom_html_collection_get_length (rows);
+
+ index = webkit_dom_html_table_cell_element_get_cell_index (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell));
+
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *row;
+
+ row = webkit_dom_html_collection_item (rows, ii);
+
+ webkit_dom_html_table_row_element_delete_cell (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index, NULL);
+ }
+}
+
+static void
+action_context_delete_row_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ WebKitDOMElement *row;
+
+ g_return_if_fail (editor->priv->table_cell != NULL);
+
+ row = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TR");
+ g_return_if_fail (row != NULL);
+
+ webkit_dom_node_remove_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row)),
+ WEBKIT_DOM_NODE (row), NULL);
+}
+
+static void
+action_context_delete_table_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ WebKitDOMElement *table;
+
+ g_return_if_fail (editor->priv->table_cell != NULL);
+
+ table = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TABLE");
+ g_return_if_fail (table != NULL);
+
+ webkit_dom_node_remove_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (table)),
+ WEBKIT_DOM_NODE (table), NULL);
+}
+
+static void
+action_context_insert_column_after_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ WebKitDOMElement *cell, *row;
+ gulong index;
+
+ g_return_if_fail (editor->priv->table_cell != NULL);
+
+ cell = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TD");
+ if (!cell) {
+ cell = e_html_editor_dom_node_find_parent_element (
+ editor->priv->table_cell, "TH");
+ }
+ g_return_if_fail (cell != NULL);
+
+ row = e_html_editor_dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TR");
+ g_return_if_fail (row != NULL);
+
+ /* Get the first row in the table */
+ row = WEBKIT_DOM_ELEMENT (
+ webkit_dom_node_get_first_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row))));
+
+ index = webkit_dom_html_table_cell_element_get_cell_index (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell));
+
+ while (row) {
+ webkit_dom_html_table_row_element_insert_cell (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index + 1, NULL);
+
+ row = WEBKIT_DOM_ELEMENT (
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (row)));
+ }
+}
+
+static void
+action_context_insert_column_before_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ WebKitDOMElement *cell, *row;
+ gulong index;
+
+ g_return_if_fail (editor->priv->table_cell != NULL);
+
+ cell = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TD");
+ if (!cell) {
+ cell = e_html_editor_dom_node_find_parent_element (
+ editor->priv->table_cell, "TH");
+ }
+ g_return_if_fail (cell != NULL);
+
+ row = e_html_editor_dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TR");
+ g_return_if_fail (row != NULL);
+
+ /* Get the first row in the table */
+ row = WEBKIT_DOM_ELEMENT (
+ webkit_dom_node_get_first_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row))));
+
+ index = webkit_dom_html_table_cell_element_get_cell_index (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell));
+
+ while (row) {
+ webkit_dom_html_table_row_element_insert_cell (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index - 1, NULL);
+
+ row = WEBKIT_DOM_ELEMENT (
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (row)));
+ }
+}
+
+static void
+action_context_insert_row_above_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ WebKitDOMElement *row, *table;
+ WebKitDOMHTMLCollection *cells;
+ WebKitDOMHTMLElement *new_row;
+ gulong index, cell_count, ii;
+
+ g_return_if_fail (editor->priv->table_cell != NULL);
+
+ row = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TR");
+ g_return_if_fail (row != NULL);
+
+ table = e_html_editor_dom_node_find_parent_element (WEBKIT_DOM_NODE (row), "TABLE");
+ g_return_if_fail (table != NULL);
+
+ index = webkit_dom_html_table_row_element_get_row_index (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+
+ new_row = webkit_dom_html_table_element_insert_row (
+ WEBKIT_DOM_HTML_TABLE_ELEMENT (table), index, NULL);
+
+ cells = webkit_dom_html_table_row_element_get_cells (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+ cell_count = webkit_dom_html_collection_get_length (cells);
+ for (ii = 0; ii < cell_count; ii++) {
+ webkit_dom_html_table_row_element_insert_cell (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (new_row), -1, NULL);
+ }
+
+}
+
+static void
+action_context_insert_row_below_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ WebKitDOMElement *row, *table;
+ WebKitDOMHTMLCollection *cells;
+ WebKitDOMHTMLElement *new_row;
+ gulong index, cell_count, ii;
+
+ g_return_if_fail (editor->priv->table_cell != NULL);
+
+ row = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TR");
+ g_return_if_fail (row != NULL);
+
+ table = e_html_editor_dom_node_find_parent_element (WEBKIT_DOM_NODE (row), "TABLE");
+ g_return_if_fail (table != NULL);
+
+ index = webkit_dom_html_table_row_element_get_row_index (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+
+ new_row = webkit_dom_html_table_element_insert_row (
+ WEBKIT_DOM_HTML_TABLE_ELEMENT (table), index + 1, NULL);
+
+ cells = webkit_dom_html_table_row_element_get_cells (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+ cell_count = webkit_dom_html_collection_get_length (cells);
+ for (ii = 0; ii < cell_count; ii++) {
+ webkit_dom_html_table_row_element_insert_cell (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (new_row), -1, NULL);
+ }
+}
+
+static void
+action_context_remove_link_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ EHTMLEditorView *view;
+ EHTMLEditorSelection *selection;
+
+ view = e_html_editor_get_view (editor);
+ selection = e_html_editor_view_get_selection (view);
+
+ e_html_editor_selection_unlink (selection);
+}
+
+static void
+action_context_spell_add_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ ESpellChecker *spell_checker;
+ EHTMLEditorSelection *selection;
+ gchar *word;
+
+ spell_checker = e_html_editor_view_get_spell_checker (
+ editor->priv->html_editor_view);
+ selection = e_html_editor_view_get_selection (editor->priv->html_editor_view);
+
+ word = e_html_editor_selection_get_caret_word (selection);
+ if (word && *word) {
+ e_spell_checker_learn_word (spell_checker, word);
+ }
+}
+
+static void
+action_context_spell_ignore_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ ESpellChecker *spell_checker;
+ EHTMLEditorSelection *selection;
+ gchar *word;
+
+ spell_checker = e_html_editor_view_get_spell_checker (
+ editor->priv->html_editor_view);
+ selection = e_html_editor_view_get_selection (editor->priv->html_editor_view);
+
+ word = e_html_editor_selection_get_caret_word (selection);
+ if (word && *word) {
+ e_spell_checker_ignore_word (spell_checker, word);
+ }
+}
+
+static void
+action_copy_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ webkit_web_view_copy_clipboard (
+ WEBKIT_WEB_VIEW (e_html_editor_get_view (editor)));
+}
+
+static void
+action_cut_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ webkit_web_view_cut_clipboard (
+ WEBKIT_WEB_VIEW (e_html_editor_get_view (editor)));
+}
+
+static void
+action_indent_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ e_html_editor_selection_indent (editor->priv->selection);
+}
+
+static void
+action_insert_emoticon_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ EHTMLEditorView *view;
+ EEmoticon *emoticon;
+
+ emoticon = e_emoticon_chooser_get_current_emoticon (
+ E_EMOTICON_CHOOSER (action));
+ g_return_if_fail (emoticon != NULL);
+
+ view = e_html_editor_get_view (editor);
+ e_html_editor_view_insert_smiley (view, emoticon);
+}
+
+static void
+action_insert_html_file_cb (GtkToggleAction *action,
+ EHTMLEditor *editor)
+{
+ GtkWidget *dialog;
+ GtkFileFilter *filter;
+
+ dialog = gtk_file_chooser_dialog_new (
+ _("Insert HTML File"), NULL,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("HTML file"));
+ gtk_file_filter_add_mime_type (filter, "text/html");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
+ GFile *file;
+
+ file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
+
+ /* XXX Need a way to cancel this. */
+ g_file_load_contents_async (
+ file, NULL, (GAsyncReadyCallback)
+ insert_html_file_ready_cb,
+ g_object_ref (editor));
+
+ g_object_unref (file);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+action_insert_image_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ GtkWidget *dialog;
+
+ dialog = e_image_chooser_dialog_new (_("Insert Image"), NULL);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
+ EHTMLEditorView *view;
+ EHTMLEditorSelection *selection;
+ gchar *uri;
+
+ uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
+
+ view = e_html_editor_get_view (editor);
+ selection = e_html_editor_view_get_selection (view);
+ e_html_editor_selection_insert_image (selection, uri);
+
+ g_free (uri);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+action_insert_link_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->link_dialog == NULL)
+ editor->priv->link_dialog =
+ e_html_editor_link_dialog_new (editor);
+
+ gtk_window_present (GTK_WINDOW (editor->priv->link_dialog));
+}
+
+static void
+action_insert_rule_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->hrule_dialog == NULL)
+ editor->priv->hrule_dialog =
+ e_html_editor_hrule_dialog_new (editor);
+
+ gtk_window_present (GTK_WINDOW (editor->priv->hrule_dialog));
+}
+
+static void
+action_insert_table_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->table_dialog == NULL)
+ editor->priv->table_dialog =
+ e_html_editor_table_dialog_new (editor);
+
+ gtk_window_present (GTK_WINDOW (editor->priv->table_dialog));
+}
+
+static void
+action_insert_text_file_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ GtkWidget *dialog;
+ GtkFileFilter *filter;
+
+ dialog = gtk_file_chooser_dialog_new (
+ _("Insert text file"), NULL,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("Text file"));
+ gtk_file_filter_add_mime_type (filter, "text/plain");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
+ GFile *file;
+
+ file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
+
+ /* XXX Need a way to cancel this. */
+ g_file_load_contents_async (
+ file, NULL, (GAsyncReadyCallback)
+ insert_text_file_ready_cb,
+ g_object_ref (editor));
+
+ g_object_unref (file);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+action_language_cb (GtkToggleAction *toggle_action,
+ EHTMLEditor *editor)
+{
+ ESpellChecker *checker;
+ EHTMLEditorView *view;
+ const gchar *language_code;
+ GtkAction *add_action;
+ gchar *action_name;
+ gboolean active;
+
+ view = e_html_editor_get_view (editor);
+ checker = e_html_editor_view_get_spell_checker (view);
+ language_code = gtk_action_get_name (GTK_ACTION (toggle_action));
+
+ active = gtk_toggle_action_get_active (toggle_action);
+ e_spell_checker_set_language_active (checker, language_code, active);
+
+ /* Update "Add Word To" context menu item visibility. */
+ action_name = g_strdup_printf ("context-spell-add-%s", language_code);
+ add_action = e_html_editor_get_action (editor, action_name);
+ gtk_action_set_visible (add_action, active);
+ g_free (action_name);
+
+ editor_update_static_spell_actions (editor);
+
+ g_signal_emit_by_name (editor, "spell-languages-changed");
+}
+
+static gboolean
+update_mode_combobox (gpointer data)
+{
+ EHTMLEditor *editor = data;
+ EHTMLEditorView *view;
+ GtkAction *action;
+ gboolean is_html;
+
+ if (!E_IS_HTML_EDITOR (editor))
+ return FALSE;
+
+ view = e_html_editor_get_view (editor);
+ is_html = e_html_editor_view_get_html_mode (view);
+
+ action = gtk_action_group_get_action (
+ editor->priv->core_actions, "mode-html");
+ gtk_radio_action_set_current_value (
+ GTK_RADIO_ACTION (action), (is_html ? 1 : 0));
+
+ return FALSE;
+}
+
+static void
+action_mode_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EHTMLEditor *editor)
+{
+ GtkActionGroup *action_group;
+ EHTMLEditorView *view;
+ GtkWidget *style_combo_box;
+ gboolean is_html;
+
+ view = e_html_editor_get_view (editor);
+ is_html = e_html_editor_view_get_html_mode (view);
+
+ /* This must be done from idle callback, because apparently we can change
+ * current value in callback of current value change */
+ g_idle_add (update_mode_combobox, editor);
+
+ action_group = editor->priv->html_actions;
+ gtk_action_group_set_sensitive (action_group, is_html);
+
+ action_group = editor->priv->html_context_actions;
+ gtk_action_group_set_visible (action_group, is_html);
+
+ gtk_widget_set_sensitive (editor->priv->color_combo_box, is_html);
+
+ if (is_html) {
+ gtk_widget_show (editor->priv->html_toolbar);
+ } else {
+ gtk_widget_hide (editor->priv->html_toolbar);
+ }
+
+ /* Certain paragraph styles are HTML-only. */
+ gtk_action_set_sensitive (ACTION (STYLE_H1), is_html);
+ gtk_action_set_visible (ACTION (STYLE_H1), is_html);
+ gtk_action_set_sensitive (ACTION (STYLE_H2), is_html);
+ gtk_action_set_visible (ACTION (STYLE_H2), is_html);
+ gtk_action_set_sensitive (ACTION (STYLE_H3), is_html);
+ gtk_action_set_visible (ACTION (STYLE_H3), is_html);
+ gtk_action_set_sensitive (ACTION (STYLE_H4), is_html);
+ gtk_action_set_visible (ACTION (STYLE_H4), is_html);
+ gtk_action_set_sensitive (ACTION (STYLE_H5), is_html);
+ gtk_action_set_visible (ACTION (STYLE_H5), is_html);
+ gtk_action_set_sensitive (ACTION (STYLE_H6), is_html);
+ gtk_action_set_visible (ACTION (STYLE_H6), is_html);
+ gtk_action_set_sensitive (ACTION (STYLE_ADDRESS), is_html);
+ gtk_action_set_visible (ACTION (STYLE_ADDRESS), is_html);
+
+ /* Hide them from the action combo box as well */
+ style_combo_box = e_html_editor_get_style_combo_box (editor);
+ e_action_combo_box_update_model (E_ACTION_COMBO_BOX (style_combo_box));
+}
+
+static void
+action_paste_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ EHTMLEditorView *view = e_html_editor_get_view (editor);
+
+ /* Paste only if WebView has focus */
+ if (gtk_widget_has_focus (GTK_WIDGET (view))) {
+ webkit_web_view_paste_clipboard (
+ WEBKIT_WEB_VIEW (view));
+
+ e_html_editor_view_force_spell_check (view);
+ }
+}
+
+static void
+action_paste_quote_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ e_html_editor_view_paste_clipboard_quoted (
+ e_html_editor_get_view (editor));
+
+ e_html_editor_view_force_spell_check (
+ e_html_editor_get_view (editor));
+}
+
+static void
+action_properties_cell_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->cell_dialog == NULL) {
+ editor->priv->cell_dialog =
+ e_html_editor_cell_dialog_new (editor);
+ }
+
+ e_html_editor_cell_dialog_show (
+ E_HTML_EDITOR_CELL_DIALOG (editor->priv->cell_dialog),
+ editor->priv->table_cell);
+}
+
+static void
+action_properties_image_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->image_dialog == NULL) {
+ editor->priv->image_dialog =
+ e_html_editor_image_dialog_new (editor);
+ }
+
+ e_html_editor_image_dialog_show (
+ E_HTML_EDITOR_IMAGE_DIALOG (editor->priv->image_dialog),
+ editor->priv->image);
+}
+
+static void
+action_properties_link_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->link_dialog == NULL) {
+ editor->priv->link_dialog =
+ e_html_editor_link_dialog_new (editor);
+ }
+
+ gtk_window_present (GTK_WINDOW (editor->priv->link_dialog));
+}
+
+static void
+action_properties_page_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->page_dialog == NULL) {
+ editor->priv->page_dialog =
+ e_html_editor_page_dialog_new (editor);
+ }
+
+ gtk_window_present (GTK_WINDOW (editor->priv->page_dialog));
+}
+
+static void
+action_properties_paragraph_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->paragraph_dialog == NULL) {
+ editor->priv->paragraph_dialog =
+ e_html_editor_paragraph_dialog_new (editor);
+ }
+
+ gtk_window_present (GTK_WINDOW (editor->priv->paragraph_dialog));
+}
+
+static void
+action_properties_rule_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->hrule_dialog == NULL) {
+ editor->priv->hrule_dialog =
+ e_html_editor_hrule_dialog_new (editor);
+ }
+
+ gtk_window_present (GTK_WINDOW (editor->priv->hrule_dialog));
+}
+
+static void
+action_properties_table_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->table_dialog == NULL) {
+ editor->priv->table_dialog =
+ e_html_editor_table_dialog_new (editor);
+ }
+
+ gtk_window_present (GTK_WINDOW (editor->priv->table_dialog));
+}
+
+static void
+action_properties_text_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->text_dialog == NULL) {
+ editor->priv->text_dialog =
+ e_html_editor_text_dialog_new (editor);
+ }
+
+ gtk_window_present (GTK_WINDOW (editor->priv->text_dialog));
+}
+
+static void
+action_redo_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ webkit_web_view_redo (
+ WEBKIT_WEB_VIEW (e_html_editor_get_view (editor)));
+}
+
+static void
+action_select_all_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ webkit_web_view_select_all (
+ WEBKIT_WEB_VIEW (e_html_editor_get_view (editor)));
+}
+
+static void
+action_show_find_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->find_dialog == NULL) {
+ editor->priv->find_dialog = e_html_editor_find_dialog_new (editor);
+ gtk_action_set_sensitive (ACTION (FIND_AGAIN), TRUE);
+ }
+
+ gtk_window_present (GTK_WINDOW (editor->priv->find_dialog));
+}
+
+static void
+action_find_again_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->find_dialog == NULL) {
+ return;
+ }
+
+ e_html_editor_find_dialog_find_next (
+ E_HTML_EDITOR_FIND_DIALOG (editor->priv->find_dialog));
+}
+
+static void
+action_show_replace_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->replace_dialog == NULL) {
+ editor->priv->replace_dialog =
+ e_html_editor_replace_dialog_new (editor);
+ }
+
+ gtk_window_present (GTK_WINDOW (editor->priv->replace_dialog));
+}
+
+static void
+action_spell_check_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ if (editor->priv->spell_check_dialog == NULL) {
+ editor->priv->spell_check_dialog =
+ e_html_editor_spell_check_dialog_new (editor);
+ }
+
+ gtk_window_present (GTK_WINDOW (editor->priv->spell_check_dialog));
+}
+
+static void
+action_undo_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ webkit_web_view_undo (
+ WEBKIT_WEB_VIEW (e_html_editor_get_view (editor)));
+}
+
+static void
+action_unindent_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ e_html_editor_selection_unindent (editor->priv->selection);
+}
+
+static void
+action_wrap_lines_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ e_html_editor_selection_wrap_lines (editor->priv->selection);
+}
+
+static void
+action_show_webkit_inspector_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ WebKitWebInspector *inspector;
+ EHTMLEditorView *view;
+
+ view = e_html_editor_get_view (editor);
+ inspector = webkit_web_view_get_inspector (WEBKIT_WEB_VIEW (view));
+
+ webkit_web_inspector_show (inspector);
+}
+
+/*****************************************************************************
+ * Core Actions
+ *
+ * These actions are always enabled.
+ *****************************************************************************/
+
+static GtkActionEntry core_entries[] = {
+
+ { "copy",
+ GTK_STOCK_COPY,
+ N_("_Copy"),
+ "<Control>c",
+ N_("Copy selected text to the clipboard"),
+ G_CALLBACK (action_copy_cb) },
+
+ { "cut",
+ GTK_STOCK_CUT,
+ N_("Cu_t"),
+ "<Control>x",
+ N_("Cut selected text to the clipboard"),
+ G_CALLBACK (action_cut_cb) },
+
+ { "indent",
+ GTK_STOCK_INDENT,
+ N_("_Increase Indent"),
+ "<Control>bracketright",
+ N_("Increase Indent"),
+ G_CALLBACK (action_indent_cb) },
+
+ { "insert-html-file",
+ NULL,
+ N_("_HTML File..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_insert_html_file_cb) },
+
+ { "insert-text-file",
+ NULL,
+ N_("Te_xt File..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_insert_text_file_cb) },
+
+ { "paste",
+ GTK_STOCK_PASTE,
+ N_("_Paste"),
+ "<Control>v",
+ N_("Paste text from the clipboard"),
+ G_CALLBACK (action_paste_cb) },
+
+ { "paste-quote",
+ NULL,
+ N_("Paste _Quotation"),
+ "<Shift><Control>v",
+ NULL,
+ G_CALLBACK (action_paste_quote_cb) },
+
+ { "redo",
+ GTK_STOCK_REDO,
+ N_("_Redo"),
+ "<Shift><Control>z",
+ N_("Redo the last undone action"),
+ G_CALLBACK (action_redo_cb) },
+
+ { "select-all",
+ GTK_STOCK_SELECT_ALL,
+ N_("Select _All"),
+ "<Control>a",
+ NULL,
+ G_CALLBACK (action_select_all_cb) },
+
+ { "show-find",
+ GTK_STOCK_FIND,
+ N_("_Find..."),
+ "<Control>f",
+ N_("Search for text"),
+ G_CALLBACK (action_show_find_cb) },
+
+ { "find-again",
+ NULL,
+ N_("Find A_gain"),
+ "<Control>g",
+ NULL,
+ G_CALLBACK (action_find_again_cb) },
+
+ { "show-replace",
+ GTK_STOCK_FIND_AND_REPLACE,
+ N_("Re_place..."),
+ "<Control>h",
+ N_("Search for and replace text"),
+ G_CALLBACK (action_show_replace_cb) },
+
+ { "spell-check",
+ GTK_STOCK_SPELL_CHECK,
+ N_("Check _Spelling..."),
+ "F7",
+ NULL,
+ G_CALLBACK (action_spell_check_cb) },
+
+ { "undo",
+ GTK_STOCK_UNDO,
+ N_("_Undo"),
+ "<Control>z",
+ N_("Undo the last action"),
+ G_CALLBACK (action_undo_cb) },
+
+ { "unindent",
+ GTK_STOCK_UNINDENT,
+ N_("_Decrease Indent"),
+ "<Control>bracketleft",
+ N_("Decrease Indent"),
+ G_CALLBACK (action_unindent_cb) },
+
+ { "wrap-lines",
+ NULL,
+ N_("_Wrap Lines"),
+ "<Control>k",
+ NULL,
+ G_CALLBACK (action_wrap_lines_cb) },
+
+ { "webkit-inspector",
+ NULL,
+ N_("Open Inspector"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_show_webkit_inspector_cb) },
+
+ /* Menus */
+
+ { "edit-menu",
+ NULL,
+ N_("_Edit"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "file-menu",
+ NULL,
+ N_("_File"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "format-menu",
+ NULL,
+ N_("For_mat"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "paragraph-style-menu",
+ NULL,
+ N_("_Paragraph Style"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "insert-menu",
+ NULL,
+ N_("_Insert"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "justify-menu",
+ NULL,
+ N_("_Alignment"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "language-menu",
+ NULL,
+ N_("Current _Languages"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "view-menu",
+ NULL,
+ N_("_View"),
+ NULL,
+ NULL,
+ NULL }
+};
+
+static GtkRadioActionEntry core_justify_entries[] = {
+
+ { "justify-center",
+ GTK_STOCK_JUSTIFY_CENTER,
+ N_("_Center"),
+ "<Control>e",
+ N_("Center Alignment"),
+ E_HTML_EDITOR_SELECTION_ALIGNMENT_CENTER },
+
+ { "justify-left",
+ GTK_STOCK_JUSTIFY_LEFT,
+ N_("_Left"),
+ "<Control>l",
+ N_("Left Alignment"),
+ E_HTML_EDITOR_SELECTION_ALIGNMENT_LEFT },
+
+ { "justify-right",
+ GTK_STOCK_JUSTIFY_RIGHT,
+ N_("_Right"),
+ "<Control>r",
+ N_("Right Alignment"),
+ E_HTML_EDITOR_SELECTION_ALIGNMENT_RIGHT }
+};
+
+static GtkRadioActionEntry core_mode_entries[] = {
+
+ { "mode-html",
+ NULL,
+ N_("_HTML"),
+ NULL,
+ N_("HTML editing mode"),
+ TRUE }, /* e_html_editor_view_set_html_mode */
+
+ { "mode-plain",
+ NULL,
+ N_("Plain _Text"),
+ NULL,
+ N_("Plain text editing mode"),
+ FALSE } /* e_html_editor_view_set_html_mode */
+};
+
+static GtkRadioActionEntry core_style_entries[] = {
+
+ { "style-normal",
+ NULL,
+ N_("_Normal"),
+ "<Control>0",
+ NULL,
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_PARAGRAPH },
+
+ { "style-h1",
+ NULL,
+ N_("Header _1"),
+ "<Control>1",
+ NULL,
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H1 },
+
+ { "style-h2",
+ NULL,
+ N_("Header _2"),
+ "<Control>2",
+ NULL,
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H2 },
+
+ { "style-h3",
+ NULL,
+ N_("Header _3"),
+ "<Control>3",
+ NULL,
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H3 },
+
+ { "style-h4",
+ NULL,
+ N_("Header _4"),
+ "<Control>4",
+ NULL,
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H4 },
+
+ { "style-h5",
+ NULL,
+ N_("Header _5"),
+ "<Control>5",
+ NULL,
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H5 },
+
+ { "style-h6",
+ NULL,
+ N_("Header _6"),
+ "<Control>6",
+ NULL,
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H6 },
+
+ { "style-preformat",
+ NULL,
+ N_("_Preformatted"),
+ "<Control>7",
+ NULL,
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_PRE },
+
+ { "style-address",
+ NULL,
+ N_("A_ddress"),
+ "<Control>8",
+ NULL,
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_ADDRESS },
+
+ { "style-blockquote",
+ NULL,
+ N_("_Blockquote"),
+ "<Control>9",
+ NULL,
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_BLOCKQUOTE },
+
+ { "style-list-bullet",
+ NULL,
+ N_("_Bulleted List"),
+ NULL,
+ NULL,
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_UNORDERED_LIST },
+
+ { "style-list-roman",
+ NULL,
+ N_("_Roman Numeral List"),
+ NULL,
+ NULL,
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_ORDERED_LIST_ROMAN },
+
+ { "style-list-number",
+ NULL,
+ N_("Numbered _List"),
+ NULL,
+ NULL,
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_ORDERED_LIST },
+
+ { "style-list-alpha",
+ NULL,
+ N_("_Alphabetical List"),
+ NULL,
+ NULL,
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_ORDERED_LIST_ALPHA }
+};
+
+/*****************************************************************************
+ * Core Actions (HTML only)
+ *
+ * These actions are only enabled in HTML mode.
+ *****************************************************************************/
+
+static GtkActionEntry html_entries[] = {
+
+ { "insert-image",
+ "insert-image",
+ N_("_Image..."),
+ NULL,
+ N_("Insert Image"),
+ G_CALLBACK (action_insert_image_cb) },
+
+ { "insert-link",
+ "insert-link",
+ N_("_Link..."),
+ NULL,
+ N_("Insert Link"),
+ G_CALLBACK (action_insert_link_cb) },
+
+ { "insert-rule",
+ "stock_insert-rule",
+ /* Translators: 'Rule' here means a horizontal line in an HTML text */
+ N_("_Rule..."),
+ NULL,
+ /* Translators: 'Rule' here means a horizontal line in an HTML text */
+ N_("Insert Rule"),
+ G_CALLBACK (action_insert_rule_cb) },
+
+ { "insert-table",
+ "stock_insert-table",
+ N_("_Table..."),
+ NULL,
+ N_("Insert Table"),
+ G_CALLBACK (action_insert_table_cb) },
+
+ { "properties-cell",
+ NULL,
+ N_("_Cell..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_properties_cell_cb) },
+
+ { "properties-image",
+ NULL,
+ N_("_Image..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_properties_image_cb) },
+
+ { "properties-link",
+ NULL,
+ N_("_Link..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_properties_link_cb) },
+
+ { "properties-page",
+ NULL,
+ N_("Pa_ge..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_properties_page_cb) },
+
+ { "properties-rule",
+ NULL,
+ /* Translators: 'Rule' here means a horizontal line in an HTML text */
+ N_("_Rule..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_properties_rule_cb) },
+
+ { "properties-table",
+ NULL,
+ N_("_Table..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_properties_table_cb) },
+
+ /* Menus */
+
+ { "font-size-menu",
+ NULL,
+ N_("Font _Size"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "font-style-menu",
+ NULL,
+ N_("_Font Style"),
+ NULL,
+ NULL,
+ NULL },
+};
+
+static GtkToggleActionEntry html_toggle_entries[] = {
+
+ { "bold",
+ GTK_STOCK_BOLD,
+ N_("_Bold"),
+ "<Control>b",
+ N_("Bold"),
+ NULL,
+ FALSE },
+
+ { "italic",
+ GTK_STOCK_ITALIC,
+ N_("_Italic"),
+ "<Control>i",
+ N_("Italic"),
+ NULL,
+ FALSE },
+
+ { "monospaced",
+ "stock_text-monospaced",
+ N_("_Plain Text"),
+ "<Control>t",
+ N_("Plain Text"),
+ NULL,
+ FALSE },
+
+ { "strikethrough",
+ GTK_STOCK_STRIKETHROUGH,
+ N_("_Strikethrough"),
+ NULL,
+ N_("Strikethrough"),
+ NULL,
+ FALSE },
+
+ { "underline",
+ GTK_STOCK_UNDERLINE,
+ N_("_Underline"),
+ "<Control>u",
+ N_("Underline"),
+ NULL,
+ FALSE }
+};
+
+static GtkRadioActionEntry html_size_entries[] = {
+
+ { "size-minus-two",
+ NULL,
+ /* Translators: This is a font size level. It is shown on a tool bar. Please keep it as short as possible. */
+ N_("-2"),
+ NULL,
+ NULL,
+ E_HTML_EDITOR_SELECTION_FONT_SIZE_TINY },
+
+ { "size-minus-one",
+ NULL,
+ /* Translators: This is a font size level. It is shown on a tool bar. Please keep it as short as possible. */
+ N_("-1"),
+ NULL,
+ NULL,
+ E_HTML_EDITOR_SELECTION_FONT_SIZE_SMALL },
+
+ { "size-plus-zero",
+ NULL,
+ /* Translators: This is a font size level. It is shown on a tool bar. Please keep it as short as possible. */
+ N_("+0"),
+ NULL,
+ NULL,
+ E_HTML_EDITOR_SELECTION_FONT_SIZE_NORMAL },
+
+ { "size-plus-one",
+ NULL,
+ /* Translators: This is a font size level. It is shown on a tool bar. Please keep it as short as possible. */
+ N_("+1"),
+ NULL,
+ NULL,
+ E_HTML_EDITOR_SELECTION_FONT_SIZE_BIG },
+
+ { "size-plus-two",
+ NULL,
+ /* Translators: This is a font size level. It is shown on a tool bar. Please keep it as short as possible. */
+ N_("+2"),
+ NULL,
+ NULL,
+ E_HTML_EDITOR_SELECTION_FONT_SIZE_BIGGER },
+
+ { "size-plus-three",
+ NULL,
+ /* Translators: This is a font size level. It is shown on a tool bar. Please keep it as short as possible. */
+ N_("+3"),
+ NULL,
+ NULL,
+ E_HTML_EDITOR_SELECTION_FONT_SIZE_LARGE },
+
+ { "size-plus-four",
+ NULL,
+ /* Translators: This is a font size level. It is shown on a tool bar. Please keep it as short as possible. */
+ N_("+4"),
+ NULL,
+ NULL,
+ E_HTML_EDITOR_SELECTION_FONT_SIZE_VERY_LARGE }
+};
+
+/*****************************************************************************
+ * Context Menu Actions
+ *
+ * These require separate action entries so we can toggle their visiblity
+ * rather than their sensitivity as we do with main menu / toolbar actions.
+ * Note that some of these actions use the same callback function as their
+ * non-context sensitive counterparts.
+ *****************************************************************************/
+
+static GtkActionEntry context_entries[] = {
+
+ { "context-delete-cell",
+ NULL,
+ N_("Cell Contents"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_context_delete_cell_cb) },
+
+ { "context-delete-column",
+ NULL,
+ N_("Column"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_context_delete_column_cb) },
+
+ { "context-delete-row",
+ NULL,
+ N_("Row"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_context_delete_row_cb) },
+
+ { "context-delete-table",
+ NULL,
+ N_("Table"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_context_delete_table_cb) },
+
+ /* Menus */
+
+ { "context-delete-table-menu",
+ NULL,
+ /* Translators: Popup menu item caption, containing all the Delete options for a table */
+ N_("Table Delete"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "context-input-methods-menu",
+ NULL,
+ N_("Input Methods"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "context-insert-table-menu",
+ NULL,
+ /* Translators: Popup menu item caption, containing all the Insert options for a table */
+ N_("Table Insert"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "context-properties-menu",
+ NULL,
+ N_("Properties"),
+ NULL,
+ NULL,
+ NULL },
+};
+
+/*****************************************************************************
+ * Context Menu Actions (HTML only)
+ *
+ * These actions are never visible in plain-text mode. Note that some
+ * of them use the same callback function as their non-context sensitive
+ * counterparts.
+ *****************************************************************************/
+
+static GtkActionEntry html_context_entries[] = {
+
+ { "context-insert-column-after",
+ NULL,
+ N_("Column After"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_context_insert_column_after_cb) },
+
+ { "context-insert-column-before",
+ NULL,
+ N_("Column Before"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_context_insert_column_before_cb) },
+
+ { "context-insert-link",
+ NULL,
+ N_("Insert _Link"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_insert_link_cb) },
+
+ { "context-insert-row-above",
+ NULL,
+ N_("Row Above"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_context_insert_row_above_cb) },
+
+ { "context-insert-row-below",
+ NULL,
+ N_("Row Below"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_context_insert_row_below_cb) },
+
+ { "context-insert-table",
+ NULL,
+ N_("Table"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_insert_table_cb) },
+
+ { "context-properties-cell",
+ NULL,
+ N_("Cell..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_properties_cell_cb) },
+
+ { "context-properties-image",
+ NULL,
+ N_("Image..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_properties_image_cb) },
+
+ { "context-properties-link",
+ NULL,
+ N_("Link..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_properties_link_cb) },
+
+ { "context-properties-page",
+ NULL,
+ N_("Page..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_properties_page_cb) },
+
+ { "context-properties-paragraph",
+ NULL,
+ N_("Paragraph..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_properties_paragraph_cb) },
+
+ { "context-properties-rule",
+ NULL,
+ /* Translators: 'Rule' here means a horizontal line in an HTML text */
+ N_("Rule..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_properties_rule_cb) },
+
+ { "context-properties-table",
+ NULL,
+ N_("Table..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_properties_table_cb) },
+
+ { "context-properties-text",
+ NULL,
+ N_("Text..."),
+ NULL,
+ NULL,
+ G_CALLBACK (action_properties_text_cb) },
+
+ { "context-remove-link",
+ NULL,
+ N_("Remove Link"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_context_remove_link_cb) }
+};
+
+/*****************************************************************************
+ * Context Menu Actions (spell checking only)
+ *
+ * These actions are only visible when the word underneath the cursor is
+ * misspelled.
+ *****************************************************************************/
+
+static GtkActionEntry spell_context_entries[] = {
+
+ { "context-spell-add",
+ NULL,
+ N_("Add Word to Dictionary"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_context_spell_add_cb) },
+
+ { "context-spell-ignore",
+ NULL,
+ N_("Ignore Misspelled Word"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_context_spell_ignore_cb) },
+
+ { "context-spell-add-menu",
+ NULL,
+ N_("Add Word To"),
+ NULL,
+ NULL,
+ NULL },
+
+ /* Menus */
+
+ { "context-more-suggestions-menu",
+ NULL,
+ N_("More Suggestions"),
+ NULL,
+ NULL,
+ NULL }
+};
+
+static void
+editor_actions_setup_languages_menu (EHTMLEditor *editor)
+{
+ ESpellChecker *checker;
+ EHTMLEditorView *view;
+ GtkUIManager *manager;
+ GtkActionGroup *action_group;
+ GList *list, *link;
+ guint merge_id;
+
+ manager = editor->priv->manager;
+ action_group = editor->priv->language_actions;
+ view = e_html_editor_get_view (editor);
+ checker = e_html_editor_view_get_spell_checker (view);
+ merge_id = gtk_ui_manager_new_merge_id (manager);
+
+ list = e_spell_checker_list_available_dicts (checker);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ESpellDictionary *dictionary = link->data;
+ GtkToggleAction *action;
+ gboolean active;
+
+ action = gtk_toggle_action_new (
+ e_spell_dictionary_get_code (dictionary),
+ e_spell_dictionary_get_name (dictionary),
+ NULL, NULL);
+
+ /* Do this BEFORE connecting to the "toggled" signal.
+ * We're not prepared to invoke the signal handler yet.
+ * The "Add Word To" actions have not yet been added. */
+ active = e_spell_checker_get_language_active (
+ checker, e_spell_dictionary_get_code (dictionary));
+ gtk_toggle_action_set_active (action, active);
+
+ g_signal_connect (
+ action, "toggled",
+ G_CALLBACK (action_language_cb), editor);
+
+ gtk_action_group_add_action (
+ action_group, GTK_ACTION (action));
+
+ g_object_unref (action);
+
+ gtk_ui_manager_add_ui (
+ manager, merge_id,
+ "/main-menu/edit-menu/language-menu",
+ e_spell_dictionary_get_code (dictionary),
+ e_spell_dictionary_get_code (dictionary),
+ GTK_UI_MANAGER_AUTO, FALSE);
+ }
+
+ g_list_free (list);
+}
+
+static void
+editor_actions_setup_spell_check_menu (EHTMLEditor *editor)
+{
+ ESpellChecker *checker;
+ GtkUIManager *manager;
+ GtkActionGroup *action_group;
+ GList *available_dicts, *iter;
+ guint merge_id;
+
+ manager = editor->priv->manager;
+ action_group = editor->priv->spell_check_actions;;
+ checker = e_html_editor_view_get_spell_checker (editor->priv->html_editor_view);
+ available_dicts = e_spell_checker_list_available_dicts (checker);
+ merge_id = gtk_ui_manager_new_merge_id (manager);
+
+ for (iter = available_dicts; iter; iter = iter->next) {
+ ESpellDictionary *dictionary = iter->data;
+ GtkAction *action;
+ const gchar *code;
+ const gchar *name;
+ gchar *action_label;
+ gchar *action_name;
+
+ code = e_spell_dictionary_get_code (dictionary);
+ name = e_spell_dictionary_get_name (dictionary);
+
+ /* Add a suggestion menu. */
+ action_name = g_strdup_printf (
+ "context-spell-suggest-%s-menu", code);
+
+ action = gtk_action_new (action_name, name, NULL, NULL);
+ gtk_action_group_add_action (action_group, action);
+ g_object_unref (action);
+
+ gtk_ui_manager_add_ui (
+ manager, merge_id,
+ "/context-menu/context-spell-suggest",
+ action_name, action_name,
+ GTK_UI_MANAGER_MENU, FALSE);
+
+ g_free (action_name);
+
+ /* Add an item to the "Add Word To" menu. */
+ action_name = g_strdup_printf ("context-spell-add-%s", code);
+ /* Translators: %s will be replaced with the actual dictionary
+ * name, where a user can add a word to. This is part of an
+ * "Add Word To" submenu. */
+ action_label = g_strdup_printf (_("%s Dictionary"), name);
+
+ action = gtk_action_new (
+ action_name, action_label, NULL, NULL);
+
+ g_signal_connect (
+ action, "activate",
+ G_CALLBACK (action_context_spell_add_cb), editor);
+
+ /* Visibility is dependent on whether the
+ * corresponding language action is active. */
+ gtk_action_set_visible (action, FALSE);
+
+ gtk_action_group_add_action (action_group, action);
+
+ g_object_unref (action);
+
+ gtk_ui_manager_add_ui (
+ manager, merge_id,
+ "/context-menu/context-spell-add-menu",
+ action_name, action_name,
+ GTK_UI_MANAGER_AUTO, FALSE);
+
+ g_free (action_label);
+ g_free (action_name);
+ }
+
+ g_list_free (available_dicts);
+}
+
+void
+editor_actions_init (EHTMLEditor *editor)
+{
+ GtkAction *action;
+ GtkActionGroup *action_group;
+ GtkUIManager *manager;
+ const gchar *domain;
+ EHTMLEditorView *view;
+ GSettings *settings;
+
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+
+ manager = e_html_editor_get_ui_manager (editor);
+ domain = GETTEXT_PACKAGE;
+ view = e_html_editor_get_view (editor);
+
+ /* Core Actions */
+ action_group = editor->priv->core_actions;
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_action_group_add_actions (
+ action_group, core_entries,
+ G_N_ELEMENTS (core_entries), editor);
+ gtk_action_group_add_radio_actions (
+ action_group, core_justify_entries,
+ G_N_ELEMENTS (core_justify_entries),
+ E_HTML_EDITOR_SELECTION_ALIGNMENT_LEFT,
+ NULL, NULL);
+ gtk_action_group_add_radio_actions (
+ action_group, core_mode_entries,
+ G_N_ELEMENTS (core_mode_entries),
+ TRUE,
+ G_CALLBACK (action_mode_cb), editor);
+ gtk_action_group_add_radio_actions (
+ action_group, core_style_entries,
+ G_N_ELEMENTS (core_style_entries),
+ E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_PARAGRAPH,
+ NULL, NULL);
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+ action = gtk_action_group_get_action (action_group, "mode-html");
+ g_object_bind_property (
+ view, "html-mode",
+ action, "current-value",
+ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+
+ /* Synchronize wiget mode with the buttons */
+ e_html_editor_view_set_html_mode (view, TRUE);
+
+ /* Face Action */
+ action = e_emoticon_action_new (
+ "insert-emoticon", _("_Emoticon"),
+ _("Insert Emoticon"), NULL);
+ g_object_set (action, "icon-name", "face-smile", NULL);
+ g_signal_connect (
+ action, "item-activated",
+ G_CALLBACK (action_insert_emoticon_cb), editor);
+ gtk_action_group_add_action (action_group, action);
+ g_object_unref (action);
+
+ /* Core Actions (HTML only) */
+ action_group = editor->priv->html_actions;
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_action_group_add_actions (
+ action_group, html_entries,
+ G_N_ELEMENTS (html_entries), editor);
+ gtk_action_group_add_toggle_actions (
+ action_group, html_toggle_entries,
+ G_N_ELEMENTS (html_toggle_entries), editor);
+ gtk_action_group_add_radio_actions (
+ action_group, html_size_entries,
+ G_N_ELEMENTS (html_size_entries),
+ E_HTML_EDITOR_SELECTION_FONT_SIZE_NORMAL,
+ NULL, NULL);
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+ /* Context Menu Actions */
+ action_group = editor->priv->context_actions;
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_action_group_add_actions (
+ action_group, context_entries,
+ G_N_ELEMENTS (context_entries), editor);
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+ /* Context Menu Actions (HTML only) */
+ action_group = editor->priv->html_context_actions;
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_action_group_add_actions (
+ action_group, html_context_entries,
+ G_N_ELEMENTS (html_context_entries), editor);
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+ /* Context Menu Actions (spell check only) */
+ action_group = editor->priv->spell_check_actions;
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_action_group_add_actions (
+ action_group, spell_context_entries,
+ G_N_ELEMENTS (spell_context_entries), editor);
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+ /* Language actions are generated dynamically. */
+ editor_actions_setup_languages_menu (editor);
+ action_group = editor->priv->language_actions;
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+ /* Some spell check actions are generated dynamically. */
+ action_group = editor->priv->suggestion_actions;
+ editor_actions_setup_spell_check_menu (editor);
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+ /* Do this after all language actions are initialized. */
+ editor_update_static_spell_actions (editor);
+
+ /* Fine Tuning */
+
+ g_object_set (
+ G_OBJECT (ACTION (SHOW_FIND)),
+ "short-label", _("_Find"), NULL);
+ g_object_set (
+ G_OBJECT (ACTION (SHOW_REPLACE)),
+ "short-label", _("Re_place"), NULL);
+ g_object_set (
+ G_OBJECT (ACTION (INSERT_IMAGE)),
+ "short-label", _("_Image"), NULL);
+ g_object_set (
+ G_OBJECT (ACTION (INSERT_LINK)),
+ "short-label", _("_Link"), NULL);
+ g_object_set (
+ G_OBJECT (ACTION (INSERT_RULE)),
+ /* Translators: 'Rule' here means a horizontal line in an HTML text */
+ "short-label", _("_Rule"), NULL);
+ g_object_set (
+ G_OBJECT (ACTION (INSERT_TABLE)),
+ "short-label", _("_Table"), NULL);
+
+ gtk_action_set_sensitive (ACTION (UNINDENT), FALSE);
+ gtk_action_set_sensitive (ACTION (FIND_AGAIN), FALSE);
+ gtk_action_set_sensitive (ACTION (SPELL_CHECK), FALSE);
+
+ g_object_bind_property (
+ view, "can-redo",
+ ACTION (REDO), "sensitive",
+ G_BINDING_SYNC_CREATE);
+ g_object_bind_property (
+ view, "can-undo",
+ ACTION (UNDO), "sensitive",
+ G_BINDING_SYNC_CREATE);
+ g_object_bind_property (
+ view, "can-copy",
+ ACTION (COPY), "sensitive",
+ G_BINDING_SYNC_CREATE);
+ g_object_bind_property (
+ view, "can-cut",
+ ACTION (CUT), "sensitive",
+ G_BINDING_SYNC_CREATE);
+ g_object_bind_property (
+ view, "can-paste",
+ ACTION (PASTE), "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ /* This is connected to JUSTIFY_LEFT action only, but
+ * it automatically applies on all actions in the group. */
+ g_object_bind_property (
+ editor->priv->selection, "alignment",
+ ACTION (JUSTIFY_LEFT), "current-value",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ g_object_bind_property (
+ editor->priv->selection, "bold",
+ ACTION (BOLD), "active",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ g_object_bind_property (
+ editor->priv->selection, "font-size",
+ ACTION (FONT_SIZE_GROUP), "current-value",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ g_object_bind_property (
+ editor->priv->selection, "block-format",
+ ACTION (STYLE_NORMAL), "current-value",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ g_object_bind_property (
+ editor->priv->selection, "indented",
+ ACTION (UNINDENT), "sensitive",
+ G_BINDING_SYNC_CREATE);
+ g_object_bind_property (
+ editor->priv->selection, "italic",
+ ACTION (ITALIC), "active",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ g_object_bind_property (
+ editor->priv->selection, "monospaced",
+ ACTION (MONOSPACED), "active",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ g_object_bind_property (
+ editor->priv->selection, "strikethrough",
+ ACTION (STRIKETHROUGH), "active",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ g_object_bind_property (
+ editor->priv->selection, "underline",
+ ACTION (UNDERLINE), "active",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+
+ /* Disable all actions and toolbars when editor is not editable */
+ g_object_bind_property (
+ view, "editable",
+ editor->priv->core_actions, "sensitive",
+ G_BINDING_SYNC_CREATE);
+ g_object_bind_property (
+ view, "editable",
+ editor->priv->html_actions, "sensitive",
+ G_BINDING_SYNC_CREATE);
+ g_object_bind_property (
+ view, "editable",
+ editor->priv->spell_check_actions, "sensitive",
+ G_BINDING_SYNC_CREATE);
+ g_object_bind_property (
+ view, "editable",
+ editor->priv->suggestion_actions, "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ settings = g_settings_new ("org.gnome.evolution.mail");
+ gtk_action_set_visible (
+ ACTION (WEBKIT_INSPECTOR),
+ g_settings_get_boolean (settings, "composer-developer-mode"));
+ g_object_unref (settings);
+}