diff options
Diffstat (limited to 'plugins/sort')
-rw-r--r-- | plugins/sort/gedit-sort-plugin.c | 418 | ||||
-rw-r--r-- | plugins/sort/gedit-sort-plugin.h | 59 | ||||
-rw-r--r-- | plugins/sort/meson.build | 34 | ||||
-rw-r--r-- | plugins/sort/resources/gedit-sort.gresource.xml | 6 | ||||
-rw-r--r-- | plugins/sort/resources/meson.build | 8 | ||||
-rw-r--r-- | plugins/sort/resources/ui/gedit-sort-plugin.ui | 160 | ||||
-rw-r--r-- | plugins/sort/sort.plugin.desktop.in | 11 |
7 files changed, 696 insertions, 0 deletions
diff --git a/plugins/sort/gedit-sort-plugin.c b/plugins/sort/gedit-sort-plugin.c new file mode 100644 index 0000000..41774fc --- /dev/null +++ b/plugins/sort/gedit-sort-plugin.c @@ -0,0 +1,418 @@ +/* + * gedit-sort-plugin.c + * + * Original author: Carlo Borreo <borreo@softhome.net> + * Ported to Gedit2 by Lee Mallabone <gnome@fonicmonkey.net> + * + * 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, 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, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include "gedit-sort-plugin.h" + +#include <string.h> +#include <glib/gi18n.h> + +#include <gedit/gedit-debug.h> +#include <gedit/gedit-utils.h> +#include <gedit/gedit-app.h> +#include <gedit/gedit-window.h> +#include <gedit/gedit-app-activatable.h> +#include <gedit/gedit-window-activatable.h> + +static void gedit_app_activatable_iface_init (GeditAppActivatableInterface *iface); +static void gedit_window_activatable_iface_init (GeditWindowActivatableInterface *iface); + +struct _GeditSortPluginPrivate +{ + GeditWindow *window; + + GSimpleAction *action; + GtkWidget *dialog; + GtkWidget *col_num_spinbutton; + GtkWidget *reverse_order_checkbutton; + GtkWidget *case_checkbutton; + GtkWidget *remove_dups_checkbutton; + + GeditApp *app; + GeditMenuExtension *menu_ext; + + GtkTextIter start, end; /* selection */ +}; + +enum +{ + PROP_0, + PROP_WINDOW, + PROP_APP +}; + +G_DEFINE_DYNAMIC_TYPE_EXTENDED (GeditSortPlugin, + gedit_sort_plugin, + PEAS_TYPE_EXTENSION_BASE, + 0, + G_IMPLEMENT_INTERFACE_DYNAMIC (GEDIT_TYPE_APP_ACTIVATABLE, + gedit_app_activatable_iface_init) + G_IMPLEMENT_INTERFACE_DYNAMIC (GEDIT_TYPE_WINDOW_ACTIVATABLE, + gedit_window_activatable_iface_init) + G_ADD_PRIVATE_DYNAMIC (GeditSortPlugin)) + +static void +do_sort (GeditSortPlugin *plugin) +{ + GeditSortPluginPrivate *priv; + GeditDocument *doc; + GtkSourceSortFlags sort_flags = 0; + gint starting_column; + + gedit_debug (DEBUG_PLUGINS); + + priv = plugin->priv; + + doc = gedit_window_get_active_document (priv->window); + g_return_if_fail (doc != NULL); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->case_checkbutton))) + { + sort_flags |= GTK_SOURCE_SORT_FLAGS_CASE_SENSITIVE; + } + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->reverse_order_checkbutton))) + { + sort_flags |= GTK_SOURCE_SORT_FLAGS_REVERSE_ORDER; + } + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->remove_dups_checkbutton))) + { + sort_flags |= GTK_SOURCE_SORT_FLAGS_REMOVE_DUPLICATES; + } + + starting_column = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->col_num_spinbutton)) - 1; + + gtk_source_buffer_sort_lines (GTK_SOURCE_BUFFER (doc), + &priv->start, + &priv->end, + sort_flags, + starting_column); + + gedit_debug_message (DEBUG_PLUGINS, "Done."); +} + +static void +sort_dialog_response_handler (GtkDialog *dlg, + gint response, + GeditSortPlugin *plugin) +{ + gedit_debug (DEBUG_PLUGINS); + + if (response == GTK_RESPONSE_OK) + { + do_sort (plugin); + } + + gtk_widget_destroy (GTK_WIDGET (dlg)); +} + +/* NOTE: we store the current selection in the dialog since focusing + * the text field (like the combo box) looses the documnent selection. + * Storing the selection ONLY works because the dialog is modal */ +static void +get_current_selection (GeditSortPlugin *plugin) +{ + GeditSortPluginPrivate *priv; + GeditDocument *doc; + + gedit_debug (DEBUG_PLUGINS); + + priv = plugin->priv; + + doc = gedit_window_get_active_document (priv->window); + + if (!gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), + &priv->start, + &priv->end)) + { + /* No selection, get the whole document. */ + gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), + &priv->start, + &priv->end); + } +} + +static void +create_sort_dialog (GeditSortPlugin *plugin) +{ + GeditSortPluginPrivate *priv; + GtkBuilder *builder; + + gedit_debug (DEBUG_PLUGINS); + + priv = plugin->priv; + + builder = gtk_builder_new (); + gtk_builder_add_from_resource (builder, "/org/gnome/gedit/plugins/sort/ui/gedit-sort-plugin.ui", NULL); + priv->dialog = GTK_WIDGET (gtk_builder_get_object (builder, "sort_dialog")); + priv->reverse_order_checkbutton = GTK_WIDGET (gtk_builder_get_object (builder, "reverse_order_checkbutton")); + priv->col_num_spinbutton = GTK_WIDGET (gtk_builder_get_object (builder, "col_num_spinbutton")); + priv->case_checkbutton = GTK_WIDGET (gtk_builder_get_object (builder, "case_checkbutton")); + priv->remove_dups_checkbutton = GTK_WIDGET (gtk_builder_get_object (builder, "remove_dups_checkbutton")); + g_object_unref (builder); + + gtk_dialog_set_default_response (GTK_DIALOG (priv->dialog), + GTK_RESPONSE_OK); + + g_signal_connect (priv->dialog, + "destroy", + G_CALLBACK (gtk_widget_destroyed), + &priv->dialog); + + g_signal_connect (priv->dialog, + "response", + G_CALLBACK (sort_dialog_response_handler), + plugin); + + get_current_selection (plugin); +} + +static void +sort_cb (GAction *action, + GVariant *parameter, + GeditSortPlugin *plugin) +{ + GeditSortPluginPrivate *priv; + GtkWindowGroup *wg; + + gedit_debug (DEBUG_PLUGINS); + + priv = plugin->priv; + + create_sort_dialog (plugin); + + wg = gedit_window_get_group (priv->window); + gtk_window_group_add_window (wg, + GTK_WINDOW (priv->dialog)); + + gtk_window_set_transient_for (GTK_WINDOW (priv->dialog), + GTK_WINDOW (priv->window)); + + gtk_window_set_modal (GTK_WINDOW (priv->dialog), + TRUE); + + gtk_widget_show (GTK_WIDGET (priv->dialog)); +} + +static void +update_ui (GeditSortPlugin *plugin) +{ + GeditView *view; + + gedit_debug (DEBUG_PLUGINS); + + view = gedit_window_get_active_view (plugin->priv->window); + + g_simple_action_set_enabled (plugin->priv->action, + (view != NULL) && + gtk_text_view_get_editable (GTK_TEXT_VIEW (view))); +} + +static void +gedit_sort_plugin_app_activate (GeditAppActivatable *activatable) +{ + GeditSortPluginPrivate *priv; + GMenuItem *item; + + gedit_debug (DEBUG_PLUGINS); + + priv = GEDIT_SORT_PLUGIN (activatable)->priv; + + priv->menu_ext = gedit_app_activatable_extend_menu (activatable, "tools-section"); + item = g_menu_item_new (_("S_ort…"), "win.sort"); + gedit_menu_extension_append_menu_item (priv->menu_ext, item); + g_object_unref (item); +} + +static void +gedit_sort_plugin_app_deactivate (GeditAppActivatable *activatable) +{ + GeditSortPluginPrivate *priv; + + gedit_debug (DEBUG_PLUGINS); + + priv = GEDIT_SORT_PLUGIN (activatable)->priv; + + g_clear_object (&priv->menu_ext); +} + +static void +gedit_sort_plugin_window_activate (GeditWindowActivatable *activatable) +{ + GeditSortPluginPrivate *priv; + + gedit_debug (DEBUG_PLUGINS); + + priv = GEDIT_SORT_PLUGIN (activatable)->priv; + + priv->action = g_simple_action_new ("sort", NULL); + g_signal_connect (priv->action, "activate", + G_CALLBACK (sort_cb), activatable); + g_action_map_add_action (G_ACTION_MAP (priv->window), + G_ACTION (priv->action)); + + update_ui (GEDIT_SORT_PLUGIN (activatable)); +} + +static void +gedit_sort_plugin_window_deactivate (GeditWindowActivatable *activatable) +{ + GeditSortPluginPrivate *priv; + + gedit_debug (DEBUG_PLUGINS); + + priv = GEDIT_SORT_PLUGIN (activatable)->priv; + g_action_map_remove_action (G_ACTION_MAP (priv->window), "sort"); +} + +static void +gedit_sort_plugin_window_update_state (GeditWindowActivatable *activatable) +{ + gedit_debug (DEBUG_PLUGINS); + + update_ui (GEDIT_SORT_PLUGIN (activatable)); +} + +static void +gedit_sort_plugin_init (GeditSortPlugin *plugin) +{ + gedit_debug_message (DEBUG_PLUGINS, "GeditSortPlugin initializing"); + + plugin->priv = gedit_sort_plugin_get_instance_private (plugin); +} + +static void +gedit_sort_plugin_dispose (GObject *object) +{ + GeditSortPlugin *plugin = GEDIT_SORT_PLUGIN (object); + + gedit_debug_message (DEBUG_PLUGINS, "GeditSortPlugin disposing"); + + g_clear_object (&plugin->priv->action); + g_clear_object (&plugin->priv->window); + g_clear_object (&plugin->priv->menu_ext); + g_clear_object (&plugin->priv->app); + + G_OBJECT_CLASS (gedit_sort_plugin_parent_class)->dispose (object); +} + + +static void +gedit_sort_plugin_finalize (GObject *object) +{ + gedit_debug_message (DEBUG_PLUGINS, "GeditSortPlugin finalizing"); + + G_OBJECT_CLASS (gedit_sort_plugin_parent_class)->finalize (object); +} + +static void +gedit_sort_plugin_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GeditSortPlugin *plugin = GEDIT_SORT_PLUGIN (object); + + switch (prop_id) + { + case PROP_WINDOW: + plugin->priv->window = GEDIT_WINDOW (g_value_dup_object (value)); + break; + case PROP_APP: + plugin->priv->app = GEDIT_APP (g_value_dup_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gedit_sort_plugin_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GeditSortPlugin *plugin = GEDIT_SORT_PLUGIN (object); + + switch (prop_id) + { + case PROP_WINDOW: + g_value_set_object (value, plugin->priv->window); + break; + case PROP_APP: + g_value_set_object (value, plugin->priv->app); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gedit_sort_plugin_class_init (GeditSortPluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = gedit_sort_plugin_dispose; + object_class->finalize = gedit_sort_plugin_finalize; + object_class->set_property = gedit_sort_plugin_set_property; + object_class->get_property = gedit_sort_plugin_get_property; + + g_object_class_override_property (object_class, PROP_WINDOW, "window"); + g_object_class_override_property (object_class, PROP_APP, "app"); +} + +static void +gedit_sort_plugin_class_finalize (GeditSortPluginClass *klass) +{ +} + +static void +gedit_app_activatable_iface_init (GeditAppActivatableInterface *iface) +{ + iface->activate = gedit_sort_plugin_app_activate; + iface->deactivate = gedit_sort_plugin_app_deactivate; +} + +static void +gedit_window_activatable_iface_init (GeditWindowActivatableInterface *iface) +{ + iface->activate = gedit_sort_plugin_window_activate; + iface->deactivate = gedit_sort_plugin_window_deactivate; + iface->update_state = gedit_sort_plugin_window_update_state; +} + +G_MODULE_EXPORT void +peas_register_types (PeasObjectModule *module) +{ + gedit_sort_plugin_register_type (G_TYPE_MODULE (module)); + + peas_object_module_register_extension_type (module, + GEDIT_TYPE_APP_ACTIVATABLE, + GEDIT_TYPE_SORT_PLUGIN); + peas_object_module_register_extension_type (module, + GEDIT_TYPE_WINDOW_ACTIVATABLE, + GEDIT_TYPE_SORT_PLUGIN); +} + +/* ex:set ts=8 noet: */ diff --git a/plugins/sort/gedit-sort-plugin.h b/plugins/sort/gedit-sort-plugin.h new file mode 100644 index 0000000..e8739e0 --- /dev/null +++ b/plugins/sort/gedit-sort-plugin.h @@ -0,0 +1,59 @@ +/* + * gedit-sort-plugin.h + * + * 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, 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef GEDIT_SORT_PLUGIN_H +#define GEDIT_SORT_PLUGIN_H + +#include <glib.h> +#include <glib-object.h> +#include <libpeas/peas-extension-base.h> +#include <libpeas/peas-object-module.h> + +G_BEGIN_DECLS + +#define GEDIT_TYPE_SORT_PLUGIN (gedit_sort_plugin_get_type ()) +#define GEDIT_SORT_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GEDIT_TYPE_SORT_PLUGIN, GeditSortPlugin)) +#define GEDIT_SORT_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GEDIT_TYPE_SORT_PLUGIN, GeditSortPluginClass)) +#define GEDIT_IS_SORT_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GEDIT_TYPE_SORT_PLUGIN)) +#define GEDIT_IS_SORT_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GEDIT_TYPE_SORT_PLUGIN)) +#define GEDIT_SORT_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GEDIT_TYPE_SORT_PLUGIN, GeditSortPluginClass)) + +typedef struct _GeditSortPlugin GeditSortPlugin; +typedef struct _GeditSortPluginPrivate GeditSortPluginPrivate; +typedef struct _GeditSortPluginClass GeditSortPluginClass; + +struct _GeditSortPlugin +{ + PeasExtensionBase parent; + + /*< private >*/ + GeditSortPluginPrivate *priv; +}; + +struct _GeditSortPluginClass +{ + PeasExtensionBaseClass parent_class; +}; + +GType gedit_sort_plugin_get_type (void) G_GNUC_CONST; + +G_MODULE_EXPORT void peas_register_types (PeasObjectModule *module); + +G_END_DECLS + +#endif /* GEDIT_SORT_PLUGIN_H */ +/* ex:set ts=8 noet: */ diff --git a/plugins/sort/meson.build b/plugins/sort/meson.build new file mode 100644 index 0000000..7f91440 --- /dev/null +++ b/plugins/sort/meson.build @@ -0,0 +1,34 @@ +libsort_sources = files( + 'gedit-sort-plugin.c', +) + +libsort_deps = [ + libgedit_dep, +] + +subdir('resources') + +libsort_sha = shared_module( + 'sort', + sources: libsort_sources, + include_directories: root_include_dir, + dependencies: libsort_deps, + install: true, + install_dir: join_paths( + pkglibdir, + 'plugins', + ), + name_suffix: module_suffix, +) + +custom_target( + 'sort.plugin', + input: 'sort.plugin.desktop.in', + output: 'sort.plugin', + command: msgfmt_plugin_cmd, + install: true, + install_dir: join_paths( + pkglibdir, + 'plugins', + ) +) diff --git a/plugins/sort/resources/gedit-sort.gresource.xml b/plugins/sort/resources/gedit-sort.gresource.xml new file mode 100644 index 0000000..3855c8f --- /dev/null +++ b/plugins/sort/resources/gedit-sort.gresource.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> + <gresource prefix="/org/gnome/gedit/plugins/sort"> + <file preprocess="xml-stripblanks">ui/gedit-sort-plugin.ui</file> + </gresource> +</gresources> diff --git a/plugins/sort/resources/meson.build b/plugins/sort/resources/meson.build new file mode 100644 index 0000000..7178761 --- /dev/null +++ b/plugins/sort/resources/meson.build @@ -0,0 +1,8 @@ +libsort_res = gnome.compile_resources( + 'gedit-sort-resources', + 'gedit-sort.gresource.xml', +) + +libsort_sources += [ + libsort_res.get(0), +] diff --git a/plugins/sort/resources/ui/gedit-sort-plugin.ui b/plugins/sort/resources/ui/gedit-sort-plugin.ui new file mode 100644 index 0000000..95a0e17 --- /dev/null +++ b/plugins/sort/resources/ui/gedit-sort-plugin.ui @@ -0,0 +1,160 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <!-- interface-requires gtk+ 2.12 --> + <object class="GtkAdjustment" id="adjustment1"> + <property name="lower">1</property> + <property name="upper">100</property> + <property name="value">1</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> + <object class="GtkDialog" id="sort_dialog"> + <property name="can_focus">False</property> + <property name="title" translatable="yes">Sort</property> + <property name="resizable">False</property> + <property name="destroy_with_parent">True</property> + <property name="type_hint">dialog</property> + <property name="use-header-bar">1</property> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkBox" id="vbox1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="border_width">10</property> + <property name="orientation">vertical</property> + <property name="spacing">18</property> + <child> + <object class="GtkBox" id="vbox5"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkCheckButton" id="reverse_order_checkbutton"> + <property name="label" translatable="yes">_Reverse order</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="remove_dups_checkbutton"> + <property name="label" translatable="yes">R_emove duplicates</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="case_checkbutton"> + <property name="label" translatable="yes">C_ase sensitive</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkBox" id="hbox13"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="label18"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">S_tart at column:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">col_num_spinbutton</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="col_num_spinbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="adjustment">adjustment1</property> + <property name="climb_rate">1</property> + <property name="numeric">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <child type="action"> + <object class="GtkButton" id="cancel"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Cancel</property> + <property name="use_underline">True</property> + </object> + </child> + <child type="action"> + <object class="GtkButton" id="sort"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Sort</property> + <property name="can-default">True</property> + <property name="use_underline">True</property> + </object> + </child> + <action-widgets> + <action-widget response="-6">cancel</action-widget> + <action-widget response="-5">sort</action-widget> + </action-widgets> + </object> +</interface> diff --git a/plugins/sort/sort.plugin.desktop.in b/plugins/sort/sort.plugin.desktop.in new file mode 100644 index 0000000..f2e2c78 --- /dev/null +++ b/plugins/sort/sort.plugin.desktop.in @@ -0,0 +1,11 @@ +[Plugin] +Module=sort +IAge=3 +Name=Sort +Description=Sorts a document or selected text. +# TRANSLATORS: Do NOT translate or transliterate this text! +# This is an icon file name. +Icon=view-sort-ascending +Authors=Carlo Borreo <borreo@softhome.net>;Lee Mallabone <gnome@fonicmonkey.net>;Paolo Maggi <paolo.maggi@polito.it>;Jorge Alberto Torres H. <jorge@deadoak.com> +Copyright=Copyright © 2001 Carlo Borreo;Copyright © 2002-2003 Lee Mallabone, Paolo Maggi;Copyright © 2004-2005 Paolo Maggi +Website=http://www.gedit.org |