Logo Search packages:      
Sourcecode: katoob version File versions  Download package

spelldlg.c

/* Katoob
 * Copyright (c) 2002,2003 Arabeyes, Mohammed Sameer.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef HAVE_SPELL

#include "katoob.h"
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <string.h>
#include "katoobdocument.h"
#include "spelldlg.h"
#include "misc.h"
#include "mdi.h"
#include "spell-private.h"

GtkWidget *spelldialog = NULL;
GtkTreeModel *model;
AspellSpeller *speller;
GtkWidget *fubar;
GtkWidget *yes_img;
GtkWidget *no_img;

static GtkTreeModel *create_model ();
static void add_suggestion (gchar * s);
static void clear_suggestions ();
static gboolean katoob_spelldlg_check_range (KatoobDocument * doc,
                                   GtkTextBuffer * buffer,
                                   gchar ** word, gboolean mark);
static void tree_selection_changed (GtkTreeSelection * selection,
                            gpointer data);
static void build_suggestions (gchar * word, GtkWidget * entry);
static GtkWidget *create_spelldlg (gchar * word);
static void spelldlg_closeb_clicked ();
static void katoob_destroy_spelldlg ();
void add_cb (GtkButton * button, gpointer user_data);
void ignore_cb (GtkButton * button, gpointer user_data);
void change_cb (GtkButton * button, gpointer user_data);
void check_cb (GtkButton * button, gpointer user_data);
static void get_next_word (KatoobDocument * doc, GtkWidget * entry);

void
katoob_create_spelldlg ()
{
  extern UI *katoob;
  KatoobDocument *doc;
  gchar *word = NULL;
  GtkWidget *entry = NULL;

  doc = katoob_get_active_doc ();

  if (!doc)
    {
      return;
    }

  if (spelldialog)
    {
      gtk_window_present (GTK_WINDOW (spelldialog));
      return;
    }

  if ((!katoob_document_get_modified (doc))
      && (!katoob_document_get_file (doc)))
    {
      katoob_info (_("The document is empty."));
      return;
    }

  if (!katoob_document_get_speller (doc))
    {
      katoob_error(_("There is no spellchecking dictionary available, Please make sure that you have installed at least one."));
      return;
    }

/* First we check if there is a mispelled word or not. */
  if (!katoob_spelldlg_check_range
      (doc, katoob_document_get_buffer (doc), &word, FALSE))
    {
      katoob_info (_("No misspelled words."));
      return;
    }

  spelldialog = create_spelldlg (word);
  g_object_set_data (G_OBJECT (spelldialog), "document", doc);

  gtk_window_set_transient_for (GTK_WINDOW (spelldialog),
                        GTK_WINDOW (katoob->win));
  entry = (GtkWidget *) g_object_get_data (G_OBJECT (spelldialog), "entry");
  gtk_entry_set_text (GTK_ENTRY (entry), word);
  gtk_widget_show_all (spelldialog);
  gtk_widget_hide (yes_img);
  speller = katoob_document_get_speller (doc);
  build_suggestions (word, entry);

  g_free (word);
/* NOTE: If you ommit these lines, The first mispelled word'll not be 
highlighted, Any ideas ?? */
  katoob_spelldlg_check_range
    (doc, katoob_document_get_buffer (doc), &word, FALSE);
  g_free (word);
}

static GtkWidget *
create_spelldlg (gchar * word)
{
  GtkWidget *spelldlg;
  GtkWidget *dialog_vbox;
  GtkWidget *vbox;
  GtkWidget *table;
  GtkWidget *check;
  GtkWidget *alignment2;
  GtkWidget *hbox3;
  GtkWidget *image3;
  GtkWidget *label5;
  GtkWidget *mispelled;
  GtkWidget *change;
  GtkWidget *hbox;
  GtkWidget *vbox2;
  GtkWidget *change_b;
  GtkWidget *ignore;
  GtkWidget *add;
  GtkWidget *alignment1;
  GtkWidget *hbox2;
  GtkWidget *image1;
  GtkWidget *label1;
  GtkWidget *dialog_action_area;
  GtkWidget *closebutton;
  GtkWidget *img_box;
  GtkTreeSelection *select;
  GtkWidget *treeview;
  GtkTreeViewColumn *column;
  GtkCellRenderer *renderer;
  GtkWidget *sw;
  GtkWidget *entry;

  spelldlg = gtk_dialog_new ();
  gtk_window_set_title (GTK_WINDOW (spelldlg), _("Check Spelling"));
  gtk_window_set_modal (GTK_WINDOW (spelldlg), TRUE);
  gtk_window_set_resizable (GTK_WINDOW (spelldlg), FALSE);
  gtk_window_set_position (GTK_WINDOW (spelldlg), GTK_WIN_POS_CENTER);

  dialog_vbox = GTK_DIALOG (spelldlg)->vbox;

  vbox = gtk_vbox_new (FALSE, 0);
  gtk_box_pack_start (GTK_BOX (dialog_vbox), vbox, TRUE, TRUE, 5);
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);

  img_box = gtk_hbox_new (FALSE, 0);
  yes_img = gtk_image_new_from_stock ("gtk-yes", GTK_ICON_SIZE_BUTTON);
  no_img = gtk_image_new_from_stock ("gtk-no", GTK_ICON_SIZE_BUTTON);
  gtk_box_pack_start (GTK_BOX (img_box), yes_img, FALSE, FALSE, 0);
  gtk_box_pack_start (GTK_BOX (img_box), no_img, FALSE, FALSE, 0);

  table = gtk_table_new (2, 3, FALSE);
  gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
  gtk_container_set_border_width (GTK_CONTAINER (table), 5);
  gtk_table_set_col_spacings (GTK_TABLE (table), 5);

  gtk_table_attach (GTK_TABLE (table), img_box, 2, 3, 0, 1,
                (GtkAttachOptions) (GTK_FILL),
                (GtkAttachOptions) (0), 0, 0);

  check = gtk_button_new ();
  g_object_set_data (G_OBJECT (check), "user_data", spelldlg);

  gtk_table_attach (GTK_TABLE (table), check, 2, 3, 1, 2,
                (GtkAttachOptions) (GTK_FILL),
                (GtkAttachOptions) (0), 0, 0);

  alignment2 = gtk_alignment_new (0.5, 0.5, 0, 0);
  gtk_container_add (GTK_CONTAINER (check), alignment2);

  hbox3 = gtk_hbox_new (FALSE, 2);
  gtk_container_add (GTK_CONTAINER (alignment2), hbox3);

  image3 = gtk_image_new_from_stock ("gtk-spell-check", GTK_ICON_SIZE_BUTTON);
  gtk_box_pack_start (GTK_BOX (hbox3), image3, FALSE, FALSE, 0);

  label5 = gtk_label_new_with_mnemonic (_("Check _Spelling"));
  gtk_box_pack_start (GTK_BOX (hbox3), label5, FALSE, FALSE, 0);
  gtk_label_set_justify (GTK_LABEL (label5), GTK_JUSTIFY_LEFT);

  mispelled = gtk_label_new (_("Mispelled:"));
  gtk_table_attach (GTK_TABLE (table), mispelled, 0, 1, 0, 1,
                (GtkAttachOptions) (GTK_FILL),
                (GtkAttachOptions) (0), 5, 5);
  gtk_label_set_justify (GTK_LABEL (mispelled), GTK_JUSTIFY_LEFT);
  gtk_misc_set_alignment (GTK_MISC (mispelled), 0, 0.5);

  change = gtk_label_new (_("Change to:"));
  gtk_table_attach (GTK_TABLE (table), change, 0, 1, 1, 2,
                (GtkAttachOptions) (GTK_FILL),
                (GtkAttachOptions) (0), 5, 5);
  gtk_label_set_justify (GTK_LABEL (change), GTK_JUSTIFY_LEFT);
  gtk_misc_set_alignment (GTK_MISC (change), 0, 0.5);

  fubar = gtk_label_new (word);
  gtk_table_attach (GTK_TABLE (table), fubar, 1, 2, 0, 1,
                (GtkAttachOptions) (GTK_FILL),
                (GtkAttachOptions) (0), 5, 5);
  gtk_label_set_justify (GTK_LABEL (fubar), GTK_JUSTIFY_LEFT);
  gtk_misc_set_alignment (GTK_MISC (fubar), 0, 0.5);

  entry = gtk_entry_new ();
  gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2,
                (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
                (GtkAttachOptions) (0), 0, 0);
  gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
  g_object_set_data (G_OBJECT (spelldlg), "entry", entry);

  hbox = gtk_hbox_new (FALSE, 0);
  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);

/* Damn tree view! */
  model = create_model ();
  sw = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW
                          (sw),
                          GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  treeview = gtk_tree_view_new_with_model (model);
  gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
/*  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); */
  g_object_unref (G_OBJECT (model));
  gtk_container_add (GTK_CONTAINER (sw), treeview);
  gtk_box_pack_start (GTK_BOX (hbox), sw, TRUE, TRUE, 0);

  renderer = gtk_cell_renderer_text_new ();
  column = gtk_tree_view_column_new_with_attributes (_("Suggestions"),
                                         renderer,
                                         "text", 0, NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);

  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
  gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);

  g_signal_connect (G_OBJECT (select), "changed",
                G_CALLBACK (tree_selection_changed), entry);

  model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));     /* WTH! */

/* End tree view! */

  vbox2 = gtk_vbox_new (TRUE, 5);
  gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, TRUE, 0);
  gtk_container_set_border_width (GTK_CONTAINER (vbox2), 3);

  change_b = gtk_button_new_with_mnemonic (_("C_hange"));
  g_object_set_data (G_OBJECT (change_b), "user_data", spelldlg);
  gtk_box_pack_start (GTK_BOX (vbox2), change_b, FALSE, TRUE, 0);
  g_object_set_data (G_OBJECT (change_b), "entry", entry);

  ignore = gtk_button_new_with_mnemonic (_("_Ignore"));
  g_object_set_data (G_OBJECT (ignore), "user_data", spelldlg);
  gtk_box_pack_start (GTK_BOX (vbox2), ignore, FALSE, TRUE, 0);
  g_object_set_data (G_OBJECT (ignore), "entry", entry);

  add = gtk_button_new ();
  g_object_set_data (G_OBJECT (add), "user_data", spelldlg);
  gtk_box_pack_start (GTK_BOX (vbox2), add, FALSE, TRUE, 0);
  g_object_set_data (G_OBJECT (add), "entry", entry);

/* Now for the "check" button */
  g_object_set_data (G_OBJECT (check), "user_data", spelldlg);
  g_object_set_data (G_OBJECT (check), "entry", entry);

  alignment1 = gtk_alignment_new (0.5, 0.5, 0, 0);
  gtk_container_add (GTK_CONTAINER (add), alignment1);

  hbox2 = gtk_hbox_new (FALSE, 2);
  gtk_container_add (GTK_CONTAINER (alignment1), hbox2);

  image1 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_BUTTON);
  gtk_box_pack_start (GTK_BOX (hbox2), image1, FALSE, FALSE, 0);

  label1 = gtk_label_new_with_mnemonic (_("_Add to user dictionary"));
  gtk_box_pack_start (GTK_BOX (hbox2), label1, FALSE, FALSE, 0);
  gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_LEFT);

  dialog_action_area = GTK_DIALOG (spelldlg)->action_area;
  gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area),
                       GTK_BUTTONBOX_END);

  closebutton = gtk_button_new_from_stock ("gtk-close");
  gtk_dialog_add_action_widget (GTK_DIALOG (spelldlg), closebutton,
                        GTK_RESPONSE_CLOSE);
  GTK_WIDGET_SET_FLAGS (closebutton, GTK_CAN_DEFAULT);

  g_signal_connect (G_OBJECT (closebutton), "clicked",
                G_CALLBACK (spelldlg_closeb_clicked), NULL);
  g_signal_connect (G_OBJECT (spelldlg), "destroy",
                G_CALLBACK (katoob_destroy_spelldlg), NULL);
  g_signal_connect (G_OBJECT (add), "clicked", G_CALLBACK (add_cb), NULL);
  g_signal_connect (G_OBJECT (ignore), "clicked", G_CALLBACK (ignore_cb),
                NULL);
  g_signal_connect (G_OBJECT (change_b), "clicked", G_CALLBACK (change_cb),
                NULL);
  g_signal_connect (G_OBJECT (check), "clicked", G_CALLBACK (check_cb), NULL);
  return spelldlg;
}

void
add_cb (GtkButton * button, gpointer user_data)
{
  GtkWidget *dlg =
    (GtkWidget *) g_object_get_data (G_OBJECT (button), "user_data");
  GtkWidget *entry =
    (GtkWidget *) g_object_get_data (G_OBJECT (button), "entry");
  KatoobDocument *doc =
    (KatoobDocument *) g_object_get_data (G_OBJECT (dlg), "document");

  KATOOB_DEBUG_FUNCTION;
  aspell_speller_add_to_personal (speller,
                          gtk_entry_get_text (GTK_ENTRY (entry)), -1);
  get_next_word (doc, entry);
}

void
ignore_cb (GtkButton * button, gpointer user_data)
{
  GtkWidget *dlg =
    (GtkWidget *) g_object_get_data (G_OBJECT (button), "user_data");
  GtkWidget *entry =
    (GtkWidget *) g_object_get_data (G_OBJECT (button), "entry");
  KatoobDocument *doc =
    (KatoobDocument *) g_object_get_data (G_OBJECT (dlg), "document");

  KATOOB_DEBUG_FUNCTION;
  get_next_word (doc, entry);
}

void
change_cb (GtkButton * button, gpointer user_data)
{
  GtkTextIter start, end;
  gchar *oldword, *newword;
  GtkWidget *dlg =
    (GtkWidget *) g_object_get_data (G_OBJECT (button), "user_data");
  GtkWidget *entry =
    (GtkWidget *) g_object_get_data (G_OBJECT (button), "entry");
  KatoobDocument *doc =
    (KatoobDocument *) g_object_get_data (G_OBJECT (dlg), "document");
  GtkTextBuffer *buffer = katoob_document_get_buffer (doc);

  KATOOB_DEBUG_FUNCTION;

  gtk_text_buffer_get_selection_bounds (buffer, &start, &end);

  newword = (gchar *) gtk_entry_get_text (GTK_ENTRY (entry));
  oldword = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);

  gtk_text_buffer_delete (buffer, &start, &end);
  gtk_text_buffer_insert (buffer, &start, newword, -1);
/*
  aspell_speller_store_replacement (katoob_document_get_speller (doc),
                            oldword, strlen (oldword),
                            newword, strlen (newword));

  g_free (oldword);

  get_next_word (doc, entry);
*/
/* TODO: undo/redo */
}

void
check_cb (GtkButton * button, gpointer user_data)
{
  GtkWidget *dlg =
    (GtkWidget *) g_object_get_data (G_OBJECT (button), "user_data");
  GtkWidget *entry =
    (GtkWidget *) g_object_get_data (G_OBJECT (button), "entry");
  KatoobDocument *doc =
    (KatoobDocument *) g_object_get_data (G_OBJECT (dlg), "document");
  gchar *word = (gchar *) gtk_entry_get_text (GTK_ENTRY (entry));

  if (!word)
    {
      return;
    }

  clear_suggestions ();

  if (!aspell_speller_check (katoob_document_get_speller (doc), word, -1))
    {
      gtk_widget_hide (yes_img);
      gtk_widget_show (no_img);
      build_suggestions (word, entry);
    }
  else
    {
      gtk_widget_hide (no_img);
      gtk_widget_show (yes_img);
    }
  KATOOB_DEBUG_FUNCTION;
}

static void
get_next_word (KatoobDocument * doc, GtkWidget * entry)
{
  gchar *word;
  if (katoob_spelldlg_check_range (doc, katoob_document_get_buffer (doc),
                           &word, TRUE))
    {
      clear_suggestions ();
      gtk_entry_set_text (GTK_ENTRY (entry), word);
      gtk_label_set_text (GTK_LABEL (fubar), word);
      build_suggestions (word, entry);
      g_free (word);
    }
  else
    {
/* Destroy the dialog */
      spelldlg_closeb_clicked ();
      katoob_info (_("No more mispelled word."));
    }
}

static void
spelldlg_closeb_clicked ()
{
  KATOOB_DEBUG_FUNCTION;
  g_signal_emit_by_name (G_OBJECT (spelldialog), "destroy");
}

static void
katoob_destroy_spelldlg ()
{
  KATOOB_DEBUG_FUNCTION;
  gtk_widget_destroyed (spelldialog, &spelldialog);
}

static GtkTreeModel *
create_model ()
{
  GtkListStore *store;
  store = gtk_list_store_new (1, G_TYPE_STRING);
  return GTK_TREE_MODEL (store);
}

static void
add_suggestion (gchar * s)
{
  GtkListStore *store;
  GtkTreeIter iter;

  store = GTK_LIST_STORE (model);
  gtk_list_store_append (store, &iter);
  gtk_list_store_set (store, &iter, 0, s, -1);
}

static void
clear_suggestions ()
{
  GtkListStore *store;
  store = GTK_LIST_STORE (model);
  gtk_list_store_clear (store);
}

static void
tree_selection_changed (GtkTreeSelection * selection, gpointer data)
{
  GtkTreeIter iter;
  GtkWidget *entry = (GtkWidget *) data;
  gchar *word = NULL;
  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
    {
      return;
    }

  gtk_tree_model_get (model, &iter, 0, &word, -1);
  gtk_entry_set_text (GTK_ENTRY (entry), word);

  gtk_widget_hide (no_img);
  gtk_widget_show (yes_img);

  g_free (word);
}

static gboolean
katoob_spelldlg_check_range (KatoobDocument * doc, GtkTextBuffer * buffer,
                       gchar ** word, gboolean mark)
{
  GtkTextIter start, end;
  GtkTextIter wstart, wend;
  gint x, y;
  KATOOB_DEBUG_FUNCTION;

  if (mark)
    {
      katoob_debug ("Iter from insert mark");
      gtk_text_buffer_get_iter_at_mark (buffer, &start,
                              katoob_document_get_mark (doc));
      gtk_text_buffer_get_end_iter (buffer, &end);
    }
  else
    {
      katoob_debug ("iter from beginning");
      gtk_text_buffer_get_bounds (buffer, &start, &end);
    }
  if (gtk_text_iter_is_end (&start))
    {
      return FALSE;
    }
  if (!gtk_text_iter_starts_word (&start))
    {
      if (gtk_text_iter_inside_word (&start)
        || gtk_text_iter_ends_word (&start))
      {
        gtk_text_iter_backward_word_start (&start);
      }
      else
      {
        /* if we're neither at the beginning nor inside a word,
         * me must be in some spaces.   
         * skip forward to the beginning of the next word. */
        if (gtk_text_iter_forward_word_end (&start))
          {
            gtk_text_iter_backward_word_start (&start);
          }
      }
    }

  wstart = start;
  while (gtk_text_iter_compare (&wstart, &end) < 0)
    {
      /* move wend to the end of the current word. */
      wend = wstart;
      gtk_text_iter_forward_word_end (&wend);
      *word = gtk_text_buffer_get_text (buffer, &wstart, &wend, FALSE);
      katoob_debug (*word);
      if (((unsigned char) *word[0] == 0xd8)
        || ((unsigned char) *word[0] == 0xd9))
      {
#warning DUALI SUPPORT.
/* Duali */
        g_free (*word);
      }
      else
      {
        if (!aspell_speller_check
            (katoob_document_get_speller (doc), *word, -1))
          {
            GtkTextIter tmp = wend;

/* Move tmp to the beginning of the next word, */
            gtk_text_iter_forward_word_end (&tmp);
            gtk_text_iter_backward_word_start (&tmp);

/* If we are in the same place, then we have reached the end. */
            x = gtk_text_iter_get_offset (&tmp);
            y = gtk_text_iter_get_offset (&wend);

            if (x != (y + 1))
            {
/* FWD. the mark to the end */
              katoob_debug ("Almost finished!");
              gtk_text_iter_forward_to_end (&tmp);
            }
            katoob_debug ("Found mispelled!");
            gtk_text_buffer_move_mark (buffer,
                               katoob_document_get_mark (doc),
                               &tmp);
/*
gtk_text_buffer_place_cursor (buffer, &wend);
gtk_text_buffer_move_mark_by_name (buffer,
                      "selection_bound", &wstart);
*/
            gtk_text_buffer_move_mark_by_name (buffer, "selection_bound",
                                     &wstart);
            gtk_text_buffer_move_mark_by_name (buffer, "insert", &wend);

            gtk_text_view_scroll_mark_onscreen
            (katoob_document_get_text_view (doc),
             gtk_text_buffer_get_insert (buffer));
            if (spelldialog)
            {
              gtk_widget_hide (yes_img);
              gtk_widget_show (no_img);
            }
            return TRUE;
          }
        else
          {
            g_free (*word);
          }
      }
      /* now move wend to the beginning of the next word, */
      gtk_text_iter_forward_word_end (&wend);
      gtk_text_iter_backward_word_start (&wend);
      /* make sure we've actually advanced
       * (we don't advance in some corner cases), */
      if (gtk_text_iter_equal (&wstart, &wend))
      {
        break;          /* we're done in these cases.. */
      }
      /* and then pick this as the new next word beginning. */
      wstart = wend;
    }

  if (spelldialog)
    {
      gtk_widget_hide (no_img);
      gtk_widget_show (yes_img);
    }

  return FALSE;
}

static void
build_suggestions (gchar * word, GtkWidget * entry)
{
  const AspellWordList *suggestions;
  AspellStringEnumeration *elements;
  gchar *suggestion;

  suggestions = aspell_speller_suggest (speller, word, -1);
  elements = aspell_word_list_elements (suggestions);
  suggestion = (gchar *) aspell_string_enumeration_next (elements);

  if (suggestion)
    {
      gtk_entry_set_text (GTK_ENTRY (entry), suggestion);
      if (spelldialog)
      {
        gtk_widget_show (yes_img);
        gtk_widget_hide (no_img);
      }
      while (suggestion)
      {
        katoob_debug (suggestion);
        add_suggestion (suggestion);
        suggestion = (gchar *) aspell_string_enumeration_next (elements);
      }
    }
  else
    {
      if (spelldialog)
      {
        gtk_widget_show (no_img);
        gtk_widget_hide (yes_img);
      }
    }
  delete_aspell_string_enumeration (elements);
}

#endif /* HAVE_SPELL */

Generated by  Doxygen 1.6.0   Back to index