geany/plugins/htmlchars.c
Enrico Tröger 639e23effa Use pluginmacros.h (for classbuilder and htmlchars plugins).
Add highlighting_get_style().
Add highlighting_get_style() to the plugin API.
Rename DocumentFuncs field in GeanyData struct to avoid name clashes.	      


git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@2103 ea778897-0a13-0410-b9d1-a72fbfd435f5
2007-12-16 11:27:59 +00:00

533 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-2007 Enrico Tröger <enrico.troeger@uvena.de>
* Copyright 2007 Nick Treleaven <nick.treleaven@btinternet.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 "pluginmacros.h"
PluginFields *plugin_fields;
GeanyData *geany_data;
VERSION_CHECK(7)
PLUGIN_INFO(_("HTML Characters"), _("Inserts HTML character entities like '&amp;'."), VERSION,
_("The Geany developer team"))
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()
{
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(app->window),
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
_("_Insert"), GTK_RESPONSE_OK, NULL);
vbox = 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 * 0.8, 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)
{
gint idx = documents->get_cur_idx();
gboolean result = FALSE;
if (DOC_IDX_VALID(idx))
{
gchar *str;
gint pos = scintilla->get_current_position(doc_list[idx].sci);
gtk_tree_model_get(model, iter, COLUMN_HTML_NAME, &str, -1);
if (str && *str)
{
scintilla->insert_text(doc_list[idx].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)
{
// refuse opening the dialog if we don't have an active tab
gint idx = documents->get_cur_idx();
if (idx == -1 || ! doc_list[idx].is_valid) return;
tools_show_dialog_insert_special_chars();
}
/* Called by Geany to initialize the plugin */
void init(GeanyData *data)
{
GtkWidget *demo_item;
// Add an item to the Tools menu
demo_item = gtk_menu_item_new_with_mnemonic(_("_Insert Special HTML Characters"));
gtk_widget_show(demo_item);
gtk_container_add(GTK_CONTAINER(geany_data->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;
}
/* Destroy widgets */
void cleanup()
{
gtk_widget_destroy(plugin_fields->menu_item);
if (sc_dialog != NULL)
gtk_widget_destroy(sc_dialog);
}