Code

Fix build failure
[inkscape.git] / src / dialogs / spellcheck.cpp
index 8f4a434def8cad2a1bcbe7e979ed74bc36fa7d62..22d440b5f9840ac289c6252eb8232b8a45273d5b 100644 (file)
@@ -3,6 +3,8 @@
  */
 /* Authors:
  *   bulia byak <bulia@users.sf.net>
+ *   Jon A. Cruz <jon@joncruz.org>
+ *   Abhishek Sharma
  *
  * Copyright (C) 2009 Authors
  *
@@ -12,7 +14,6 @@
 #include "widgets/icon.h"
 #include "message-stack.h"
 
-#include <aspell.h>
 #include <gtk/gtk.h>
 
 #include <glibmm/i18n.h>
 #include <xml/repr.h>
 #include "display/canvas-bpath.h"
 #include "display/curve.h"
+#include "document-undo.h"
+
+#ifdef HAVE_ASPELL
+#include <aspell.h>
 
 #ifdef WIN32
 #include <windows.h>
@@ -58,9 +63,12 @@ static Glib::ustring const prefs_path = "/dialogs/spellcheck/";
 // plain-C GTK callbacks.
 
 static SPDesktop *_desktop = NULL;
-static AspellSpeller *_speller = 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;
 
@@ -93,6 +101,11 @@ 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()
@@ -105,6 +118,22 @@ void spellcheck_clear_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()
 {
@@ -123,6 +152,7 @@ spellcheck_disconnect()
 static void sp_spellcheck_dialog_destroy(GtkObject *object, gpointer)
 {
     spellcheck_clear_rects();
+    spellcheck_clear_langs();
     spellcheck_disconnect();
 
     sp_signal_disconnect_by_data (INKSCAPE, object);
@@ -134,6 +164,7 @@ static void sp_spellcheck_dialog_destroy(GtkObject *object, gpointer)
 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);
@@ -142,11 +173,10 @@ static gboolean sp_spellcheck_dialog_delete(GtkObject *, GdkEvent *, gpointer /*
     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);
+    _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
 }
@@ -173,10 +203,11 @@ all_text_items (SPObject *r, GSList *l, bool hidden, bool locked)
     if (SP_IS_DEFS(r))
         return l; // we're not interested in items in defs
 
-    if (!strcmp (SP_OBJECT_REPR (r)->name(), "svg:metadata"))
+    if (!strcmp(r->getRepr()->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)) {
+    for (SPObject *child = r->firstChild(); child; child = child->next) {
         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))
@@ -209,8 +240,8 @@ 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));
+    Geom::OptRect bbox1 = i1->getBounds(i1->i2d_affine());
+    Geom::OptRect bbox2 = i2->getBounds(i2->i2d_affine());
     if (!bbox1 || !bbox2) {
         return 0;
     }
@@ -294,16 +325,11 @@ spellcheck_init(SPDesktop *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);
 
-    _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
@@ -313,20 +339,19 @@ spellcheck_init(SPDesktop *desktop)
     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");
+    _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");
-
-    // create speller
     AspellCanHaveError *ret = new_aspell_speller(config);
     delete_aspell_config(config);
     if (aspell_error(ret) != 0) {
@@ -335,8 +360,43 @@ spellcheck_init(SPDesktop *desktop)
         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);
+    }
 
-    _root = SP_DOCUMENT_ROOT (sp_desktop_document (desktop));
+    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);
@@ -356,6 +416,16 @@ 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();
@@ -365,7 +435,9 @@ spellcheck_finished ()
     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);
 
@@ -441,20 +513,41 @@ spellcheck_next_word()
     }
 
     // skip words containing digits
-    bool digits = false;
-    for (gchar *c = (gchar *) _word.c_str(); *c; c++) {
-        if (g_ascii_isdigit(*c)) {
-            digits = true;
+    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;
         }
-    }
-    if (digits) {
-        return false;
     }
 
-    //g_print ("%s\n", word.c_str());
+    // 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 (have == 0) { // not found
+    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();
@@ -462,19 +555,26 @@ spellcheck_next_word()
         // 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());
+            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, sp_item_i2d_affine(_text));
+            _layout->createSelectionShape(_begin_w, _end_w, _text->i2d_affine());
         Geom::Point tl, br;
         tl = br = points.front();
         for (unsigned i = 0 ; i < points.size() ; i ++) {
@@ -537,13 +637,15 @@ spellcheck_next_word()
 
         // 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));
+
+            {
+            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);
@@ -553,6 +655,38 @@ spellcheck_next_word()
                                     -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
         }
 
@@ -647,8 +781,8 @@ sp_spellcheck_accept (GObject *, GObject *dlg)
             // 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"));
+            Inkscape::DocumentUndo::done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_TEXT,
+                                 _("Fix spelling"));
         }
     }
 
@@ -661,6 +795,18 @@ 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
@@ -670,7 +816,25 @@ void
 sp_spellcheck_add (GObject */*obj*/, GObject */*dlg*/)
 {
     _adds++;
-    aspell_speller_add_to_personal(_speller, _word.c_str(), -1);
+    GtkComboBox *cbox =
+        GTK_COMBO_BOX(gtk_object_get_data (GTK_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
@@ -703,20 +867,35 @@ static gboolean spellcheck_desktop_deactivated(Inkscape::Application */*applicat
 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);
-        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);
+            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);
+            w = _prefs->getInt(prefs_path + "w", 0);
+            h = _prefs->getInt(prefs_path + "h", 0);
         }
 
         if (w && h)
@@ -791,10 +970,29 @@ sp_spellcheck_dialog (void)
             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 once"), tt, _("Ignore this word only once"),
+                                      sp_spellcheck_ignore_once, "b_ignore_once");
             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"),
+            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:"), tt, _("Add this word to the chosen dictionary"),
                                       sp_spellcheck_add, "b_add");
+            GtkComboBox *cbox = GTK_COMBO_BOX (gtk_combo_box_new_text());
+            gtk_combo_box_append_text (cbox,  _lang);
+            if (_lang2) {
+                gtk_combo_box_append_text (cbox, _lang2);
+            }
+            if (_lang3) {
+                gtk_combo_box_append_text (cbox, _lang3);
+            }
+            gtk_combo_box_set_active (cbox, 0);
+            gtk_widget_show_all (GTK_WIDGET(cbox));
+            g_object_set_data (G_OBJECT (dlg), "addto_langs", cbox);
+            gtk_box_pack_start (GTK_BOX (hb), GTK_WIDGET(cbox), TRUE, TRUE, 0);
             gtk_box_pack_start (GTK_BOX (vb), hb, FALSE, FALSE, 0);
         }
 
@@ -821,6 +1019,12 @@ sp_spellcheck_dialog (void)
     sp_spellcheck_start (NULL, NULL);
 }
 
+#else 
+
+void sp_spellcheck_dialog (void) {}
+
+#endif // HAVE_ASPELL
+
 
 /*
   Local Variables:
@@ -831,4 +1035,4 @@ sp_spellcheck_dialog (void)
   fill-column:99
   End:
 */
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :