2
* htmlchars.c - this file is part of Geany, a fast and lightweight IDE
4
* Copyright 2006-2008 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5
* Copyright 2007-2008 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22
* $Id: htmlchars.c 2411 2008-03-26 17:10:18Z ntrel $
25
/* HTML Characters plugin (Inserts HTML character entities like '&') */
29
#include "plugindata.h"
31
#include "keybindings.h"
32
#include "pluginmacros.h"
35
PluginFields *plugin_fields;
36
GeanyData *geany_data;
39
PLUGIN_VERSION_CHECK(48)
41
PLUGIN_INFO(_("HTML Characters"), _("Inserts HTML character entities like '&'."), VERSION,
42
_("The Geany developer team"))
52
PLUGIN_KEY_GROUP(html_chars, KB_COUNT)
63
static GtkWidget *sc_dialog = NULL;
64
static GtkTreeStore *sc_store = NULL;
65
static GtkTreeView *sc_tree = NULL;
67
static void sc_on_tools_show_dialog_insert_special_chars_response
68
(GtkDialog *dialog, gint response, gpointer user_data);
69
static void sc_on_tree_row_activated
70
(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer user_data);
71
static void sc_fill_store(GtkTreeStore *store);
72
static gboolean sc_insert(GtkTreeModel *model, GtkTreeIter *iter);
75
static void tools_show_dialog_insert_special_chars(void)
77
if (sc_dialog == NULL)
80
GtkCellRenderer *renderer;
81
GtkTreeViewColumn *column;
82
GtkWidget *swin, *vbox, *label;
84
sc_dialog = gtk_dialog_new_with_buttons(
85
_("Special Characters"), GTK_WINDOW(app->window),
86
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
87
_("_Insert"), GTK_RESPONSE_OK, NULL);
88
vbox = p_ui->dialog_vbox_new(GTK_DIALOG(sc_dialog));
89
gtk_box_set_spacing(GTK_BOX(vbox), 6);
90
gtk_widget_set_name(sc_dialog, "GeanyDialog");
92
height = GEANY_WINDOW_MINIMAL_HEIGHT;
93
gtk_window_set_default_size(GTK_WINDOW(sc_dialog), height * 8 / 10, height);
94
gtk_dialog_set_default_response(GTK_DIALOG(sc_dialog), GTK_RESPONSE_CANCEL);
96
label = gtk_label_new(_("Choose a special character from the list below and double click on it or use the button to insert it at the current cursor position."));
97
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
98
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
99
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
101
sc_tree = GTK_TREE_VIEW(gtk_tree_view_new());
103
sc_store = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
104
gtk_tree_view_set_model(GTK_TREE_VIEW(sc_tree),
105
GTK_TREE_MODEL(sc_store));
107
renderer = gtk_cell_renderer_text_new();
108
column = gtk_tree_view_column_new_with_attributes(
109
_("Character"), renderer, "text", COLUMN_CHARACTER, NULL);
110
gtk_tree_view_column_set_resizable(column, TRUE);
111
gtk_tree_view_append_column(GTK_TREE_VIEW(sc_tree), column);
113
renderer = gtk_cell_renderer_text_new();
114
column = gtk_tree_view_column_new_with_attributes(
115
_("HTML (name)"), renderer, "text", COLUMN_HTML_NAME, NULL);
116
gtk_tree_view_column_set_resizable(column, TRUE);
117
gtk_tree_view_append_column(GTK_TREE_VIEW(sc_tree), column);
119
swin = gtk_scrolled_window_new(NULL, NULL);
120
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin), GTK_POLICY_AUTOMATIC,
121
GTK_POLICY_AUTOMATIC);
122
gtk_scrolled_window_add_with_viewport(
123
GTK_SCROLLED_WINDOW(swin), GTK_WIDGET(sc_tree));
125
gtk_box_pack_start(GTK_BOX(vbox), swin, TRUE, TRUE, 0);
127
g_signal_connect((gpointer) sc_tree, "row-activated",
128
G_CALLBACK(sc_on_tree_row_activated), NULL);
130
g_signal_connect((gpointer) sc_dialog, "response",
131
G_CALLBACK(sc_on_tools_show_dialog_insert_special_chars_response), NULL);
133
g_signal_connect((gpointer) sc_dialog, "delete_event",
134
G_CALLBACK(gtk_widget_hide_on_delete), NULL);
136
sc_fill_store(sc_store);
138
/*gtk_tree_view_expand_all(special_characters_tree);*/
139
gtk_tree_view_set_search_column(sc_tree, COLUMN_HTML_NAME);
141
gtk_widget_show_all(sc_dialog);
145
/* fill the tree model with data
146
** TODO move this in a file and make it extendable for more data types */
147
static void sc_fill_store(GtkTreeStore *store)
150
GtkTreeIter *parent_iter = NULL;
155
{ _("HTML characters"), NULL },
161
{ _("ISO 8859-1 characters"), NULL },
259
{ _("Greek characters"), NULL },
269
{ "Ε", "Ε" },
270
{ "ε", "ε" },
289
{ "Ο", "Ο" },
290
{ "ο", "ο" },
300
{ "Υ", "Υ" },
301
{ "υ", "υ" },
310
{ "ϑ", "ϑ" },
314
{ _("Mathematical characters"), NULL },
355
{ _("Technical characters"), NULL },
363
{ _("Arrow characters"), NULL },
376
{ _("Punctuation characters"), NULL },
392
{ _("Miscellaneous characters"), NULL },
403
{ "ℵ", "ℵ" },
416
for (i = 0; i < G_N_ELEMENTS(chars); i++)
418
if (chars[i][1] == NULL)
419
{ /* add a category */
420
gtk_tree_store_append(store, &iter, NULL);
421
gtk_tree_store_set(store, &iter, COLUMN_CHARACTER, chars[i][0], -1);
422
if (parent_iter != NULL) gtk_tree_iter_free(parent_iter);
423
parent_iter = gtk_tree_iter_copy(&iter);
426
{ /* add child to parent_iter */
427
gtk_tree_store_append(store, &iter, parent_iter);
428
gtk_tree_store_set(store, &iter, COLUMN_CHARACTER, chars[i][0],
429
COLUMN_HTML_NAME, chars[i][1], -1);
435
/* just inserts the HTML_NAME coloumn of the selected row at current position
436
* returns only TRUE if a valid selection(i.e. no category) could be found */
437
static gboolean sc_insert(GtkTreeModel *model, GtkTreeIter *iter)
439
gint idx = p_document->get_cur_idx();
440
gboolean result = FALSE;
442
if (DOC_IDX_VALID(idx))
445
gint pos = p_sci->get_current_position(doc_list[idx].sci);
447
gtk_tree_model_get(model, iter, COLUMN_HTML_NAME, &str, -1);
450
p_sci->insert_text(doc_list[idx].sci, pos, str);
459
static void sc_on_tools_show_dialog_insert_special_chars_response(GtkDialog *dialog, gint response,
462
if (response == GTK_RESPONSE_OK)
464
GtkTreeSelection *selection;
468
selection = gtk_tree_view_get_selection(sc_tree);
470
if (gtk_tree_selection_get_selected(selection, &model, &iter))
472
/* only hide dialog if selection was not a category */
473
if (sc_insert(model, &iter))
474
gtk_widget_hide(GTK_WIDGET(dialog));
478
gtk_widget_hide(GTK_WIDGET(dialog));
482
static void sc_on_tree_row_activated(GtkTreeView *treeview, GtkTreePath *path,
483
GtkTreeViewColumn *col, gpointer user_data)
486
GtkTreeModel *model = GTK_TREE_MODEL(sc_store);
488
if (gtk_tree_model_get_iter(model, &iter, path))
490
/* only hide dialog if selection was not a category */
491
if (sc_insert(model, &iter))
492
gtk_widget_hide(sc_dialog);
494
{ /* double click on a category to toggle the expand or collapse it */
495
if (gtk_tree_view_row_expanded(sc_tree, path))
496
gtk_tree_view_collapse_row(sc_tree, path);
498
gtk_tree_view_expand_row(sc_tree, path, FALSE);
504
/* Callback when the menu item is clicked */
506
item_activate(GtkMenuItem *menuitem, gpointer gdata)
508
/* refuse opening the dialog if we don't have an active tab */
509
gint idx = p_document->get_cur_idx();
511
if (idx == -1 || ! doc_list[idx].is_valid) return;
513
tools_show_dialog_insert_special_chars();
517
static void kb_activate(G_GNUC_UNUSED guint key_id)
519
item_activate(NULL, NULL);
523
/* Called by Geany to initialize the plugin */
524
void init(GeanyData *data)
526
GtkWidget *demo_item;
527
const gchar *menu_text = _("_Insert Special HTML Characters");
528
gchar *kb_label = _("Insert Special HTML Characters");
530
/* Add an item to the Tools menu */
531
demo_item = gtk_menu_item_new_with_mnemonic(menu_text);
532
gtk_widget_show(demo_item);
533
gtk_container_add(GTK_CONTAINER(geany_data->tools_menu), demo_item);
534
g_signal_connect(G_OBJECT(demo_item), "activate", G_CALLBACK(item_activate), NULL);
536
/* disable menu_item when there are no documents open */
537
plugin_fields->menu_item = demo_item;
538
plugin_fields->flags = PLUGIN_IS_DOCUMENT_SENSITIVE;
540
/* setup keybindings */
541
p_keybindings->set_item(plugin_key_group, KB_INSERT_HTML_CHARS, kb_activate,
542
0, 0, "insert_html_chars", kb_label, demo_item);
546
/* Destroy widgets */
549
gtk_widget_destroy(plugin_fields->menu_item);
551
if (sc_dialog != NULL)
552
gtk_widget_destroy(sc_dialog);