summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJohn Smith <john.smith7545@yahoo.com>2012-02-21 13:26:58 +0000
committerJohn Smith <removethis.john.q.public@bigmail.com>2012-02-21 13:26:58 +0000
commit5a97256cdaa9cc74e50b05aaf6a491f2df6fda0f (patch)
tree243844f1ed4140f61458fbd435f0194ed37b6d42 /src
parentCopy missing libintl-8.dll in build.xml (diff)
downloadinkscape-5a97256cdaa9cc74e50b05aaf6a491f2df6fda0f.tar.gz
inkscape-5a97256cdaa9cc74e50b05aaf6a491f2df6fda0f.zip
Fix for 934721 : Convert SpellCheck dialog to a dockable dialog
(bzr r11006)
Diffstat (limited to 'src')
-rw-r--r--src/dialogs/Makefile_insert2
-rw-r--r--src/dialogs/spellcheck.cpp1060
-rw-r--r--src/dialogs/spellcheck.h31
-rw-r--r--src/ui/context-menu.cpp5
-rw-r--r--src/ui/dialog/Makefile_insert2
-rw-r--r--src/ui/dialog/dialog-manager.cpp4
-rw-r--r--src/ui/dialog/spellcheck.cpp871
-rw-r--r--src/ui/dialog/spellcheck.h280
-rw-r--r--src/verbs.cpp4
9 files changed, 1160 insertions, 1099 deletions
diff --git a/src/dialogs/Makefile_insert b/src/dialogs/Makefile_insert
index 6a3d33f07..88f0df197 100644
--- a/src/dialogs/Makefile_insert
+++ b/src/dialogs/Makefile_insert
@@ -9,7 +9,5 @@ ink_common_sources += \
dialogs/export.h \
dialogs/find.cpp \
dialogs/find.h \
- dialogs/spellcheck.cpp \
- dialogs/spellcheck.h \
dialogs/xml-tree.cpp \
dialogs/xml-tree.h
diff --git a/src/dialogs/spellcheck.cpp b/src/dialogs/spellcheck.cpp
deleted file mode 100644
index cc1afd475..000000000
--- a/src/dialogs/spellcheck.cpp
+++ /dev/null
@@ -1,1060 +0,0 @@
-/**
- * @file
- * Spellcheck dialog.
- */
-/* Authors:
- * bulia byak <bulia@users.sf.net>
- * Jon A. Cruz <jon@joncruz.org>
- * Abhishek Sharma
- *
- * Copyright (C) 2009 Authors
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include "widgets/icon.h"
-#include "message-stack.h"
-
-#include <gtk/gtk.h>
-
-#include <glibmm/i18n.h>
-#include "helper/window.h"
-#include "macros.h"
-#include "inkscape.h"
-#include "document.h"
-#include "desktop.h"
-#include "selection.h"
-#include "desktop-handles.h"
-#include "dialog-events.h"
-#include "tools-switch.h"
-#include "text-context.h"
-#include "../interface.h"
-#include "../preferences.h"
-#include "../sp-text.h"
-#include "../sp-flowtext.h"
-#include "../text-editing.h"
-#include "../sp-tspan.h"
-#include "../sp-tref.h"
-#include "../sp-defs.h"
-#include "../selection-chemistry.h"
-#include <xml/repr.h>
-#include "display/canvas-bpath.h"
-#include "display/curve.h"
-#include "document-undo.h"
-#include "sp-root.h"
-#include "verbs.h"
-
-#ifdef HAVE_ASPELL
-#include <aspell.h>
-
-#ifdef WIN32
-#include <windows.h>
-#endif
-
-using Inkscape::DocumentUndo;
-
-#define MIN_ONSCREEN_DISTANCE 50
-
-static GtkWidget *dlg = NULL;
-static win_data wd;
-
-// impossible original values to make sure they are read from prefs
-static gint x = -1000, y = -1000, w = 0, h = 0;
-static Glib::ustring const prefs_path = "/dialogs/spellcheck/";
-
-// C++ for the poor: instead of creating a formal C++ class, I just treat this entire file as a
-// class, with the globals as its data fields. In such a simple case as this, when no inheritance
-// or encapsulation are necessary, this is much simpler and less verbose, and mixes easily with
-// plain-C GTK callbacks.
-
-static SPDesktop *_desktop = NULL;
-static SPObject *_root;
-
-static AspellSpeller *_speller = NULL;
-static AspellSpeller *_speller2 = NULL;
-static AspellSpeller *_speller3 = NULL;
-
-// list of canvasitems (currently just rects) that mark misspelled things on canvas
-static GSList *_rects = NULL;
-
-// list of text objects we have already checked in this session
-static GSList *_seen_objects = NULL;
-
-// the object currently being checked
-static SPItem *_text = NULL;
-// its layout
-static Inkscape::Text::Layout const *_layout = NULL;
-
-// iterators for the start and end of the current word
-static Inkscape::Text::Layout::iterator _begin_w;
-static Inkscape::Text::Layout::iterator _end_w;
-
-// the word we're checking
-static Glib::ustring _word;
-
-// counters for the number of stops and dictionary adds
-static int _stops = 0;
-static int _adds = 0;
-
-// true if we are in the middle of a check
-static bool _working = false;
-
-// connect to the object being checked in case it is modified or deleted by user
-static sigc::connection *_modified_connection = NULL;
-static sigc::connection *_release_connection = NULL;
-
-// true if the spell checker dialog has changed text, to suppress modified callback
-static bool _local_change = false;
-
-static Inkscape::Preferences *_prefs = NULL;
-
-static gchar *_lang = NULL;
-static gchar *_lang2 = NULL;
-static gchar *_lang3 = NULL;
-
-
-void spellcheck_clear_rects()
-{
- for (GSList *it = _rects; it; it = it->next) {
- sp_canvas_item_hide((SPCanvasItem*) it->data);
- gtk_object_destroy((SPCanvasItem*) it->data);
- }
- g_slist_free(_rects);
- _rects = NULL;
-}
-
-void spellcheck_clear_langs()
-{
- if (_lang) {
- g_free(_lang);
- _lang = NULL;
- }
- if (_lang2) {
- g_free(_lang2);
- _lang2 = NULL;
- }
- if (_lang3) {
- g_free(_lang3);
- _lang3 = NULL;
- }
-}
-
-void
-spellcheck_disconnect()
-{
- if (_release_connection) {
- _release_connection->disconnect();
- delete _release_connection;
- _release_connection = NULL;
- }
- if (_modified_connection) {
- _modified_connection->disconnect();
- delete _modified_connection;
- _modified_connection = NULL;
- }
-}
-
-static void sp_spellcheck_dialog_destroy(GtkObject *object, gpointer)
-{
- _prefs->setInt(prefs_path + "visible", 0);
-
- spellcheck_clear_rects();
- spellcheck_clear_langs();
- spellcheck_disconnect();
-
- sp_signal_disconnect_by_data (INKSCAPE, object);
- wd.win = dlg = NULL;
- wd.stop = 0;
-}
-
-
-static gboolean sp_spellcheck_dialog_delete(GtkObject *, GdkEvent *, gpointer /*data*/)
-{
- spellcheck_clear_rects();
- spellcheck_clear_langs();
- spellcheck_disconnect();
-
- gtk_window_get_position (GTK_WINDOW (dlg), &x, &y);
- gtk_window_get_size (GTK_WINDOW (dlg), &w, &h);
-
- if (x<0) x=0;
- if (y<0) y=0;
-
- _prefs->setInt(prefs_path + "x", x);
- _prefs->setInt(prefs_path + "y", y);
- _prefs->setInt(prefs_path + "w", w);
- _prefs->setInt(prefs_path + "h", h);
-
- return FALSE; // which means, go ahead and destroy it
-}
-
-void
-sp_spellcheck_new_button (GtkWidget *dlg, GtkWidget *hb, const gchar *label, const gchar *tip, void (*function) (GObject *, GObject *), const gchar *cookie)
-{
- GtkWidget *b = gtk_button_new_with_mnemonic (label);
- gtk_widget_set_tooltip_text (b, tip);
- gtk_box_pack_start (GTK_BOX (hb), b, TRUE, TRUE, 0);
- g_signal_connect ( G_OBJECT (b), "clicked", G_CALLBACK (function), dlg );
- g_object_set_data (G_OBJECT (dlg), cookie, b);
- gtk_widget_show (b);
-}
-
-
-
-GSList *
-all_text_items (SPObject *r, GSList *l, bool hidden, bool locked)
-{
- if (!_desktop)
- return l; // no desktop to check
-
- if (SP_IS_DEFS(r))
- return l; // we're not interested in items in defs
-
- if (!strcmp(r->getRepr()->name(), "svg:metadata")) {
- return l; // we're not interested in metadata
- }
-
- for (SPObject *child = r->firstChild(); child; child = child->next) {
- if (SP_IS_ITEM (child) && !child->cloned && !_desktop->isLayer(SP_ITEM(child))) {
- if ((hidden || !_desktop->itemIsHidden(SP_ITEM(child))) && (locked || !SP_ITEM(child)->isLocked())) {
- if (SP_IS_TEXT(child) || SP_IS_FLOWTEXT(child))
- l = g_slist_prepend (l, child);
- }
- }
- l = all_text_items (child, l, hidden, locked);
- }
- return l;
-}
-
-bool
-spellcheck_text_is_valid (SPObject *root, SPItem *text)
-{
- GSList *l = NULL;
- l = all_text_items (root, l, false, true);
- for (GSList *i = l; i; i = i->next) {
- SPItem *item = static_cast<SPItem *>(i->data);
- if (item == text) {
- g_slist_free (l);
- return true;
- }
- }
- g_slist_free (l);
- return false;
-}
-
-gint compare_text_bboxes (gconstpointer a, gconstpointer b)
-{
- SPItem *i1 = SP_ITEM(a);
- SPItem *i2 = SP_ITEM(b);
-
- Geom::OptRect bbox1 = i1->desktopVisualBounds();
- Geom::OptRect bbox2 = i2->desktopVisualBounds();
- if (!bbox1 || !bbox2) {
- return 0;
- }
-
- // vector between top left corners
- Geom::Point diff = Geom::Point(bbox2->min()[Geom::X], bbox2->max()[Geom::Y]) -
- Geom::Point(bbox1->min()[Geom::X], bbox1->max()[Geom::Y]);
-
- // sort top to bottom, left to right, but:
- // if i2 is higher only 0.2 or less times it is righter than i1, put i1 first
- if (diff[Geom::Y] > 0.2 * diff[Geom::X])
- return 1;
- else
- return -1;
-
- return 0;
-}
-
-// we regenerate and resort the list every time, because user could have changed it while the
-// dialog was waiting
-SPItem *spellcheck_get_text (SPObject *root)
-{
- GSList *l = NULL;
- l = all_text_items (root, l, false, true);
- l = g_slist_sort(l, compare_text_bboxes);
-
- for (GSList *i = l; i; i = i->next) {
- SPItem *item = static_cast<SPItem *>(i->data);
- if (!g_slist_find (_seen_objects, item)) {
- _seen_objects = g_slist_prepend(_seen_objects, item);
- g_slist_free(l);
- return item;
- }
- }
-
- g_slist_free(l);
- return NULL;
-}
-
-void
-spellcheck_sensitive (const gchar *cookie, gboolean gray)
-{
- GtkWidget *l = GTK_WIDGET(g_object_get_data(G_OBJECT (dlg), cookie));
- gtk_widget_set_sensitive(l, gray);
-}
-
-static void spellcheck_enable_accept(GtkTreeSelection * /*selection*/,
- void * /*??*/)
-{
- spellcheck_sensitive ("b_accept", TRUE);
-}
-
-static void spellcheck_obj_modified (SPObject *obj, guint /*flags*/, gpointer /*data*/);
-static void spellcheck_obj_released (SPObject *obj, gpointer /*data*/);
-
-void
-spellcheck_next_text()
-{
- spellcheck_disconnect();
-
- _text = spellcheck_get_text(_root);
- if (_text) {
- _release_connection = new sigc::connection (SP_OBJECT(_text)->connectRelease(
- sigc::bind<1>(sigc::ptr_fun(&spellcheck_obj_released), dlg)));
-
- _modified_connection = new sigc::connection (SP_OBJECT(_text)->connectModified(
- sigc::bind<2>(sigc::ptr_fun(&spellcheck_obj_modified), dlg)));
-
- _layout = te_get_layout (_text);
- _begin_w = _layout->begin();
- }
- _end_w = _begin_w;
- _word.clear();
-}
-
-bool
-spellcheck_init(SPDesktop *desktop)
-{
- _desktop = desktop;
-
- spellcheck_sensitive("suggestions", FALSE);
- spellcheck_sensitive("b_accept", FALSE);
- spellcheck_sensitive("b_ignore", FALSE);
- spellcheck_sensitive("b_ignore_once", FALSE);
- spellcheck_sensitive("b_add", FALSE);
- spellcheck_sensitive("addto_langs", FALSE);
- spellcheck_sensitive("b_start", FALSE);
-
-#ifdef WIN32
- // on windows, dictionaries are in a lib/aspell-0.60 subdir off inkscape's executable dir;
- // this is some black magick to find out the executable path to give it to aspell
- char exeName[MAX_PATH+1];
- GetModuleFileName(NULL, exeName, MAX_PATH);
- char *slashPos = strrchr(exeName, '\\');
- if (slashPos)
- *slashPos = '\0';
- g_print ("%s\n", exeName);
-#endif
-
- _stops = 0;
- _adds = 0;
- spellcheck_clear_rects();
-
- {
- AspellConfig *config = new_aspell_config();
-#ifdef WIN32
- aspell_config_replace(config, "prefix", exeName);
-#endif
- aspell_config_replace(config, "lang", _lang);
- aspell_config_replace(config, "encoding", "UTF-8");
- AspellCanHaveError *ret = new_aspell_speller(config);
- delete_aspell_config(config);
- if (aspell_error(ret) != 0) {
- g_warning("Error: %s\n", aspell_error_message(ret));
- delete_aspell_can_have_error(ret);
- return false;
- }
- _speller = to_aspell_speller(ret);
- }
-
- if (_lang2) {
- AspellConfig *config = new_aspell_config();
-#ifdef WIN32
- aspell_config_replace(config, "prefix", exeName);
-#endif
- aspell_config_replace(config, "lang", _lang2);
- aspell_config_replace(config, "encoding", "UTF-8");
- AspellCanHaveError *ret = new_aspell_speller(config);
- delete_aspell_config(config);
- if (aspell_error(ret) != 0) {
- g_warning("Error: %s\n", aspell_error_message(ret));
- delete_aspell_can_have_error(ret);
- return false;
- }
- _speller2 = to_aspell_speller(ret);
- }
-
- if (_lang3) {
- AspellConfig *config = new_aspell_config();
-#ifdef WIN32
- aspell_config_replace(config, "prefix", exeName);
-#endif
- aspell_config_replace(config, "lang", _lang3);
- aspell_config_replace(config, "encoding", "UTF-8");
- AspellCanHaveError *ret = new_aspell_speller(config);
- delete_aspell_config(config);
- if (aspell_error(ret) != 0) {
- g_warning("Error: %s\n", aspell_error_message(ret));
- delete_aspell_can_have_error(ret);
- return false;
- }
- _speller3 = to_aspell_speller(ret);
- }
-
- _root = sp_desktop_document(desktop)->getRoot();
-
- // empty the list of objects we've checked
- g_slist_free (_seen_objects);
- _seen_objects = NULL;
-
- // grab first text
- spellcheck_next_text();
-
- _working = true;
-
- return true;
-}
-
-void
-spellcheck_finished ()
-{
- aspell_speller_save_all_word_lists(_speller);
- delete_aspell_speller(_speller);
- _speller = NULL;
- if (_speller2) {
- aspell_speller_save_all_word_lists(_speller2);
- delete_aspell_speller(_speller2);
- _speller2 = NULL;
- }
- if (_speller3) {
- aspell_speller_save_all_word_lists(_speller3);
- delete_aspell_speller(_speller3);
- _speller3 = NULL;
- }
-
- spellcheck_clear_rects();
- spellcheck_disconnect();
-
- _desktop->clearWaitingCursor();
-
- spellcheck_sensitive("suggestions", FALSE);
- spellcheck_sensitive("b_accept", FALSE);
- spellcheck_sensitive("b_ignore", FALSE);
- spellcheck_sensitive("b_ignore_once", FALSE);
- spellcheck_sensitive("b_add", FALSE);
- spellcheck_sensitive("addto_langs", FALSE);
- spellcheck_sensitive("b_stop", FALSE);
- spellcheck_sensitive("b_start", TRUE);
-
- {
- GtkWidget *l = GTK_WIDGET(g_object_get_data(G_OBJECT (dlg), "banner"));
- gchar *label;
- if (_stops)
- label = g_strdup_printf(_("<b>Finished</b>, <b>%d</b> words added to dictionary"), _adds);
- else
- label = g_strdup_printf(_("<b>Finished</b>, nothing suspicious found"));
- gtk_label_set_markup (GTK_LABEL(l), label);
- g_free(label);
- }
-
- g_slist_free(_seen_objects);
- _seen_objects = NULL;
-
- _desktop = NULL;
- _root = NULL;
-
- _working = false;
-}
-
-bool
-spellcheck_next_word()
-{
- if (!_working)
- return false;
-
- if (!_text) {
- spellcheck_finished();
- return false;
- }
- _word.clear();
-
- while (_word.size() == 0) {
- _begin_w = _end_w;
-
- if (!_layout || _begin_w == _layout->end()) {
- spellcheck_next_text();
- return false;
- }
-
- if (!_layout->isStartOfWord(_begin_w)) {
- _begin_w.nextStartOfWord();
- }
-
- _end_w = _begin_w;
- _end_w.nextEndOfWord();
- _word = sp_te_get_string_multiline (_text, _begin_w, _end_w);
- }
-
- // try to link this word with the next if separated by '
- void *rawptr;
- Glib::ustring::iterator text_iter;
- _layout->getSourceOfCharacter(_end_w, &rawptr, &text_iter);
- SPObject *char_item = SP_OBJECT(rawptr);
- if (SP_IS_STRING(char_item)) {
- int this_char = *text_iter;
- if (this_char == '\'' || this_char == 0x2019) {
- Inkscape::Text::Layout::iterator end_t = _end_w;
- end_t.nextCharacter();
- _layout->getSourceOfCharacter(end_t, &rawptr, &text_iter);
- SPObject *char_item = SP_OBJECT(rawptr);
- if (SP_IS_STRING(char_item)) {
- int this_char = *text_iter;
- if (g_ascii_isalpha(this_char)) { // 's
- _end_w.nextEndOfWord();
- _word = sp_te_get_string_multiline (_text, _begin_w, _end_w);
- }
- }
- }
- }
-
- // skip words containing digits
- if (_prefs->getInt(prefs_path + "ignorenumbers") != 0) {
- bool digits = false;
- for (unsigned int i = 0; i < _word.size(); i++) {
- if (g_unichar_isdigit(_word[i])) {
- digits = true;
- break;
- }
- }
- if (digits) {
- return false;
- }
- }
-
- // skip ALL-CAPS words
- if (_prefs->getInt(prefs_path + "ignoreallcaps") != 0) {
- bool allcaps = true;
- for (unsigned int i = 0; i < _word.size(); i++) {
- if (!g_unichar_isupper(_word[i])) {
- allcaps = false;
- break;
- }
- }
- if (allcaps) {
- return false;
- }
- }
-
- // run it by all active spellers
- int have = aspell_speller_check(_speller, _word.c_str(), -1);
- if (_speller2)
- have += aspell_speller_check(_speller2, _word.c_str(), -1);
- if (_speller3)
- have += aspell_speller_check(_speller3, _word.c_str(), -1);
-
- if (have == 0) { // not found in any!
- _stops ++;
-
- _desktop->clearWaitingCursor();
-
- // display it in window
- {
- GtkWidget *l = GTK_WIDGET(g_object_get_data(G_OBJECT (dlg), "banner"));
- Glib::ustring langs = _lang;
- if (_lang2)
- langs = langs + ", " + _lang2;
- if (_lang3)
- langs = langs + ", " + _lang3;
- gchar *label = g_strdup_printf(_("Not in dictionary (%s): <b>%s</b>"), langs.c_str(), _word.c_str());
- gtk_label_set_markup (GTK_LABEL(l), label);
- g_free(label);
- }
-
- spellcheck_sensitive("suggestions", TRUE);
- spellcheck_sensitive("b_ignore", TRUE);
- spellcheck_sensitive("b_ignore_once", TRUE);
- spellcheck_sensitive("b_add", TRUE);
- spellcheck_sensitive("addto_langs", TRUE);
- spellcheck_sensitive("b_stop", TRUE);
-
- // draw rect
- std::vector<Geom::Point> points =
- _layout->createSelectionShape(_begin_w, _end_w, _text->i2dt_affine());
- Geom::Point tl, br;
- tl = br = points.front();
- for (unsigned i = 0 ; i < points.size() ; i ++) {
- if (points[i][Geom::X] < tl[Geom::X])
- tl[Geom::X] = points[i][Geom::X];
- if (points[i][Geom::Y] < tl[Geom::Y])
- tl[Geom::Y] = points[i][Geom::Y];
- if (points[i][Geom::X] > br[Geom::X])
- br[Geom::X] = points[i][Geom::X];
- if (points[i][Geom::Y] > br[Geom::Y])
- br[Geom::Y] = points[i][Geom::Y];
- }
-
- // expand slightly
- Geom::Rect area = Geom::Rect(tl, br);
- double mindim = fabs(tl[Geom::Y] - br[Geom::Y]);
- if (fabs(tl[Geom::X] - br[Geom::X]) < mindim)
- mindim = fabs(tl[Geom::X] - br[Geom::X]);
- area.expandBy(MAX(0.05 * mindim, 1));
-
- // create canvas path rectangle, red stroke
- SPCanvasItem *rect = sp_canvas_bpath_new(sp_desktop_sketch(_desktop), NULL);
- sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(rect), 0xff0000ff, 3.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
- sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(rect), 0, SP_WIND_RULE_NONZERO);
- SPCurve *curve = new SPCurve();
- curve->moveto(area.corner(0));
- curve->lineto(area.corner(1));
- curve->lineto(area.corner(2));
- curve->lineto(area.corner(3));
- curve->lineto(area.corner(0));
- sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(rect), curve);
- sp_canvas_item_show(rect);
- _rects = g_slist_prepend(_rects, rect);
-
- // scroll to make it all visible
- Geom::Point const center = _desktop->get_display_area().midpoint();
- area.expandBy(0.5 * mindim);
- Geom::Point scrollto;
- double dist = 0;
- for (unsigned corner = 0; corner < 4; corner ++) {
- if (Geom::L2(area.corner(corner) - center) > dist) {
- dist = Geom::L2(area.corner(corner) - center);
- scrollto = area.corner(corner);
- }
- }
- _desktop->scroll_to_point (scrollto, 1.0);
-
- // select text; if in Text tool, position cursor to the beginning of word
- // unless it is already in the word
- if (_desktop->selection->singleItem() != _text)
- _desktop->selection->set (_text);
- if (tools_isactive(_desktop, TOOLS_TEXT)) {
- Inkscape::Text::Layout::iterator *cursor =
- sp_text_context_get_cursor_position(SP_TEXT_CONTEXT(_desktop->event_context), _text);
- if (!cursor) // some other text is selected there
- _desktop->selection->set (_text);
- else if (*cursor <= _begin_w || *cursor >= _end_w)
- sp_text_context_place_cursor (SP_TEXT_CONTEXT(_desktop->event_context), _text, _begin_w);
- }
-
- // get suggestions
- {
- GtkTreeView *tree_view =
- GTK_TREE_VIEW(g_object_get_data(G_OBJECT (dlg), "suggestions"));
- GtkListStore *model = gtk_list_store_new (1, G_TYPE_STRING);
- gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (model));
-
- {
- const AspellWordList *wl = aspell_speller_suggest(_speller, _word.c_str(), -1);
- AspellStringEnumeration * els = aspell_word_list_elements(wl);
- const char *sugg;
- GtkTreeIter iter;
- while ((sugg = aspell_string_enumeration_next(els)) != 0) {
- gtk_list_store_append (GTK_LIST_STORE (model), &iter);
- gtk_list_store_set (GTK_LIST_STORE (model),
- &iter,
- 0, sugg,
- -1);
- }
- delete_aspell_string_enumeration(els);
- }
-
- if (_speller2) {
- const AspellWordList *wl = aspell_speller_suggest(_speller2, _word.c_str(), -1);
- AspellStringEnumeration * els = aspell_word_list_elements(wl);
- const char *sugg;
- GtkTreeIter iter;
- while ((sugg = aspell_string_enumeration_next(els)) != 0) {
- gtk_list_store_append (GTK_LIST_STORE (model), &iter);
- gtk_list_store_set (GTK_LIST_STORE (model),
- &iter,
- 0, sugg,
- -1);
- }
- delete_aspell_string_enumeration(els);
- }
-
- if (_speller3) {
- const AspellWordList *wl = aspell_speller_suggest(_speller3, _word.c_str(), -1);
- AspellStringEnumeration * els = aspell_word_list_elements(wl);
- const char *sugg;
- GtkTreeIter iter;
- while ((sugg = aspell_string_enumeration_next(els)) != 0) {
- gtk_list_store_append (GTK_LIST_STORE (model), &iter);
- gtk_list_store_set (GTK_LIST_STORE (model),
- &iter,
- 0, sugg,
- -1);
- }
- delete_aspell_string_enumeration(els);
- }
-
- spellcheck_sensitive("b_accept", FALSE); // gray it out until something is chosen
- }
-
- return true;
-
- }
- return false;
-}
-
-
-
-void
-spellcheck_delete_last_rect ()
-{
- if (_rects) {
- sp_canvas_item_hide(SP_CANVAS_ITEM(_rects->data));
- gtk_object_destroy(GTK_OBJECT(_rects->data));
- _rects = _rects->next; // pop latest-prepended rect
- }
-}
-
-void
-do_spellcheck ()
-{
- GtkWidget *l = GTK_WIDGET(g_object_get_data(G_OBJECT (dlg), "banner"));
- gtk_label_set_markup (GTK_LABEL(l), _("<i>Checking...</i>"));
- gtk_widget_queue_draw(GTK_WIDGET(dlg));
- gdk_window_process_updates(gtk_widget_get_window (GTK_WIDGET(dlg)), TRUE);
-
- _desktop->setWaitingCursor();
-
- while (_working)
- if (spellcheck_next_word())
- break;
-}
-
-static void
-spellcheck_obj_modified (SPObject */*obj*/, guint /*flags*/, gpointer /*data*/)
-{
- if (_local_change) { // this was a change by this dialog, i.e. an Accept, skip it
- _local_change = false;
- return;
- }
-
- if (_working && _root) {
- // user may have edited the text we're checking; try to do the most sensible thing in this
- // situation
-
- // just in case, re-get text's layout
- _layout = te_get_layout (_text);
-
- // re-get the word
- _layout->validateIterator(&_begin_w);
- _end_w = _begin_w;
- _end_w.nextEndOfWord();
- Glib::ustring word_new = sp_te_get_string_multiline (_text, _begin_w, _end_w);
- if (word_new != _word) {
- _end_w = _begin_w;
- spellcheck_delete_last_rect ();
- do_spellcheck (); // recheck this word and go ahead if it's ok
- }
- }
-}
-
-static void
-spellcheck_obj_released (SPObject */*obj*/, gpointer /*data*/)
-{
- if (_working && _root) {
- // the text object was deleted
- spellcheck_delete_last_rect ();
- spellcheck_next_text();
- do_spellcheck (); // get next text and continue
- }
-}
-
-void
-sp_spellcheck_accept (GObject *, GObject *dlg)
-{
- // insert chosen suggestion
- GtkTreeView *tv =
- GTK_TREE_VIEW(g_object_get_data(G_OBJECT (dlg), "suggestions"));
- GtkTreeSelection *ts = gtk_tree_view_get_selection(tv);
- GtkTreeModel *model = 0;
- GtkTreeIter iter;
- if (gtk_tree_selection_get_selected(ts, &model, &iter)) {
- gchar *sugg;
- gtk_tree_model_get (model, &iter, 0, &sugg, -1);
- if (sugg) {
- //g_print("chosen: %s\n", sugg);
- _local_change = true;
- sp_te_replace(_text, _begin_w, _end_w, sugg);
- // find the end of the word anew
- _end_w = _begin_w;
- _end_w.nextEndOfWord();
- DocumentUndo::done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_TEXT,
- _("Fix spelling"));
- }
- }
-
- spellcheck_delete_last_rect ();
-
- do_spellcheck(); // next word or end
-}
-
-void
-sp_spellcheck_ignore (GObject */*obj*/, GObject */*dlg*/)
-{
- aspell_speller_add_to_session(_speller, _word.c_str(), -1);
- if (_speller2)
- aspell_speller_add_to_session(_speller2, _word.c_str(), -1);
- if (_speller3)
- aspell_speller_add_to_session(_speller3, _word.c_str(), -1);
- spellcheck_delete_last_rect ();
-
- do_spellcheck(); // next word or end
-}
-
-void
-sp_spellcheck_ignore_once (GObject */*obj*/, GObject */*dlg*/)
-{
- spellcheck_delete_last_rect ();
-
- do_spellcheck(); // next word or end
-}
-
-void
-sp_spellcheck_add (GObject */*obj*/, GObject */*dlg*/)
-{
- _adds++;
- GtkComboBox *cbox =
- GTK_COMBO_BOX(g_object_get_data(G_OBJECT (dlg), "addto_langs"));
- gint num = gtk_combo_box_get_active(cbox);
- switch (num) {
- case 0:
- aspell_speller_add_to_personal(_speller, _word.c_str(), -1);
- break;
- case 1:
- if (_speller2)
- aspell_speller_add_to_personal(_speller2, _word.c_str(), -1);
- break;
- case 2:
- if (_speller3)
- aspell_speller_add_to_personal(_speller3, _word.c_str(), -1);
- break;
- default:
- break;
- }
-
- spellcheck_delete_last_rect ();
-
- do_spellcheck(); // next word or end
-}
-
-void
-sp_spellcheck_stop (GObject */*obj*/, GObject */*dlg*/)
-{
- spellcheck_finished();
-}
-
-void
-sp_spellcheck_start (GObject *, GObject *)
-{
- if (spellcheck_init (SP_ACTIVE_DESKTOP))
- do_spellcheck(); // next word or end
-}
-
-static gboolean spellcheck_desktop_deactivated(Inkscape::Application */*application*/, SPDesktop *desktop, void */*data*/)
-{
- if (_working) {
- if (_desktop == desktop) {
- spellcheck_finished();
- }
- }
- return FALSE;
-}
-
-
-void
-sp_spellcheck_dialog (void)
-{
- _prefs = Inkscape::Preferences::get();
-
- // take languages from prefs
- _lang = _lang2 = _lang3 = NULL;
- Glib::ustring lang = _prefs->getString(prefs_path + "lang");
- if (lang != "")
- _lang = g_strdup(lang.c_str());
- else
- _lang = g_strdup("en");
- lang = _prefs->getString(prefs_path + "lang2");
- if (lang != "")
- _lang2 = g_strdup(lang.c_str());
- lang = _prefs->getString(prefs_path + "lang3");
- if (lang != "")
- _lang3 = g_strdup(lang.c_str());
-
- if (!dlg)
- {
- gchar title[500];
- sp_ui_dialog_title_string (Inkscape::Verb::get(SP_VERB_DIALOG_SPELLCHECK), title);
-
- dlg = sp_window_new (title, TRUE);
- if (x == -1000 || y == -1000) {
- x = _prefs->getInt(prefs_path + "x", -1000);
- y = _prefs->getInt(prefs_path + "y", -1000);
- }
- if (w ==0 || h == 0) {
- w = _prefs->getInt(prefs_path + "w", 0);
- h = _prefs->getInt(prefs_path + "h", 0);
- }
-
- _prefs->setInt(prefs_path + "visible", 1);
-
- if (w && h)
- gtk_window_resize ((GtkWindow *) dlg, w, h);
- if (x >= 0 && y >= 0 && (x < (gdk_screen_width()-MIN_ONSCREEN_DISTANCE)) && (y < (gdk_screen_height()-MIN_ONSCREEN_DISTANCE))) {
- gtk_window_move ((GtkWindow *) dlg, x, y);
- } else {
- gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
- }
-
- sp_transientize (dlg);
- wd.win = dlg;
- wd.stop = 0;
- g_signal_connect ( G_OBJECT (INKSCAPE), "activate_desktop", G_CALLBACK (sp_transientize_callback), &wd );
-
- g_signal_connect( G_OBJECT(INKSCAPE), "deactivate_desktop", G_CALLBACK( spellcheck_desktop_deactivated ), NULL);
-
-
- g_signal_connect ( G_OBJECT (dlg), "event", G_CALLBACK (sp_dialog_event_handler), dlg);
-
- g_signal_connect ( G_OBJECT (dlg), "destroy", G_CALLBACK (sp_spellcheck_dialog_destroy), NULL );
- g_signal_connect ( G_OBJECT (dlg), "delete_event", G_CALLBACK (sp_spellcheck_dialog_delete), dlg);
- g_signal_connect ( G_OBJECT (INKSCAPE), "shut_down", G_CALLBACK (sp_spellcheck_dialog_delete), dlg);
-
- g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_hide", G_CALLBACK (sp_dialog_hide), dlg);
- g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_unhide", G_CALLBACK (sp_dialog_unhide), dlg);
-
- gtk_container_set_border_width (GTK_CONTAINER (dlg), 4);
-
- /* Toplevel vbox */
- GtkWidget *vb = gtk_vbox_new (FALSE, 4);
- gtk_container_add (GTK_CONTAINER (dlg), vb);
-
- {
- GtkWidget *hb = gtk_hbox_new (FALSE, 0);
- GtkWidget *l = gtk_label_new (NULL);
- g_object_set_data (G_OBJECT (dlg), "banner", l);
- gtk_box_pack_start (GTK_BOX (hb), l, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (vb), hb, FALSE, FALSE, 0);
- }
-
- {
- GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC);
-
- GtkListStore *model = gtk_list_store_new (1, G_TYPE_STRING);
- GtkWidget *tree_view = gtk_tree_view_new ();
- g_object_set_data (G_OBJECT (dlg), "suggestions", tree_view);
- gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window),
- tree_view);
- gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (model));
- GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree_view));
- g_signal_connect (G_OBJECT(selection), "changed",
- G_CALLBACK (spellcheck_enable_accept), NULL);
- gtk_widget_show (tree_view);
- GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
- GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes (_("Suggestions:"),
- cell,
- "text", 0,
- NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
- GTK_TREE_VIEW_COLUMN (column));
- gtk_box_pack_start (GTK_BOX (vb), scrolled_window, TRUE, TRUE, 0);
- }
-
-
- {
- GtkWidget *hb = gtk_hbox_new (FALSE, 0);
- sp_spellcheck_new_button (dlg, hb, _("_Accept"), _("Accept the chosen suggestion"),
- sp_spellcheck_accept, "b_accept");
- sp_spellcheck_new_button (dlg, hb, _("_Ignore once"), _("Ignore this word only once"),
- sp_spellcheck_ignore_once, "b_ignore_once");
- sp_spellcheck_new_button (dlg, hb, _("_Ignore"), _("Ignore this word in this session"),
- sp_spellcheck_ignore, "b_ignore");
- gtk_box_pack_start (GTK_BOX (vb), hb, FALSE, FALSE, 0);
- }
-
- {
- GtkWidget *hb = gtk_hbox_new (FALSE, 0);
- sp_spellcheck_new_button (dlg, hb, _("A_dd to dictionary:"), _("Add this word to the chosen dictionary"),
- sp_spellcheck_add, "b_add");
-
-// Backward compatibility fix: The GtkComboBoxText API was introduced with
-// GTK+ 2.24. This check should eventually be dropped when we bump our
-// GTK dependency.
-#if GTK_CHECK_VERSION(2, 24, 0)
- GtkWidget *cbox = gtk_combo_box_text_new();
- gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cbox), _lang);
- if (_lang2) {
- gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cbox), _lang2);
- }
- if (_lang3) {
- gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cbox), _lang3);
- }
-#else
- GtkWidget *cbox = gtk_combo_box_new_text();
- gtk_combo_box_append_text (GTK_COMBO_BOX (cbox), _lang);
- if (_lang2) {
- gtk_combo_box_append_text (GTK_COMBO_BOX (cbox), _lang2);
- }
- if (_lang3) {
- gtk_combo_box_append_text (GTK_COMBO_BOX (cbox), _lang3);
- }
-#endif
- gtk_combo_box_set_active (GTK_COMBO_BOX (cbox), 0);
- gtk_widget_show_all (cbox);
- g_object_set_data (G_OBJECT (dlg), "addto_langs", cbox);
- gtk_box_pack_start (GTK_BOX (hb), cbox, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (vb), hb, FALSE, FALSE, 0);
- }
-
- {
- GtkWidget *hs = gtk_hseparator_new ();
- gtk_box_pack_start (GTK_BOX (vb), hs, FALSE, FALSE, 0);
- }
-
- {
- GtkWidget *hb = gtk_hbox_new (FALSE, 0);
- sp_spellcheck_new_button (dlg, hb, _("_Stop"), _("Stop the check"),
- sp_spellcheck_stop, "b_stop");
- sp_spellcheck_new_button (dlg, hb, _("_Start"), _("Start the check"),
- sp_spellcheck_start, "b_start");
- gtk_box_pack_start (GTK_BOX (vb), hb, FALSE, FALSE, 0);
- }
-
- gtk_widget_show_all (vb);
- }
-
- gtk_window_present ((GtkWindow *) dlg);
-
- // run it at once
- sp_spellcheck_start (NULL, NULL);
-}
-
-#else
-
-void sp_spellcheck_dialog (void) {}
-
-#endif // HAVE_ASPELL
-
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/dialogs/spellcheck.h b/src/dialogs/spellcheck.h
deleted file mode 100644
index fe80be2cb..000000000
--- a/src/dialogs/spellcheck.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/** @file
- * @brief Spellcheck dialog
- */
-/* Authors:
- * bulia byak <bulia@users.sf.net>
- *
- * Copyright (C) 2009 Authors
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#ifndef SEEN_SPELLCHECK_H
-#define SEEN_SPELLCHECK_H
-
-#include <gtk/gtk.h>
-
-void sp_spellcheck_dialog();
-
-
-#endif /* !SEEN_SPELLCHECK_H */
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/ui/context-menu.cpp b/src/ui/context-menu.cpp
index 4cfc01cdc..5bc9af2bc 100644
--- a/src/ui/context-menu.cpp
+++ b/src/ui/context-menu.cpp
@@ -55,10 +55,9 @@ void sp_object_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu)
#include "sp-path.h"
#include "sp-text.h"
#include "desktop-handles.h"
-#include "dialogs/spellcheck.h"
#include "ui/dialog/object-attributes.h"
#include "ui/dialog/object-properties.h"
-
+#include "ui/dialog/spellcheck.h"
static void sp_item_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
@@ -550,7 +549,7 @@ static void sp_spellcheck_settings(GtkMenuItem *menuitem, SPItem *item)
sp_desktop_selection(desktop)->set(item);
}
- sp_spellcheck_dialog();
+ desktop->_dlg_mgr->showDialog("SpellCheck");
}
/* SPText */
diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert
index c2a200d53..f64db1c65 100644
--- a/src/ui/dialog/Makefile_insert
+++ b/src/ui/dialog/Makefile_insert
@@ -75,6 +75,8 @@ ink_common_sources += \
ui/dialog/print-colors-preview-dialog.h \
ui/dialog/scriptdialog.cpp \
ui/dialog/scriptdialog.h \
+ ui/dialog/spellcheck.cpp \
+ ui/dialog/spellcheck.h \
ui/dialog/svg-fonts-dialog.cpp \
ui/dialog/svg-fonts-dialog.h \
ui/dialog/swatches.cpp \
diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp
index 308a1247c..0bbb2bab4 100644
--- a/src/ui/dialog/dialog-manager.cpp
+++ b/src/ui/dialog/dialog-manager.cpp
@@ -48,7 +48,7 @@
#include "ui/dialog/object-attributes.h"
#include "ui/dialog/object-properties.h"
#include "ui/dialog/text-edit.h"
-
+#include "ui/dialog/spellcheck.h"
#ifdef ENABLE_SVG_FONTS
#include "ui/dialog/svg-fonts-dialog.h"
@@ -124,6 +124,7 @@ DialogManager::DialogManager() {
registerFactory("UndoHistory", &create<UndoHistory, FloatingBehavior>);
registerFactory("InputDevices", &create<InputDialog, FloatingBehavior>);
registerFactory("TextFont", &create<TextEdit, FloatingBehavior>);
+ registerFactory("SpellCheck", &create<SpellCheck, FloatingBehavior>);
} else {
@@ -155,6 +156,7 @@ DialogManager::DialogManager() {
registerFactory("UndoHistory", &create<UndoHistory, DockBehavior>);
registerFactory("InputDevices", &create<InputDialog, DockBehavior>);
registerFactory("TextFont", &create<TextEdit, DockBehavior>);
+ registerFactory("SpellCheck", &create<SpellCheck, DockBehavior>);
}
}
diff --git a/src/ui/dialog/spellcheck.cpp b/src/ui/dialog/spellcheck.cpp
new file mode 100644
index 000000000..1f46d9a0d
--- /dev/null
+++ b/src/ui/dialog/spellcheck.cpp
@@ -0,0 +1,871 @@
+/**
+ * @file
+ * Spellcheck dialog.
+ */
+/* Authors:
+ * bulia byak <bulia@users.sf.net>
+ * Jon A. Cruz <jon@joncruz.org>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2009 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "widgets/icon.h"
+#include "message-stack.h"
+
+#include <gtk/gtk.h>
+
+#include "helper/window.h"
+#include "macros.h"
+#include "inkscape.h"
+#include "document.h"
+#include "selection.h"
+#include "desktop-handles.h"
+#include "tools-switch.h"
+#include "text-context.h"
+#include "interface.h"
+#include "preferences.h"
+#include "sp-text.h"
+#include "sp-flowtext.h"
+#include "text-editing.h"
+#include "sp-tspan.h"
+#include "sp-tref.h"
+#include "sp-defs.h"
+#include "selection-chemistry.h"
+#include <xml/repr.h>
+#include "display/canvas-bpath.h"
+#include "display/curve.h"
+#include "document-undo.h"
+#include "sp-root.h"
+#include "verbs.h"
+#include "spellcheck.h"
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+SpellCheck::SpellCheck (void) :
+ UI::Widget::Panel ("", "/dialogs/spellcheck/", SP_VERB_DIALOG_SPELLCHECK),
+ _speller(NULL),
+ _speller2(NULL),
+ _speller3(NULL),
+ _rects(NULL),
+ _seen_objects(NULL),
+ _text(NULL),
+ _layout(NULL),
+ _stops(0),
+ _adds(0),
+ _working(false),
+ _local_change(false),
+ _prefs(NULL),
+ _lang("en"),
+ _lang2(""),
+ _lang3(""),
+ accept_button(_("_Accept"), true),
+ ignoreonce_button(_("_Ignore once"), true),
+ ignore_button(_("_Ignore"), true),
+ add_button(_("A_dd"), true),
+ dictionary_hbox(false, 0),
+ stop_button(_("_Stop"), true),
+ start_button(_("_Start"), true),
+ desktop(NULL),
+ deskTrack()
+{
+ _prefs = Inkscape::Preferences::get();
+
+ // take languages from prefs
+ _lang = _prefs->getString(_prefs_path + "lang");
+ _lang2 = _prefs->getString(_prefs_path + "lang2");
+ _lang3 = _prefs->getString(_prefs_path + "lang3");
+ if (_lang == "")
+ _lang = "en";
+
+ banner_hbox.set_layout(Gtk::BUTTONBOX_START);
+ banner_hbox.add(banner_label);
+
+ scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
+ scrolled_window.set_shadow_type(Gtk::SHADOW_IN);
+ scrolled_window.set_size_request(120, 96);
+ scrolled_window.add(tree_view);
+
+ model = Gtk::ListStore::create(tree_columns);
+ tree_view.set_model(model);
+ tree_view.append_column(_("Suggestions:"), tree_columns.suggestions);
+
+ {
+// Backward compatibility fix: The GtkComboBoxText API was introduced with
+// GTK+ 2.24. This check should eventually be dropped when we bump our
+// GTK dependency.
+#if GTK_CHECK_VERSION(2, 24, 0)
+ dictionary_combo = gtk_combo_box_text_new();
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (dictionary_combo), _lang.c_str());
+ if (_lang2 != "") {
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (dictionary_combo), _lang2.c_str());
+ }
+ if (_lang3 != "") {
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (dictionary_combo), _lang3.c_str());
+ }
+#else
+ dictionary_combo = gtk_combo_box_new_text();
+ gtk_combo_box_append_text (GTK_COMBO_BOX (dictionary_combo), _lang.c_str());
+ if (_lang2 != "") {
+ gtk_combo_box_append_text (GTK_COMBO_BOX (dictionary_combo), _lang2.c_str());
+ }
+ if (_lang3 != "") {
+ gtk_combo_box_append_text (GTK_COMBO_BOX (dictionary_combo), _lang3.c_str());
+ }
+#endif
+ gtk_combo_box_set_active (GTK_COMBO_BOX (dictionary_combo), 0);
+ gtk_widget_show_all (dictionary_combo);
+ }
+
+ accept_button.set_tooltip_text(_("Accept the chosen suggestion"));
+ ignoreonce_button.set_tooltip_text(_("Ignore this word only once"));
+ ignore_button.set_tooltip_text(_("Ignore this word in this session"));
+ add_button.set_tooltip_text(_("Add this word to the chosen dictionary"));
+
+ dictionary_hbox.pack_start(add_button, true, true, 0);
+ dictionary_hbox.pack_start(*Gtk::manage(Glib::wrap(dictionary_combo)), false, false, 0);
+
+ changebutton_vbox.set_spacing(4);
+ changebutton_vbox.pack_start(accept_button, false, false, 0);
+ changebutton_vbox.pack_start(ignoreonce_button, false, false, 0);
+ changebutton_vbox.pack_start(ignore_button, false, false, 0);
+ changebutton_vbox.pack_start(dictionary_hbox, false, false, 0);
+
+ suggestion_hbox.pack_start (scrolled_window, true, true, 4);
+ suggestion_hbox.pack_end (changebutton_vbox, false, false, 0);
+
+ stop_button.set_tooltip_text(_("Stop the check"));
+ start_button.set_tooltip_text(_("Start the check"));
+
+ actionbutton_hbox.set_layout(Gtk::BUTTONBOX_END);
+ actionbutton_hbox.set_spacing(4);
+ actionbutton_hbox.add(stop_button);
+ actionbutton_hbox.add(start_button);
+
+ /**
+ * Main dialog
+ */
+ Gtk::Box *contents = _getContents();
+ contents->set_spacing(6);
+ contents->pack_start (banner_hbox, false, false, 0);
+ contents->pack_start (suggestion_hbox, true, true, 0);
+ contents->pack_start (action_sep, false, false, 6);
+ contents->pack_start (actionbutton_hbox, false, false, 0);
+
+ /**
+ * Signal handlers
+ */
+ accept_button.signal_clicked().connect(sigc::mem_fun(*this, &SpellCheck::onAccept));
+ ignoreonce_button.signal_clicked().connect(sigc::mem_fun(*this, &SpellCheck::onIgnoreOnce));
+ ignore_button.signal_clicked().connect(sigc::mem_fun(*this, &SpellCheck::onIgnore));
+ add_button.signal_clicked().connect(sigc::mem_fun(*this, &SpellCheck::onAdd));
+ start_button.signal_clicked().connect(sigc::mem_fun(*this, &SpellCheck::onStart));
+ stop_button.signal_clicked().connect(sigc::mem_fun(*this, &SpellCheck::onStop));
+ tree_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SpellCheck::onTreeSelectionChange));
+ desktopChangeConn = deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &SpellCheck::setTargetDesktop) );
+ deskTrack.connect(GTK_WIDGET(gobj()));
+
+ show_all_children ();
+
+ // run it at once
+ onStart ();
+}
+
+SpellCheck::~SpellCheck(void)
+{
+ clearRects();
+ disconnect();
+
+ desktopChangeConn.disconnect();
+ deskTrack.disconnect();
+}
+
+void SpellCheck::setDesktop(SPDesktop *desktop)
+{
+ Panel::setDesktop(desktop);
+ deskTrack.setBase(desktop);
+}
+
+void SpellCheck::setTargetDesktop(SPDesktop *desktop)
+{
+ if (this->desktop != desktop) {
+ this->desktop = desktop;
+ if (_working) {
+ // Stop and start on the new desktop
+ finished();
+ onStart();
+ }
+ }
+}
+
+void SpellCheck::clearRects()
+{
+ for (GSList *it = _rects; it; it = it->next) {
+ sp_canvas_item_hide((SPCanvasItem*) it->data);
+ gtk_object_destroy((SPCanvasItem*) it->data);
+ }
+ g_slist_free(_rects);
+ _rects = NULL;
+}
+
+void SpellCheck::disconnect()
+{
+ if (_release_connection) {
+ _release_connection.disconnect();
+ }
+ if (_modified_connection) {
+ _modified_connection.disconnect();
+ }
+}
+
+GSList *SpellCheck::allTextItems (SPObject *r, GSList *l, bool hidden, bool locked)
+{
+ if (!desktop)
+ return l; // no desktop to check
+
+ if (SP_IS_DEFS(r))
+ return l; // we're not interested in items in defs
+
+ if (!strcmp(r->getRepr()->name(), "svg:metadata")) {
+ return l; // we're not interested in metadata
+ }
+
+ for (SPObject *child = r->firstChild(); child; child = child->next) {
+ if (SP_IS_ITEM (child) && !child->cloned && !desktop->isLayer(SP_ITEM(child))) {
+ if ((hidden || !desktop->itemIsHidden(SP_ITEM(child))) && (locked || !SP_ITEM(child)->isLocked())) {
+ if (SP_IS_TEXT(child) || SP_IS_FLOWTEXT(child))
+ l = g_slist_prepend (l, child);
+ }
+ }
+ l = allTextItems (child, l, hidden, locked);
+ }
+ return l;
+}
+
+bool
+SpellCheck::textIsValid (SPObject *root, SPItem *text)
+{
+ GSList *l = NULL;
+ l = allTextItems (root, l, false, true);
+ for (GSList *i = l; i; i = i->next) {
+ SPItem *item = static_cast<SPItem *>(i->data);
+ if (item == text) {
+ g_slist_free (l);
+ return true;
+ }
+ }
+ g_slist_free (l);
+ return false;
+}
+
+gint SpellCheck::compareTextBboxes (gconstpointer a, gconstpointer b)
+{
+ SPItem *i1 = SP_ITEM(a);
+ SPItem *i2 = SP_ITEM(b);
+
+ Geom::OptRect bbox1 = i1->desktopVisualBounds();
+ Geom::OptRect bbox2 = i2->desktopVisualBounds();
+ if (!bbox1 || !bbox2) {
+ return 0;
+ }
+
+ // vector between top left corners
+ Geom::Point diff = Geom::Point(bbox2->min()[Geom::X], bbox2->max()[Geom::Y]) -
+ Geom::Point(bbox1->min()[Geom::X], bbox1->max()[Geom::Y]);
+
+ // sort top to bottom, left to right, but:
+ // if i2 is higher only 0.2 or less times it is righter than i1, put i1 first
+ if (diff[Geom::Y] > 0.2 * diff[Geom::X])
+ return 1;
+ else
+ return -1;
+
+ return 0;
+}
+
+// We regenerate and resort the list every time, because user could have changed it while the
+// dialog was waiting
+SPItem *SpellCheck::getText (SPObject *root)
+{
+ GSList *l = NULL;
+ l = allTextItems (root, l, false, true);
+ l = g_slist_sort(l, (GCompareFunc)SpellCheck::compareTextBboxes);
+
+ for (GSList *i = l; i; i = i->next) {
+ SPItem *item = static_cast<SPItem *>(i->data);
+ if (!g_slist_find (_seen_objects, item)) {
+ _seen_objects = g_slist_prepend(_seen_objects, item);
+ g_slist_free(l);
+ return item;
+ }
+ }
+
+ g_slist_free(l);
+ return NULL;
+}
+
+void
+SpellCheck::nextText()
+{
+ disconnect();
+
+ _text = getText(_root);
+ if (_text) {
+
+ _modified_connection = ((SPObject*) _text)->connectModified(sigc::mem_fun(*this, &SpellCheck::onObjModified));
+ _release_connection = ((SPObject*) _text)->connectRelease(sigc::mem_fun(*this, &SpellCheck::onObjReleased));
+
+ _layout = te_get_layout (_text);
+ _begin_w = _layout->begin();
+ }
+ _end_w = _begin_w;
+ _word.clear();
+}
+
+bool
+SpellCheck::init(SPDesktop *d)
+{
+ desktop = d;
+
+ tree_view.set_sensitive(false);
+ accept_button.set_sensitive(false);
+ ignore_button.set_sensitive(false);
+ ignoreonce_button.set_sensitive(false);
+ add_button.set_sensitive(false);
+ gtk_widget_set_sensitive(dictionary_combo, false);
+ start_button.set_sensitive(false);
+
+#ifdef WIN32
+ // on windows, dictionaries are in a lib/aspell-0.60 subdir off inkscape's executable dir;
+ // this is some black magick to find out the executable path to give it to aspell
+ char exeName[MAX_PATH+1];
+ GetModuleFileName(NULL, exeName, MAX_PATH);
+ char *slashPos = strrchr(exeName, '\\');
+ if (slashPos)
+ *slashPos = '\0';
+ g_print ("%s\n", exeName);
+#endif
+
+ _stops = 0;
+ _adds = 0;
+ clearRects();
+
+ {
+ AspellConfig *config = new_aspell_config();
+#ifdef WIN32
+ aspell_config_replace(config, "prefix", exeName);
+#endif
+ aspell_config_replace(config, "lang", _lang.c_str());
+ aspell_config_replace(config, "encoding", "UTF-8");
+ AspellCanHaveError *ret = new_aspell_speller(config);
+ delete_aspell_config(config);
+ if (aspell_error(ret) != 0) {
+ g_warning("Error: %s\n", aspell_error_message(ret));
+ delete_aspell_can_have_error(ret);
+ return false;
+ }
+ _speller = to_aspell_speller(ret);
+ }
+
+ if (_lang2 != "") {
+ AspellConfig *config = new_aspell_config();
+#ifdef WIN32
+ aspell_config_replace(config, "prefix", exeName);
+#endif
+ aspell_config_replace(config, "lang", _lang2.c_str());
+ aspell_config_replace(config, "encoding", "UTF-8");
+ AspellCanHaveError *ret = new_aspell_speller(config);
+ delete_aspell_config(config);
+ if (aspell_error(ret) != 0) {
+ g_warning("Error: %s\n", aspell_error_message(ret));
+ delete_aspell_can_have_error(ret);
+ return false;
+ }
+ _speller2 = to_aspell_speller(ret);
+ }
+
+ if (_lang3 != "") {
+ AspellConfig *config = new_aspell_config();
+#ifdef WIN32
+ aspell_config_replace(config, "prefix", exeName);
+#endif
+ aspell_config_replace(config, "lang", _lang3.c_str());
+ aspell_config_replace(config, "encoding", "UTF-8");
+ AspellCanHaveError *ret = new_aspell_speller(config);
+ delete_aspell_config(config);
+ if (aspell_error(ret) != 0) {
+ g_warning("Error: %s\n", aspell_error_message(ret));
+ delete_aspell_can_have_error(ret);
+ return false;
+ }
+ _speller3 = to_aspell_speller(ret);
+ }
+
+ _root = sp_desktop_document(desktop)->getRoot();
+
+ // empty the list of objects we've checked
+ g_slist_free (_seen_objects);
+ _seen_objects = NULL;
+
+ // grab first text
+ nextText();
+
+ _working = true;
+
+ return true;
+}
+
+void
+SpellCheck::finished ()
+{
+ aspell_speller_save_all_word_lists(_speller);
+ delete_aspell_speller(_speller);
+ _speller = NULL;
+ if (_speller2) {
+ aspell_speller_save_all_word_lists(_speller2);
+ delete_aspell_speller(_speller2);
+ _speller2 = NULL;
+ }
+ if (_speller3) {
+ aspell_speller_save_all_word_lists(_speller3);
+ delete_aspell_speller(_speller3);
+ _speller3 = NULL;
+ }
+
+ clearRects();
+ disconnect();
+
+ //desktop->clearWaitingCursor();
+
+ tree_view.set_sensitive(false);
+ accept_button.set_sensitive(false);
+ ignore_button.set_sensitive(false);
+ ignoreonce_button.set_sensitive(false);
+ gtk_widget_set_sensitive(dictionary_combo, false);
+ add_button.set_sensitive(false);
+ stop_button.set_sensitive(false);
+ start_button.set_sensitive(true);
+
+ {
+ gchar *label;
+ if (_stops)
+ label = g_strdup_printf(_("<b>Finished</b>, <b>%d</b> words added to dictionary"), _adds);
+ else
+ label = g_strdup_printf(_("<b>Finished</b>, nothing suspicious found"));
+ banner_label.set_markup(label);
+ g_free(label);
+ }
+
+ g_slist_free(_seen_objects);
+ _seen_objects = NULL;
+
+ desktop = NULL;
+ _root = NULL;
+
+ _working = false;
+}
+
+bool
+SpellCheck::nextWord()
+{
+ if (!_working)
+ return false;
+
+ if (!_text) {
+ finished();
+ return false;
+ }
+ _word.clear();
+
+ while (_word.size() == 0) {
+ _begin_w = _end_w;
+
+ if (!_layout || _begin_w == _layout->end()) {
+ nextText();
+ return false;
+ }
+
+ if (!_layout->isStartOfWord(_begin_w)) {
+ _begin_w.nextStartOfWord();
+ }
+
+ _end_w = _begin_w;
+ _end_w.nextEndOfWord();
+ _word = sp_te_get_string_multiline (_text, _begin_w, _end_w);
+ }
+
+ // try to link this word with the next if separated by '
+ void *rawptr;
+ Glib::ustring::iterator text_iter;
+ _layout->getSourceOfCharacter(_end_w, &rawptr, &text_iter);
+ SPObject *char_item = SP_OBJECT(rawptr);
+ if (SP_IS_STRING(char_item)) {
+ int this_char = *text_iter;
+ if (this_char == '\'' || this_char == 0x2019) {
+ Inkscape::Text::Layout::iterator end_t = _end_w;
+ end_t.nextCharacter();
+ _layout->getSourceOfCharacter(end_t, &rawptr, &text_iter);
+ SPObject *char_item = SP_OBJECT(rawptr);
+ if (SP_IS_STRING(char_item)) {
+ int this_char = *text_iter;
+ if (g_ascii_isalpha(this_char)) { // 's
+ _end_w.nextEndOfWord();
+ _word = sp_te_get_string_multiline (_text, _begin_w, _end_w);
+ }
+ }
+ }
+ }
+
+ // skip words containing digits
+ if (_prefs->getInt(_prefs_path + "ignorenumbers") != 0) {
+ bool digits = false;
+ for (unsigned int i = 0; i < _word.size(); i++) {
+ if (g_unichar_isdigit(_word[i])) {
+ digits = true;
+ break;
+ }
+ }
+ if (digits) {
+ return false;
+ }
+ }
+
+ // skip ALL-CAPS words
+ if (_prefs->getInt(_prefs_path + "ignoreallcaps") != 0) {
+ bool allcaps = true;
+ for (unsigned int i = 0; i < _word.size(); i++) {
+ if (!g_unichar_isupper(_word[i])) {
+ allcaps = false;
+ break;
+ }
+ }
+ if (allcaps) {
+ return false;
+ }
+ }
+
+ // run it by all active spellers
+ int have = aspell_speller_check(_speller, _word.c_str(), -1);
+ if (_speller2)
+ have += aspell_speller_check(_speller2, _word.c_str(), -1);
+ if (_speller3)
+ have += aspell_speller_check(_speller3, _word.c_str(), -1);
+
+ if (have == 0) { // not found in any!
+ _stops ++;
+
+ //desktop->clearWaitingCursor();
+
+ // display it in window
+ {
+ Glib::ustring langs = _lang;
+ if (_lang2 != "")
+ langs = langs + ", " + _lang2;
+ if (_lang3 != "")
+ langs = langs + ", " + _lang3;
+ gchar *label = g_strdup_printf(_("Not in dictionary (%s): <b>%s</b>"), langs.c_str(), _word.c_str());
+ banner_label.set_markup(label);
+ g_free(label);
+ }
+
+ tree_view.set_sensitive(true);
+ ignore_button.set_sensitive(true);
+ ignoreonce_button.set_sensitive(true);
+ gtk_widget_set_sensitive(dictionary_combo, true);
+ add_button.set_sensitive(true);
+ stop_button.set_sensitive(true);
+
+ // draw rect
+ std::vector<Geom::Point> points =
+ _layout->createSelectionShape(_begin_w, _end_w, _text->i2dt_affine());
+ Geom::Point tl, br;
+ tl = br = points.front();
+ for (unsigned i = 0 ; i < points.size() ; i ++) {
+ if (points[i][Geom::X] < tl[Geom::X])
+ tl[Geom::X] = points[i][Geom::X];
+ if (points[i][Geom::Y] < tl[Geom::Y])
+ tl[Geom::Y] = points[i][Geom::Y];
+ if (points[i][Geom::X] > br[Geom::X])
+ br[Geom::X] = points[i][Geom::X];
+ if (points[i][Geom::Y] > br[Geom::Y])
+ br[Geom::Y] = points[i][Geom::Y];
+ }
+
+ // expand slightly
+ Geom::Rect area = Geom::Rect(tl, br);
+ double mindim = fabs(tl[Geom::Y] - br[Geom::Y]);
+ if (fabs(tl[Geom::X] - br[Geom::X]) < mindim)
+ mindim = fabs(tl[Geom::X] - br[Geom::X]);
+ area.expandBy(MAX(0.05 * mindim, 1));
+
+ // create canvas path rectangle, red stroke
+ SPCanvasItem *rect = sp_canvas_bpath_new(sp_desktop_sketch(desktop), NULL);
+ sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(rect), 0xff0000ff, 3.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
+ sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(rect), 0, SP_WIND_RULE_NONZERO);
+ SPCurve *curve = new SPCurve();
+ curve->moveto(area.corner(0));
+ curve->lineto(area.corner(1));
+ curve->lineto(area.corner(2));
+ curve->lineto(area.corner(3));
+ curve->lineto(area.corner(0));
+ sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(rect), curve);
+ sp_canvas_item_show(rect);
+ _rects = g_slist_prepend(_rects, rect);
+
+ // scroll to make it all visible
+ Geom::Point const center = desktop->get_display_area().midpoint();
+ area.expandBy(0.5 * mindim);
+ Geom::Point scrollto;
+ double dist = 0;
+ for (unsigned corner = 0; corner < 4; corner ++) {
+ if (Geom::L2(area.corner(corner) - center) > dist) {
+ dist = Geom::L2(area.corner(corner) - center);
+ scrollto = area.corner(corner);
+ }
+ }
+ desktop->scroll_to_point (scrollto, 1.0);
+
+ // select text; if in Text tool, position cursor to the beginning of word
+ // unless it is already in the word
+ if (desktop->selection->singleItem() != _text)
+ desktop->selection->set (_text);
+ if (tools_isactive(desktop, TOOLS_TEXT)) {
+ Inkscape::Text::Layout::iterator *cursor =
+ sp_text_context_get_cursor_position(SP_TEXT_CONTEXT(desktop->event_context), _text);
+ if (!cursor) // some other text is selected there
+ desktop->selection->set (_text);
+ else if (*cursor <= _begin_w || *cursor >= _end_w)
+ sp_text_context_place_cursor (SP_TEXT_CONTEXT(desktop->event_context), _text, _begin_w);
+ }
+
+ // get suggestions
+ {
+ model = Gtk::ListStore::create(tree_columns);
+ tree_view.set_model(model);
+
+ {
+ const AspellWordList *wl = aspell_speller_suggest(_speller, _word.c_str(), -1);
+ AspellStringEnumeration * els = aspell_word_list_elements(wl);
+ const char *sugg;
+ Gtk::TreeModel::iterator iter;
+
+ while ((sugg = aspell_string_enumeration_next(els)) != 0) {
+ iter = model->append();
+ Gtk::TreeModel::Row row = *iter;
+ row[tree_columns.suggestions] = sugg;
+ }
+ delete_aspell_string_enumeration(els);
+ }
+
+ if (_speller2) {
+ const AspellWordList *wl = aspell_speller_suggest(_speller2, _word.c_str(), -1);
+ AspellStringEnumeration * els = aspell_word_list_elements(wl);
+ const char *sugg;
+ Gtk::TreeModel::iterator iter;
+ while ((sugg = aspell_string_enumeration_next(els)) != 0) {
+ iter = model->append();
+ Gtk::TreeModel::Row row = *iter;
+ row[tree_columns.suggestions] = sugg;
+ }
+ delete_aspell_string_enumeration(els);
+ }
+
+ if (_speller3) {
+ const AspellWordList *wl = aspell_speller_suggest(_speller3, _word.c_str(), -1);
+ AspellStringEnumeration * els = aspell_word_list_elements(wl);
+ const char *sugg;
+ Gtk::TreeModel::iterator iter;
+ while ((sugg = aspell_string_enumeration_next(els)) != 0) {
+ iter = model->append();
+ Gtk::TreeModel::Row row = *iter;
+ row[tree_columns.suggestions] = sugg;
+ }
+ delete_aspell_string_enumeration(els);
+ }
+
+ accept_button.set_sensitive(false); // gray it out until something is chosen
+ }
+
+ return true;
+
+ }
+ return false;
+}
+
+
+
+void
+SpellCheck::deleteLastRect ()
+{
+ if (_rects) {
+ sp_canvas_item_hide(SP_CANVAS_ITEM(_rects->data));
+ gtk_object_destroy(GTK_OBJECT(_rects->data));
+ _rects = _rects->next; // pop latest-prepended rect
+ }
+}
+
+void SpellCheck::doSpellcheck ()
+{
+ banner_label.set_markup(_("<i>Checking...</i>"));
+
+ //desktop->setWaitingCursor();
+
+ while (_working)
+ if (nextWord())
+ break;
+}
+
+void SpellCheck::onTreeSelectionChange()
+{
+ accept_button.set_sensitive(true);
+}
+
+void SpellCheck::onObjModified (SPObject* /* blah */, unsigned int /* bleh */)
+{
+ if (_local_change) { // this was a change by this dialog, i.e. an Accept, skip it
+ _local_change = false;
+ return;
+ }
+
+ if (_working && _root) {
+ // user may have edited the text we're checking; try to do the most sensible thing in this
+ // situation
+
+ // just in case, re-get text's layout
+ _layout = te_get_layout (_text);
+
+ // re-get the word
+ _layout->validateIterator(&_begin_w);
+ _end_w = _begin_w;
+ _end_w.nextEndOfWord();
+ Glib::ustring word_new = sp_te_get_string_multiline (_text, _begin_w, _end_w);
+ if (word_new != _word) {
+ _end_w = _begin_w;
+ deleteLastRect ();
+ doSpellcheck (); // recheck this word and go ahead if it's ok
+ }
+ }
+}
+
+void SpellCheck::onObjReleased (SPObject* /* blah */)
+{
+ if (_working && _root) {
+ // the text object was deleted
+ deleteLastRect ();
+ nextText();
+ doSpellcheck (); // get next text and continue
+ }
+}
+
+void SpellCheck::onAccept ()
+{
+ // insert chosen suggestion
+
+ Glib::RefPtr<Gtk::TreeSelection> selection = tree_view.get_selection();
+ Gtk::TreeModel::iterator iter = selection->get_selected();
+ if (iter) {
+ Gtk::TreeModel::Row row = *iter;
+ Glib::ustring sugg = row[tree_columns.suggestions];
+
+ if (sugg.length() > 0) {
+ //g_print("chosen: %s\n", sugg);
+ _local_change = true;
+ sp_te_replace(_text, _begin_w, _end_w, sugg.c_str());
+ // find the end of the word anew
+ _end_w = _begin_w;
+ _end_w.nextEndOfWord();
+ DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT,
+ _("Fix spelling"));
+ }
+ }
+
+ deleteLastRect();
+ doSpellcheck();
+}
+
+void
+SpellCheck::onIgnore ()
+{
+ aspell_speller_add_to_session(_speller, _word.c_str(), -1);
+ if (_speller2)
+ aspell_speller_add_to_session(_speller2, _word.c_str(), -1);
+ if (_speller3)
+ aspell_speller_add_to_session(_speller3, _word.c_str(), -1);
+
+ deleteLastRect();
+ doSpellcheck();
+}
+
+void
+SpellCheck::onIgnoreOnce ()
+{
+ deleteLastRect();
+ doSpellcheck();
+}
+
+void
+SpellCheck::onAdd ()
+{
+ _adds++;
+
+ gint num = gtk_combo_box_get_active((GtkComboBox *)dictionary_combo);
+ switch (num) {
+ case 0:
+ aspell_speller_add_to_personal(_speller, _word.c_str(), -1);
+ break;
+ case 1:
+ if (_speller2)
+ aspell_speller_add_to_personal(_speller2, _word.c_str(), -1);
+ break;
+ case 2:
+ if (_speller3)
+ aspell_speller_add_to_personal(_speller3, _word.c_str(), -1);
+ break;
+ default:
+ break;
+ }
+
+ deleteLastRect();
+ doSpellcheck();
+}
+
+void
+SpellCheck::onStop ()
+{
+ finished();
+}
+
+void
+SpellCheck::onStart ()
+{
+ if (init (SP_ACTIVE_DESKTOP))
+ doSpellcheck();
+}
+
+
+}
+}
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/dialog/spellcheck.h b/src/ui/dialog/spellcheck.h
new file mode 100644
index 000000000..29ebc5d83
--- /dev/null
+++ b/src/ui/dialog/spellcheck.h
@@ -0,0 +1,280 @@
+/** @file
+ * @brief Spellcheck dialog
+ */
+/* Authors:
+ * bulia byak <bulia@users.sf.net>
+ *
+ * Copyright (C) 2009 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_SPELLCHECK_H
+#define SEEN_SPELLCHECK_H
+
+#include <gtk/gtk.h>
+
+#include <gtkmm/box.h>
+#include <gtkmm/textview.h>
+#include <gtkmm/button.h>
+#include <gtkmm/frame.h>
+#include <gtkmm/scrolledwindow.h>
+#include <gtkmm/separator.h>
+#include <gtkmm/liststore.h>
+#include <gtkmm/treeview.h>
+
+#include <glibmm/i18n.h>
+
+#include "desktop.h"
+#include "ui/dialog/desktop-tracker.h"
+#include "ui/widget/panel.h"
+#include "preferences.h"
+#include "sp-text.h"
+
+/* TODO - What is there is no ASPELL ?? */
+#ifdef HAVE_ASPELL
+#include <aspell.h>
+#endif
+
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+/**
+ *
+ * A dialog widget to checking spelling of text elements in the document
+ * Uses ASpell and one of the languages set in the users preference file
+ *
+ */
+class SpellCheck : public Widget::Panel {
+public:
+ SpellCheck ();
+ ~SpellCheck ();
+
+ static SpellCheck &getInstance() { return *new SpellCheck(); }
+
+private:
+
+ /**
+ * Remove the highlight rectangle form the canvas
+ */
+ void clearRects();
+
+ /**
+ * Release handlers to the selected item
+ */
+ void disconnect();
+
+ /**
+ * Returns a list of all the text items in the SPObject
+ */
+ GSList *allTextItems (SPObject *r, GSList *l, bool hidden, bool locked);
+
+ /**
+ * Is text inside the SPOject's tree
+ */
+ bool textIsValid (SPObject *root, SPItem *text);
+
+ /**
+ * Compare the visual bounds of 2 SPItems referred to by a and b
+ */
+ static gint compareTextBboxes (gconstpointer a, gconstpointer b);
+ SPItem *getText (SPObject *root);
+ void nextText ();
+
+ /**
+ * Initialize the controls and aspell
+ */
+ bool init (SPDesktop *desktop);
+
+ /**
+ * Cleanup after spellcheck is finished
+ */
+ void finished ();
+
+ /**
+ * Find the next word to spell check
+ */
+ bool nextWord();
+ void deleteLastRect ();
+ void doSpellcheck ();
+
+ /**
+ * Accept button clicked
+ */
+ void onAccept ();
+
+ /**
+ * Ignore button clicked
+ */
+ void onIgnore ();
+
+ /**
+ * Ignore once button clicked
+ */
+ void onIgnoreOnce ();
+
+ /**
+ * Add button clicked
+ */
+ void onAdd ();
+
+ /**
+ * Stop button clicked
+ */
+ void onStop ();
+
+ /**
+ * Start button clicked
+ */
+ void onStart ();
+
+ /**
+ * Selected object modified on canvas
+ */
+ void onObjModified (SPObject* /* blah */, unsigned int /* bleh */);
+
+ /**
+ * Selected object removed from canvas
+ */
+ void onObjReleased (SPObject* /* blah */);
+
+ /**
+ * Selection in suggestions text view changed
+ */
+ void onTreeSelectionChange();
+
+ /**
+ * Can be invoked for setting the desktop. Currently not used.
+ */
+ void setDesktop(SPDesktop *desktop);
+
+ /**
+ * Is invoked by the desktop tracker when the desktop changes.
+ */
+ void setTargetDesktop(SPDesktop *desktop);
+
+ SPObject *_root;
+
+ AspellSpeller *_speller;
+ AspellSpeller *_speller2;
+ AspellSpeller *_speller3;
+
+ /**
+ * list of canvasitems (currently just rects) that mark misspelled things on canvas
+ */
+ GSList *_rects;
+
+ /**
+ * list of text objects we have already checked in this session
+ */
+ GSList *_seen_objects;
+
+ /**
+ * the object currently being checked
+ */
+ SPItem *_text;
+
+ /**
+ * current objects layout
+ */
+ Inkscape::Text::Layout const *_layout;
+
+ /**
+ * iterators for the start and end of the current word
+ */
+ Inkscape::Text::Layout::iterator _begin_w;
+ Inkscape::Text::Layout::iterator _end_w;
+
+ /**
+ * the word we're checking
+ */
+ Glib::ustring _word;
+
+ /**
+ * counters for the number of stops and dictionary adds
+ */
+ int _stops;
+ int _adds;
+
+ /**
+ * true if we are in the middle of a check
+ */
+ bool _working;
+
+ /**
+ * connect to the object being checked in case it is modified or deleted by user
+ */
+ sigc::connection _modified_connection;
+ sigc::connection _release_connection;
+
+ /**
+ * true if the spell checker dialog has changed text, to suppress modified callback
+ */
+ bool _local_change;
+
+ Inkscape::Preferences *_prefs;
+
+ Glib::ustring _lang;
+ Glib::ustring _lang2;
+ Glib::ustring _lang3;
+
+ /**
+ * Dialogs widgets
+ */
+ Gtk::Label banner_label;
+ Gtk::HButtonBox banner_hbox;
+ Gtk::ScrolledWindow scrolled_window;
+ Gtk::TreeView tree_view;
+ Glib::RefPtr<Gtk::ListStore> model;
+
+ Gtk::HBox suggestion_hbox;
+ Gtk::VBox changebutton_vbox;
+ Gtk::Button accept_button;
+ Gtk::Button ignoreonce_button;
+ Gtk::Button ignore_button;
+
+ Gtk::Button add_button;
+ GtkWidget * dictionary_combo;
+ Gtk::HBox dictionary_hbox;
+
+ Gtk::HSeparator action_sep;
+ Gtk::Button stop_button;
+ Gtk::Button start_button;
+ Gtk::HButtonBox actionbutton_hbox;
+
+ SPDesktop * desktop;
+ DesktopTracker deskTrack;
+ sigc::connection desktopChangeConn;
+
+ class TreeColumns : public Gtk::TreeModel::ColumnRecord
+ {
+ public:
+ TreeColumns()
+ {
+ add(suggestions);
+ }
+ virtual ~TreeColumns() {}
+ Gtk::TreeModelColumn<Glib::ustring> suggestions;
+ };
+ TreeColumns tree_columns;
+
+};
+
+}
+}
+}
+
+#endif /* !SEEN_SPELLCHECK_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/verbs.cpp b/src/verbs.cpp
index afdeb665a..1a17391b6 100644
--- a/src/verbs.cpp
+++ b/src/verbs.cpp
@@ -41,7 +41,6 @@
#include "desktop-handles.h"
#include "dialogs/clonetiler.h"
#include "dialogs/find.h"
-#include "dialogs/spellcheck.h"
#include "dialogs/xml-tree.h"
#include "display/curve.h"
#include "document.h"
@@ -79,6 +78,7 @@
#include "ui/dialog/layers.h"
#include "ui/dialog/object-properties.h"
#include "ui/dialog/swatches.h"
+#include "ui/dialog/spellcheck.h"
#include "ui/icon-names.h"
#include "ui/tool/node-tool.h"
@@ -1830,7 +1830,7 @@ void DialogVerb::perform(SPAction *action, void *data)
// not implemented yet
break;
case SP_VERB_DIALOG_SPELLCHECK:
- sp_spellcheck_dialog();
+ dt->_dlg_mgr->showDialog("SpellCheck");
break;
case SP_VERB_DIALOG_DEBUG:
dt->_dlg_mgr->showDialog("Messages");