summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 640481f)
raw | patch | inline | side by side (parent: 640481f)
author | buliabyak <buliabyak@users.sourceforge.net> | |
Tue, 17 Feb 2009 20:33:18 +0000 (20:33 +0000) | ||
committer | buliabyak <buliabyak@users.sourceforge.net> | |
Tue, 17 Feb 2009 20:33:18 +0000 (20:33 +0000) |
src/dialogs/Makefile_insert | patch | blob | history | |
src/dialogs/spellcheck.cpp | [new file with mode: 0644] | patch | blob |
src/dialogs/spellcheck.h | [new file with mode: 0644] | patch | blob |
src/menus-skeleton.h | patch | blob | history | |
src/preferences-skeleton.h | patch | blob | history | |
src/verbs.cpp | patch | blob | history | |
src/verbs.h | patch | blob | history |
index 5d561466849f3cc3c131d46d21ff04d4f6475c4c..1b3358506a5e19cf9cc8e425da712742fa791f4d 100644 (file)
dialogs/rdf.h \
dialogs/sp-attribute-widget.cpp \
dialogs/sp-attribute-widget.h \
+ dialogs/spellcheck.cpp \
+ dialogs/spellcheck.h \
dialogs/stroke-style.cpp \
dialogs/stroke-style.h \
dialogs/swatches.cpp \
diff --git a/src/dialogs/spellcheck.cpp b/src/dialogs/spellcheck.cpp
--- /dev/null
@@ -0,0 +1,834 @@
+/** @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
+ */
+
+#include "widgets/icon.h"
+#include "message-stack.h"
+
+#include <aspell.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"
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#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 AspellSpeller *_speller = NULL;
+static SPObject *_root;
+
+// 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;
+
+
+
+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_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)
+{
+ spellcheck_clear_rects();
+ 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_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;
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ 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, GtkTooltips *tt, const gchar *tip, void (*function) (GObject *, GObject *), const gchar *cookie)
+{
+ GtkWidget *b = gtk_button_new_with_mnemonic (label);
+ gtk_tooltips_set_tip (tt, b, tip, NULL);
+ gtk_box_pack_start (GTK_BOX (hb), b, TRUE, TRUE, 0);
+ g_signal_connect ( G_OBJECT (b), "clicked", G_CALLBACK (function), dlg );
+ gtk_object_set_data (GTK_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 (SP_OBJECT_REPR (r)->name(), "svg:metadata"))
+ return l; // we're not interested in metadata
+
+ for (SPObject *child = sp_object_first_child(r); child; child = SP_OBJECT_NEXT (child)) {
+ if (SP_IS_ITEM (child) && !SP_OBJECT_IS_CLONED (child) && !_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 = (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->getBounds(sp_item_i2d_affine(i1));
+ Geom::OptRect bbox2 = i2->getBounds(sp_item_i2d_affine(i2));
+ 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 = (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(gtk_object_get_data (GTK_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_add", FALSE);
+ spellcheck_sensitive("b_start", FALSE);
+
+ _stops = 0;
+ _adds = 0;
+
+ spellcheck_clear_rects();
+
+ AspellConfig *config = new_aspell_config();
+
+#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);
+ aspell_config_replace(config, "prefix", exeName);
+#endif
+
+ // take language from prefs
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ Glib::ustring lang = prefs->getString(prefs_path + "lang");
+ if (lang != "")
+ aspell_config_replace(config, "lang", lang.c_str());
+ else
+ aspell_config_replace(config, "lang", "en_US");
+
+ aspell_config_replace(config, "encoding", "UTF-8");
+
+ // create speller
+ 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);
+
+ _root = SP_DOCUMENT_ROOT (sp_desktop_document (desktop));
+
+ // 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;
+
+ spellcheck_clear_rects();
+ spellcheck_disconnect();
+
+ _desktop->clearWaitingCursor();
+
+ spellcheck_sensitive("suggestions", FALSE);
+ spellcheck_sensitive("b_accept", FALSE);
+ spellcheck_sensitive("b_ignore", FALSE);
+ spellcheck_sensitive("b_add", FALSE);
+ spellcheck_sensitive("b_stop", FALSE);
+ spellcheck_sensitive("b_start", TRUE);
+
+ {
+ GtkWidget *l = GTK_WIDGET(gtk_object_get_data (GTK_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
+ bool digits = false;
+ for (gchar *c = (gchar *) _word.c_str(); *c; c++) {
+ if (g_ascii_isdigit(*c)) {
+ digits = true;
+ }
+ }
+ if (digits) {
+ return false;
+ }
+
+ //g_print ("%s\n", word.c_str());
+
+ int have = aspell_speller_check(_speller, _word.c_str(), -1);
+ if (have == 0) { // not found
+ _stops ++;
+
+ _desktop->clearWaitingCursor();
+
+ // display it in window
+ {
+ GtkWidget *l = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (dlg), "banner"));
+ gchar *label = g_strdup_printf(_("Not in dictionary: <b>%s</b>"), _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_add", TRUE);
+ spellcheck_sensitive("b_stop", TRUE);
+
+ // draw rect
+ std::vector<Geom::Point> points =
+ _layout->createSelectionShape(_begin_w, _end_w, sp_item_i2d_affine(_text));
+ 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);
+
+ // if in Text tool, position cursor to the beginnign of word
+ // unless it is already in the word
+ 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);
+ } else { // just select the object
+ _desktop->selection->set (_text);
+ }
+
+ // get suggestions
+ {
+ const AspellWordList *wl = aspell_speller_suggest(_speller, _word.c_str(), -1);
+ AspellStringEnumeration * els = aspell_word_list_elements(wl);
+ const char *sugg;
+ GtkTreeView *tree_view =
+ GTK_TREE_VIEW(gtk_object_get_data (GTK_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));
+ 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(gtk_object_get_data (GTK_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(dlg)->window, 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(gtk_object_get_data (GTK_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();
+ sp_document_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 *, GObject *dlg)
+{
+ aspell_speller_add_to_session(_speller, _word.c_str(), -1);
+ spellcheck_delete_last_rect ();
+
+ do_spellcheck(); // next word or end
+}
+
+void
+sp_spellcheck_add (GObject *, GObject *dlg)
+{
+ _adds++;
+ aspell_speller_add_to_personal(_speller, _word.c_str(), -1);
+ spellcheck_delete_last_rect ();
+
+ do_spellcheck(); // next word or end
+}
+
+void
+sp_spellcheck_stop (GObject *, 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)
+{
+ if (!dlg)
+ {
+ gchar title[500];
+ sp_ui_dialog_title_string (Inkscape::Verb::get(SP_VERB_DIALOG_SPELLCHECK), title);
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ 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);
+ }
+
+ 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);
+
+
+ gtk_signal_connect ( GTK_OBJECT (dlg), "event", GTK_SIGNAL_FUNC (sp_dialog_event_handler), dlg);
+
+ gtk_signal_connect ( GTK_OBJECT (dlg), "destroy", G_CALLBACK (sp_spellcheck_dialog_destroy), NULL );
+ gtk_signal_connect ( GTK_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);
+
+ GtkTooltips *tt = gtk_tooltips_new ();
+
+ 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);
+ gtk_object_set_data (GTK_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 ();
+ gtk_object_set_data (GTK_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"), tt, _("Accept the chosen suggestion"),
+ sp_spellcheck_accept, "b_accept");
+ sp_spellcheck_new_button (dlg, hb, _("_Ignore"), tt, _("Ignore this word in this session"),
+ sp_spellcheck_ignore, "b_ignore");
+ sp_spellcheck_new_button (dlg, hb, _("A_dd"), tt, _("Add this word to the dictionary"),
+ sp_spellcheck_add, "b_add");
+ 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"), tt, _("Stop the check"),
+ sp_spellcheck_stop, "b_stop");
+ sp_spellcheck_new_button (dlg, hb, _("_Start"), tt, _("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);
+}
+
+
+/*
+ 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:encoding=utf-8:textwidth=99 :
diff --git a/src/dialogs/spellcheck.h b/src/dialogs/spellcheck.h
--- /dev/null
+++ b/src/dialogs/spellcheck.h
@@ -0,0 +1,31 @@
+/** @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/gtkstyle.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/menus-skeleton.h b/src/menus-skeleton.h
index 9840a1aa15d246b02da40c52907a5623b80691bb..5d110483dc3144beae7ebbbe6af5709b72f0bb90 100644 (file)
--- a/src/menus-skeleton.h
+++ b/src/menus-skeleton.h
" <verb verb-id=\"ObjectFlowtextToText\" />\n"
" <separator/>\n"
" <verb verb-id=\"SelectionTextRemoveKerns\" />\n"
+" <separator/>\n"
+" <verb verb-id=\"DialogSpellcheck\" />\n"
" </submenu>\n"
" <submenu name=\"" N_("Filter_s") "\">\n"
" <filters-list/>\n"
index 64a2b4ba1cd95793de890ba3a8f4b4af1bbbd514..65d30d6a6e120147372ffc8797839a2cc5a6727d 100644 (file)
" <group id=\"align\"/>\n"
" <group id=\"xml\"/>\n"
" <group id=\"find\"/>\n"
+" <group id=\"spellcheck\" w=\"200\" h=\"250\" lang=\"en_US\"/>\n"
" <group id=\"documentoptions\" state=\"1\"/>\n"
" <group id=\"preferences\" state=\"1\"/>\n"
" <group id=\"gradienteditor\"/>\n"
diff --git a/src/verbs.cpp b/src/verbs.cpp
index 78c4423f51efb1603199602dff2402360456c583..56d4e667d98040041e04d6bb530326da261b2785 100644 (file)
--- a/src/verbs.cpp
+++ b/src/verbs.cpp
#include "dialogs/xml-tree.h"
#include "dialogs/item-properties.h"
#include "dialogs/find.h"
+#include "dialogs/spellcheck.h"
#include "dialogs/layer-properties.h"
#include "dialogs/clonetiler.h"
#include "dialogs/iconpreview.h"
// Please test the new find dialog if you have time:
// dt->_dlg_mgr->showDialog("Find");
break;
+ case SP_VERB_DIALOG_FINDREPLACE:
+ // not implemented yet
+ break;
+ case SP_VERB_DIALOG_SPELLCHECK:
+ sp_spellcheck_dialog();
+ break;
case SP_VERB_DIALOG_DEBUG:
dt->_dlg_mgr->showDialog("Messages");
break;
N_("View and edit the XML tree of the document"), "xml_editor"),
new DialogVerb(SP_VERB_DIALOG_FIND, "DialogFind", N_("_Find..."),
N_("Find objects in document"), GTK_STOCK_FIND ),
+ new DialogVerb(SP_VERB_DIALOG_FINDREPLACE, "DialogFindReplace", N_("Find and _Replace Text..."),
+ N_("Find and replace text in document"), GTK_STOCK_FIND_AND_REPLACE ),
+ new DialogVerb(SP_VERB_DIALOG_SPELLCHECK, "DialogSpellcheck", N_("Check Spellin_g..."),
+ N_("Check spelling of text in document"), GTK_STOCK_SPELL_CHECK ),
new DialogVerb(SP_VERB_DIALOG_DEBUG, "DialogDebug", N_("_Messages..."),
N_("View debug messages"), "messages"),
new DialogVerb(SP_VERB_DIALOG_SCRIPT, "DialogScript", N_("S_cripts..."),
diff --git a/src/verbs.h b/src/verbs.h
index 7798f63640fec566f999bf96984e543cdb5dc31b..c3b88918b7bac4311e2639d6523f00d557b4edc9 100644 (file)
--- a/src/verbs.h
+++ b/src/verbs.h
SP_VERB_DIALOG_TEXT,
SP_VERB_DIALOG_XML_EDITOR,
SP_VERB_DIALOG_FIND,
+ SP_VERB_DIALOG_FINDREPLACE,
+ SP_VERB_DIALOG_SPELLCHECK,
SP_VERB_DIALOG_DEBUG,
SP_VERB_DIALOG_SCRIPT,
SP_VERB_DIALOG_TOGGLE,