geany/plugins/htmlchars.c
Enrico Tröger 1e8d82f46a Note: this breaks the plugin API for msgwin and navqueue functions.
Make NavQueueFuncs and MsgWinFuncs use a GeanyDocument* instead of an integer index.
Adjust plugins to work with these changes.            


git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/branches/document-pointer@2688 ea778897-0a13-0410-b9d1-a72fbfd435f5
2008-06-12 20:09:57 +00:00

554 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* htmlchars.c - this file is part of Geany, a fast and lightweight IDE
*
* Copyright 2006-2008 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
* Copyright 2007-2008 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* $Id$
*/
/* HTML Characters plugin (Inserts HTML character entities like '&amp;') */
#include "geany.h"
#include "support.h"
#include "plugindata.h"
#include "document.h"
#include "keybindings.h"
#include "ui_utils.h"
#include "utils.h"
#include "pluginmacros.h"
PluginFields *plugin_fields;
GeanyData *geany_data;
GeanyFunctions *geany_functions;
PLUGIN_VERSION_CHECK(69)
PLUGIN_SET_INFO(_("HTML Characters"), _("Inserts HTML character entities like '&amp;'."), VERSION,
_("The Geany developer team"))
/* Keybinding(s) */
enum
{
KB_INSERT_HTML_CHARS,
KB_COUNT
};
PLUGIN_KEY_GROUP(html_chars, KB_COUNT)
enum
{
COLUMN_CHARACTER,
COLUMN_HTML_NAME,
N_COLUMNS
};
static GtkWidget *sc_dialog = NULL;
static GtkTreeStore *sc_store = NULL;
static GtkTreeView *sc_tree = NULL;
static void sc_on_tools_show_dialog_insert_special_chars_response
(GtkDialog *dialog, gint response, gpointer user_data);
static void sc_on_tree_row_activated
(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer user_data);
static void sc_fill_store(GtkTreeStore *store);
static gboolean sc_insert(GtkTreeModel *model, GtkTreeIter *iter);
static void tools_show_dialog_insert_special_chars(void)
{
if (sc_dialog == NULL)
{
gint height;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkWidget *swin, *vbox, *label;
sc_dialog = gtk_dialog_new_with_buttons(
_("Special Characters"), GTK_WINDOW(main_widgets->window),
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
_("_Insert"), GTK_RESPONSE_OK, NULL);
vbox = p_ui->dialog_vbox_new(GTK_DIALOG(sc_dialog));
gtk_box_set_spacing(GTK_BOX(vbox), 6);
gtk_widget_set_name(sc_dialog, "GeanyDialog");
height = GEANY_WINDOW_MINIMAL_HEIGHT;
gtk_window_set_default_size(GTK_WINDOW(sc_dialog), height * 8 / 10, height);
gtk_dialog_set_default_response(GTK_DIALOG(sc_dialog), GTK_RESPONSE_CANCEL);
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."));
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
sc_tree = GTK_TREE_VIEW(gtk_tree_view_new());
sc_store = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
gtk_tree_view_set_model(GTK_TREE_VIEW(sc_tree),
GTK_TREE_MODEL(sc_store));
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes(
_("Character"), renderer, "text", COLUMN_CHARACTER, NULL);
gtk_tree_view_column_set_resizable(column, TRUE);
gtk_tree_view_append_column(GTK_TREE_VIEW(sc_tree), column);
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes(
_("HTML (name)"), renderer, "text", COLUMN_HTML_NAME, NULL);
gtk_tree_view_column_set_resizable(column, TRUE);
gtk_tree_view_append_column(GTK_TREE_VIEW(sc_tree), column);
swin = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin), GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_add_with_viewport(
GTK_SCROLLED_WINDOW(swin), GTK_WIDGET(sc_tree));
gtk_box_pack_start(GTK_BOX(vbox), swin, TRUE, TRUE, 0);
g_signal_connect((gpointer) sc_tree, "row-activated",
G_CALLBACK(sc_on_tree_row_activated), NULL);
g_signal_connect((gpointer) sc_dialog, "response",
G_CALLBACK(sc_on_tools_show_dialog_insert_special_chars_response), NULL);
g_signal_connect((gpointer) sc_dialog, "delete_event",
G_CALLBACK(gtk_widget_hide_on_delete), NULL);
sc_fill_store(sc_store);
/*gtk_tree_view_expand_all(special_characters_tree);*/
gtk_tree_view_set_search_column(sc_tree, COLUMN_HTML_NAME);
}
gtk_widget_show_all(sc_dialog);
}
/* fill the tree model with data
** TODO move this in a file and make it extendable for more data types */
static void sc_fill_store(GtkTreeStore *store)
{
GtkTreeIter iter;
GtkTreeIter *parent_iter = NULL;
guint i;
gchar *chars[][2] =
{
{ _("HTML characters"), NULL },
{ "\"", "&quot;" },
{ "&", "&amp;" },
{ "<", "&lt;" },
{ ">", "&gt;" },
{ _("ISO 8859-1 characters"), NULL },
{ " ", "&nbsp;" },
{ "¡", "&iexcl;" },
{ "¢", "&cent;" },
{ "£", "&pound;" },
{ "¤", "&curren;" },
{ "¥", "&yen;" },
{ "¦", "&brvbar;" },
{ "§", "&sect;" },
{ "¨", "&uml;" },
{ "©", "&copy;" },
{ "®", "&reg;" },
{ "«", "&laquo;" },
{ "»", "&raquo;" },
{ "¬", "&not;" },
{ " ", "&shy;" },
{ "¯", "&macr;" },
{ "°", "&deg;" },
{ "±", "&plusmn;" },
{ "¹", "&sup1;" },
{ "²", "&sup2;" },
{ "³", "&sup3;" },
{ "¼", "&frac14;" },
{ "½", "&frac12;" },
{ "¾", "&frac34;" },
{ "×", "&times;" },
{ "÷", "&divide;" },
{ "´", "&acute;" },
{ "µ", "&micro;" },
{ "", "&para;" },
{ "·", "&middot;" },
{ "¸", "&cedil;" },
{ "ª", "&ordf;" },
{ "º", "&ordm;" },
{ "¿", "&iquest;" },
{ "À", "&Agrave;" },
{ "Á", "&Aacute;" },
{ "Â", "&Acirc;" },
{ "Ã", "&Atilde;" },
{ "Ä", "&Auml;" },
{ "Å", "&Aring;" },
{ "Æ", "&AElig;" },
{ "Ç", "&Ccedil;" },
{ "È", "&Egrave;" },
{ "É", "&Eacute;" },
{ "Ê", "&Ecirc;" },
{ "Ë", "&Euml;" },
{ "Ì", "&Igrave;" },
{ "Í", "&Iacute;" },
{ "Î", "&Icirc;" },
{ "Ï", "&Iuml;" },
{ "Ð", "&ETH;" },
{ "Ñ", "&Ntilde;" },
{ "Ò", "&Ograve;" },
{ "Ó", "&Oacute;" },
{ "Ô", "&Ocirc;" },
{ "Õ", "&Otilde;" },
{ "Ö", "&Ouml;" },
{ "Ø", "&Oslash;" },
{ "Ù", "&Ugrave;" },
{ "Ú", "&Uacute;" },
{ "Û", "&Ucirc;" },
{ "Ü", "&Uuml;" },
{ "Ý", "&Yacute;" },
{ "Þ", "&THORN;" },
{ "ß", "&szlig;" },
{ "à", "&agrave;" },
{ "á", "&aacute;" },
{ "â", "&acirc;" },
{ "ã", "&atilde;" },
{ "ä", "&auml;" },
{ "å", "&aring;" },
{ "æ", "&aelig;" },
{ "ç", "&ccedil;" },
{ "è", "&egrave;" },
{ "é", "&eacute;" },
{ "ê", "&ecirc;" },
{ "ë", "&euml;" },
{ "ì", "&igrave;" },
{ "í", "&iacute;" },
{ "î", "&icirc;" },
{ "ï", "&iuml;" },
{ "ð", "&eth;" },
{ "ñ", "&ntilde;" },
{ "ò", "&ograve;" },
{ "ó", "&oacute;" },
{ "ô", "&ocirc;" },
{ "õ", "&otilde;" },
{ "ö", "&ouml;" },
{ "ø", "&oslash;" },
{ "ù", "&ugrave;" },
{ "ú", "&uacute;" },
{ "û", "&ucirc;" },
{ "ü", "&uuml;" },
{ "ý", "&yacute;" },
{ "þ", "&thorn;" },
{ "ÿ", "&yuml;" },
{ _("Greek characters"), NULL },
{ "Α", "&Alpha;" },
{ "α", "&alpha;" },
{ "Β", "&Beta;" },
{ "β", "&beta;" },
{ "Γ", "&Gamma;" },
{ "γ", "&gamma;" },
{ "Δ", "&Delta;" },
{ "δ", "&Delta;" },
{ "δ", "&delta;" },
{ "Ε", "&Epsilon;" },
{ "ε", "&epsilon;" },
{ "Ζ", "&Zeta;" },
{ "ζ", "&zeta;" },
{ "Η", "&Eta;" },
{ "η", "&eta;" },
{ "Θ", "&Theta;" },
{ "θ", "&theta;" },
{ "Ι", "&Iota;" },
{ "ι", "&iota;" },
{ "Κ", "&Kappa;" },
{ "κ", "&kappa;" },
{ "Λ", "&Lambda;" },
{ "λ", "&lambda;" },
{ "Μ", "&Mu;" },
{ "μ", "&mu;" },
{ "Ν", "&Nu;" },
{ "ν", "&nu;" },
{ "Ξ", "&Xi;" },
{ "ξ", "&xi;" },
{ "Ο", "&Omicron;" },
{ "ο", "&omicron;" },
{ "Π", "&Pi;" },
{ "π", "&pi;" },
{ "Ρ", "&Rho;" },
{ "ρ", "&rho;" },
{ "Σ", "&Sigma;" },
{ "ς", "&sigmaf;" },
{ "σ", "&sigma;" },
{ "Τ", "&Tau;" },
{ "τ", "&tau;" },
{ "Υ", "&Upsilon;" },
{ "υ", "&upsilon;" },
{ "Φ", "&Phi;" },
{ "φ", "&phi;" },
{ "Χ", "&Chi;" },
{ "χ", "&chi;" },
{ "Ψ", "&Psi;" },
{ "ψ", "&psi;" },
{ "Ω", "&Omega;" },
{ "ω", "&omega;" },
{ "ϑ", "&thetasym;" },
{ "ϒ", "&upsih;" },
{ "ϖ", "&piv;" },
{ _("Mathematical characters"), NULL },
{ "", "&forall;" },
{ "", "&part;" },
{ "", "&exist;" },
{ "", "&empty;" },
{ "", "&nabla;" },
{ "", "&isin;" },
{ "", "&notin;" },
{ "", "&ni;" },
{ "", "&prod;" },
{ "", "&sum;" },
{ "", "&minus;" },
{ "", "&lowast;" },
{ "", "&radic;" },
{ "", "&prop;" },
{ "", "&infin;" },
{ "", "&ang;" },
{ "", "&and;" },
{ "", "&or;" },
{ "", "&cap;" },
{ "", "&cup;" },
{ "", "&int;" },
{ "", "&there4;" },
{ "", "&sim;" },
{ "", "&cong;" },
{ "", "&asymp;" },
{ "", "&ne;" },
{ "", "&equiv;" },
{ "", "&le;" },
{ "", "&ge;" },
{ "", "&sub;" },
{ "", "&sup;" },
{ "", "&nsub;" },
{ "", "&sube;" },
{ "", "&supe;" },
{ "", "&oplus;" },
{ "", "&otimes;" },
{ "", "&perp;" },
{ "", "&sdot;" },
{ "", "&loz;" },
{ _("Technical characters"), NULL },
{ "", "&lceil;" },
{ "", "&rceil;" },
{ "", "&lfloor;" },
{ "", "&rfloor;" },
{ "", "&lang;" },
{ "", "&rang;" },
{ _("Arrow characters"), NULL },
{ "", "&larr;" },
{ "", "&uarr;" },
{ "", "&rarr;" },
{ "", "&darr;" },
{ "", "&harr;" },
{ "", "&crarr;" },
{ "", "&lArr;" },
{ "", "&uArr;" },
{ "", "&rArr;" },
{ "", "&dArr;" },
{ "", "&hArr;" },
{ _("Punctuation characters"), NULL },
{ "", "&ndash;" },
{ "", "&mdash;" },
{ "", "&lsquo;" },
{ "", "&rsquo;" },
{ "", "&sbquo;" },
{ "", "&ldquo;" },
{ "", "&rdquo;" },
{ "", "&bdquo;" },
{ "", "&dagger;" },
{ "", "&Dagger;" },
{ "", "&hellip;" },
{ "", "&permil;" },
{ "", "&lsaquo;" },
{ "", "&rsaquo;" },
{ _("Miscellaneous characters"), NULL },
{ "", "&bull;" },
{ "", "&prime;" },
{ "", "&Prime;" },
{ "", "&oline;" },
{ "", "&frasl;" },
{ "", "&weierp;" },
{ "", "&image;" },
{ "", "&real;" },
{ "", "&trade;" },
{ "", "&euro;" },
{ "", "&alefsym;" },
{ "", "&spades;" },
{ "", "&clubs;" },
{ "", "&hearts;" },
{ "", "&diams;" },
{ "Œ", "&OElig;" },
{ "œ", "&oelig;" },
{ "Š", "&Scaron;" },
{ "š", "&scaron;" },
{ "Ÿ", "&Yuml;" },
{ "ƒ", "&fnof;" },
};
for (i = 0; i < G_N_ELEMENTS(chars); i++)
{
if (chars[i][1] == NULL)
{ /* add a category */
gtk_tree_store_append(store, &iter, NULL);
gtk_tree_store_set(store, &iter, COLUMN_CHARACTER, chars[i][0], -1);
if (parent_iter != NULL) gtk_tree_iter_free(parent_iter);
parent_iter = gtk_tree_iter_copy(&iter);
}
else
{ /* add child to parent_iter */
gtk_tree_store_append(store, &iter, parent_iter);
gtk_tree_store_set(store, &iter, COLUMN_CHARACTER, chars[i][0],
COLUMN_HTML_NAME, chars[i][1], -1);
}
}
}
/* just inserts the HTML_NAME coloumn of the selected row at current position
* returns only TRUE if a valid selection(i.e. no category) could be found */
static gboolean sc_insert(GtkTreeModel *model, GtkTreeIter *iter)
{
GeanyDocument *doc = p_document->get_current();
gboolean result = FALSE;
if (doc != NULL)
{
gchar *str;
gint pos = p_sci->get_current_position(doc->sci);
gtk_tree_model_get(model, iter, COLUMN_HTML_NAME, &str, -1);
if (NZV(str))
{
p_sci->insert_text(doc->sci, pos, str);
g_free(str);
result = TRUE;
}
}
return result;
}
static void sc_on_tools_show_dialog_insert_special_chars_response(GtkDialog *dialog, gint response,
gpointer user_data)
{
if (response == GTK_RESPONSE_OK)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
selection = gtk_tree_view_get_selection(sc_tree);
if (gtk_tree_selection_get_selected(selection, &model, &iter))
{
/* only hide dialog if selection was not a category */
if (sc_insert(model, &iter))
gtk_widget_hide(GTK_WIDGET(dialog));
}
}
else
gtk_widget_hide(GTK_WIDGET(dialog));
}
static void sc_on_tree_row_activated(GtkTreeView *treeview, GtkTreePath *path,
GtkTreeViewColumn *col, gpointer user_data)
{
GtkTreeIter iter;
GtkTreeModel *model = GTK_TREE_MODEL(sc_store);
if (gtk_tree_model_get_iter(model, &iter, path))
{
/* only hide dialog if selection was not a category */
if (sc_insert(model, &iter))
gtk_widget_hide(sc_dialog);
else
{ /* double click on a category to toggle the expand or collapse it */
if (gtk_tree_view_row_expanded(sc_tree, path))
gtk_tree_view_collapse_row(sc_tree, path);
else
gtk_tree_view_expand_row(sc_tree, path, FALSE);
}
}
}
/* Callback when the menu item is clicked */
static void
item_activate(GtkMenuItem *menuitem, gpointer gdata)
{
tools_show_dialog_insert_special_chars();
}
static void kb_activate(G_GNUC_UNUSED guint key_id)
{
item_activate(NULL, NULL);
}
/* Called by Geany to initialize the plugin */
void plugin_init(GeanyData *data)
{
GtkWidget *demo_item;
const gchar *menu_text = _("_Insert Special HTML Characters");
gchar *kb_label = _("Insert Special HTML Characters");
/* Add an item to the Tools menu */
demo_item = gtk_menu_item_new_with_mnemonic(menu_text);
gtk_widget_show(demo_item);
gtk_container_add(GTK_CONTAINER(main_widgets->tools_menu), demo_item);
g_signal_connect(G_OBJECT(demo_item), "activate", G_CALLBACK(item_activate), NULL);
/* disable menu_item when there are no documents open */
plugin_fields->menu_item = demo_item;
plugin_fields->flags = PLUGIN_IS_DOCUMENT_SENSITIVE;
/* setup keybindings */
p_keybindings->set_item(plugin_key_group, KB_INSERT_HTML_CHARS, kb_activate,
0, 0, "insert_html_chars", kb_label, demo_item);
}
/* Destroy widgets */
void plugin_cleanup(void)
{
gtk_widget_destroy(plugin_fields->menu_item);
if (sc_dialog != NULL)
gtk_widget_destroy(sc_dialog);
}