diff options
| author | John Smith <john.smith7545@yahoo.com> | 2012-02-21 13:26:58 +0000 |
|---|---|---|
| committer | John Smith <removethis.john.q.public@bigmail.com> | 2012-02-21 13:26:58 +0000 |
| commit | 5a97256cdaa9cc74e50b05aaf6a491f2df6fda0f (patch) | |
| tree | 243844f1ed4140f61458fbd435f0194ed37b6d42 /src | |
| parent | Copy missing libintl-8.dll in build.xml (diff) | |
| download | inkscape-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_insert | 2 | ||||
| -rw-r--r-- | src/dialogs/spellcheck.cpp | 1060 | ||||
| -rw-r--r-- | src/dialogs/spellcheck.h | 31 | ||||
| -rw-r--r-- | src/ui/context-menu.cpp | 5 | ||||
| -rw-r--r-- | src/ui/dialog/Makefile_insert | 2 | ||||
| -rw-r--r-- | src/ui/dialog/dialog-manager.cpp | 4 | ||||
| -rw-r--r-- | src/ui/dialog/spellcheck.cpp | 871 | ||||
| -rw-r--r-- | src/ui/dialog/spellcheck.h | 280 | ||||
| -rw-r--r-- | src/verbs.cpp | 4 |
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"); |
