1 /***************************************************************************
2  *   copyright       : (C) 2007-2017 by Pascal Brachet                     *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  ***************************************************************************/
10 
11 #include "spellerdialog.h"
12 
13 #include <QDebug>
14 #include <QTextCursor>
15 #include <QTextBlock>
16 #include <QMessageBox>
17 #include <QTimer>
18 #include <QCloseEvent>
19 #include <QTextCodec>
20 #include <QTextStream>
21 #include <QTextCharFormat>
22 #include <QFileInfo>
23 #include <QApplication>
24 #include "blockdata.h"
25 
SpellerDialog(QWidget * parent,LatexEditor * ed,QString ignoredWords)26 SpellerDialog::SpellerDialog(QWidget *parent,LatexEditor *ed,QString ignoredWords)
27     :QDialog( parent)
28 {
29 editor=ed;
30 
31 ui.setupUi(this);
32 setModal(true);
33 
34 pChecker = editor->pChecker;
35 if (pChecker) spell_encoding=QString(pChecker->get_dic_encoding());
36 
37 connect(ui.pushButtonIgnore, SIGNAL(clicked()), this, SLOT(slotIgnore()));
38 connect(ui.pushButtonAlwaysIgnore, SIGNAL(clicked()), this, SLOT(slotAlwaysIgnore()));
39 connect(ui.pushButtonReplace, SIGNAL(clicked()), this, SLOT(slotReplace()));
40 connect(ui.listWidget, SIGNAL(itemSelectionChanged()),this, SLOT(updateItem()));
41 
42 if (!ignoredWords.isEmpty()) alwaysignoredwordList=ignoredWords.split(",");
43 else alwaysignoredwordList.clear();
44 ignoredwordList=alwaysignoredwordList;
45 QFile wordsfile(":/spell/spellignore.txt");
46 QString line;
47 if (wordsfile.open(QFile::ReadOnly))
48     {
49     while (!wordsfile.atEnd())
50 	    {
51 	    line = wordsfile.readLine();
52 	    if (!line.isEmpty()) hardignoredwordList.append(line.trimmed());
53 	    }
54     }
55 ui.listWidget->setEnabled(false);
56 ui.lineEditNew->setEnabled(false);
57 ui.pushButtonIgnore->setEnabled(false);
58 ui.pushButtonAlwaysIgnore->setEnabled(false);
59 ui.pushButtonReplace->setEnabled(false);
60 ui.lineEditOriginal->setEnabled(false);
61 ui.lineEditOriginal->clear();
62 ui.listWidget->clear();
63 ui.lineEditNew->clear();
64 show();
65 c = editor->textCursor();
66 spellingInit();
67 //QFileInfo fi(SpellDic);
68 //if (fi.exists() && fi.isReadable()) spellingInit();
69 //else ui.labelMessage->setText("<b>"+tr("Error : Can't open the dictionary")+"</b>");
70 }
71 
~SpellerDialog()72 SpellerDialog::~SpellerDialog(){
73 //delete pChecker;
74 }
75 
closeEvent(QCloseEvent * ce)76 void SpellerDialog::closeEvent( QCloseEvent* ce )
77 {
78 QTextCursor cursor=editor->textCursor();
79 cursor.setPosition(startpos,QTextCursor::MoveAnchor);
80 editor->setTextCursor(cursor);
81 ce->accept();
82 }
83 
accept()84 void SpellerDialog::accept()
85 {
86 QTextCursor cursor=editor->textCursor();
87 cursor.setPosition(startpos,QTextCursor::MoveAnchor);
88 editor->setTextCursor(cursor);
89 QDialog::accept();
90 }
91 
updateItem()92 void SpellerDialog::updateItem()
93 {
94 int current=-1;
95 QList<QListWidgetItem *> items;
96 items = ui.listWidget->selectedItems();
97 if (items.count() > 0)
98 	{
99 	ui.listWidget->setCurrentItem(items[0]);
100 	current=ui.listWidget->row(items[0]);
101 	}
102 if (current>=0)
103 	{
104 	ui.lineEditNew->setText(ui.listWidget->currentItem()->text());
105 	}
106 }
107 
108 
spellingInit()109 void SpellerDialog::spellingInit()
110 {
111 deltacol=0;
112 go=true;
113 if (c.hasSelection())
114 	{
115 	ui.labelMessage->setText(tr("Check spelling selection..."));
116 	startpos=c.selectionStart();
117 	endpos=c.selectionEnd();
118 	c.setPosition(endpos,QTextCursor::MoveAnchor);
119 	c.setPosition(startpos,QTextCursor::MoveAnchor);
120 	SpellingNextWord();
121 	}
122 else
123 	{
124 //	c.movePosition(QTextCursor::Start,QTextCursor::MoveAnchor);
125 	ui.labelMessage->setText(tr("Check spelling from cursor..."));
126 	startpos=c.position();
127 	c.movePosition(QTextCursor::End,QTextCursor::MoveAnchor);
128 	endpos=c.position();
129 	c.setPosition(startpos,QTextCursor::MoveAnchor);
130 	SpellingNextWord();
131 	}
132 }
133 
slotIgnore()134 void SpellerDialog::slotIgnore()
135 {
136 ignoredwordList.append(ui.lineEditOriginal->text());
137 ui.listWidget->setEnabled(false);
138 ui.lineEditNew->setEnabled(false);
139 ui.pushButtonIgnore->setEnabled(false);
140 ui.pushButtonAlwaysIgnore->setEnabled(false);
141 ui.pushButtonReplace->setEnabled(false);
142 ui.lineEditOriginal->setEnabled(false);
143 ui.lineEditOriginal->clear();
144 ui.listWidget->clear();
145 ui.lineEditNew->clear();
146 ui.labelMessage->setText("<b>"+tr("No more misspelled words")+"</b>");
147 SpellingNextWord();
148 }
149 
slotAlwaysIgnore()150 void SpellerDialog::slotAlwaysIgnore()
151 {
152 alwaysignoredwordList.append(ui.lineEditOriginal->text());
153 ignoredwordList.append(ui.lineEditOriginal->text());
154 ui.listWidget->setEnabled(false);
155 ui.lineEditNew->setEnabled(false);
156 ui.pushButtonIgnore->setEnabled(false);
157 ui.pushButtonAlwaysIgnore->setEnabled(false);
158 ui.pushButtonReplace->setEnabled(false);
159 ui.lineEditOriginal->setEnabled(false);
160 ui.lineEditOriginal->clear();
161 ui.listWidget->clear();
162 ui.lineEditNew->clear();
163 ui.labelMessage->setText("<b>"+tr("No more misspelled words")+"</b>");
164 SpellingNextWord();
165 }
166 
slotReplace()167 void SpellerDialog::slotReplace()
168 {
169 QString selectedword="";
170 QTextCursor cursor=editor->textCursor();
171 if (cursor.hasSelection()) selectedword=cursor.selectedText();
172 QString newword=ui.lineEditNew->text();
173 if (!newword.isEmpty())
174 	{
175 	deltacol=deltacol+newword.length()-selectedword.length();
176 	editor->replace(newword,false,"");
177 	}
178 ui.listWidget->setEnabled(false);
179 ui.lineEditNew->setEnabled(false);
180 ui.pushButtonIgnore->setEnabled(false);
181 ui.pushButtonAlwaysIgnore->setEnabled(false);
182 ui.pushButtonReplace->setEnabled(false);
183 ui.lineEditOriginal->setEnabled(false);
184 ui.lineEditOriginal->clear();
185 ui.listWidget->clear();
186 ui.lineEditNew->clear();
187 ui.labelMessage->setText("<b>"+tr("No more misspelled words")+"</b>");
188 SpellingNextWord();
189 }
190 
SpellingNextWord()191 void SpellerDialog::SpellingNextWord()
192 {
193 /*QApplication::setOverrideCursor(Qt::WaitCursor);
194 BlockData* data;
195 QTextCodec *codec = QTextCodec::codecForName(spell_encoding.toLatin1());
196 QByteArray encodedString;
197 QTextBlock block;
198 QString text,word;
199 bool gonext=true;
200 QByteArray t;
201 int li,cols,cole,colstart,colend,check,ns;
202 char ** wlst;
203 QStringList suggWords;
204 while(gonext && c.position() < endpos+deltacol && go)
205 	{
206 	ui.listWidget->setEnabled(false);
207 	ui.lineEditNew->setEnabled(false);
208 	ui.pushButtonIgnore->setEnabled(false);
209 	ui.pushButtonAlwaysIgnore->setEnabled(false);
210 	ui.pushButtonReplace->setEnabled(false);
211 	ui.lineEditOriginal->setEnabled(false);
212 	ui.lineEditOriginal->clear();
213 	ui.listWidget->clear();
214 	ui.lineEditNew->clear();
215 	ui.labelMessage->setText("<b>"+tr("No more misspelled words")+"</b>");
216 
217 //	c.movePosition(QTextCursor::NextCharacter,QTextCursor::MoveAnchor);
218 	c.movePosition(QTextCursor::StartOfWord,QTextCursor::MoveAnchor);
219 	data = (BlockData*)c.block().userData();
220 	li=c.blockNumber();
221 	block=c.block();
222 	colstart=c.position()-block.position();
223 	c.movePosition(QTextCursor::EndOfWord,QTextCursor::KeepAnchor);
224 	block=c.block();
225 	colend=c.position()-block.position()-1;
226 	cols=colstart;
227 	text=c.selectedText();
228 	while ((cols<colend && cols<data->code.count() && data->code[cols]==1) || text.mid(cols-colstart,1)==" " || text.mid(cols-colstart,1)=="\t" )
229 		{
230 		cols++;
231 		}
232 	cole=colend;
233 	while (cole>colstart && cole<data->code.count() && data->code[cole]==1)
234 		{
235 		cole--;
236 		}
237 	if (text.length()>1 && cole>cols)
238 		{
239 		word=text.mid(cols-colstart,cole-cols+1);
240 		if (!ignoredwordList.contains(word) && !hardignoredwordList.contains(word))
241 			{
242 			encodedString = codec->fromUnicode(word);
243 			if (pChecker) check = pChecker->spell(encodedString.data());
244 			else check=true;
245 			if (!check)
246 				{
247 				editor->selectword(li,cols,word);
248 				ui.listWidget->setEnabled(true);
249 				ui.lineEditNew->setEnabled(true);
250 				ui.pushButtonIgnore->setEnabled(true);
251 				ui.pushButtonAlwaysIgnore->setEnabled(true);
252 				ui.pushButtonReplace->setEnabled(true);
253 				ui.lineEditOriginal->setEnabled(true);
254 				ui.lineEditOriginal->setText(word);
255 				ui.listWidget->clear();
256 				ui.lineEditNew->clear();
257 				ui.labelMessage->setText("");
258 				gonext=false;
259 				ns = pChecker->suggest(&wlst,encodedString.data());
260 				if (ns > 0)
261 					{
262 					suggWords.clear();
263 					for (int i=0; i < ns; i++)
264 						{
265 						suggWords.append(codec->toUnicode(wlst[i]));
266 					//free(wlst[i]);
267 						}
268 				//free(wlst);
269 					pChecker->free_list(&wlst, ns);
270 					if (!suggWords.isEmpty())
271 						{
272 						if (suggWords.contains(word)) gonext=true;
273 						else
274 							{
275 							ui.listWidget->addItems(suggWords);
276 							ui.lineEditNew->setText(suggWords.at(0));
277 							}
278 						}
279 					}
280 				}
281 			}
282 		}
283 	go=c.movePosition(QTextCursor::NextWord,QTextCursor::MoveAnchor);
284 	}
285 QApplication::restoreOverrideCursor();*/
286 QApplication::setOverrideCursor(Qt::WaitCursor);
287 QTextCodec *codec = QTextCodec::codecForName(spell_encoding.toLatin1());
288 QTextBlock block;
289 QString text;
290 int i;
291 int check;
292 int offset ;
293 int ns;
294 char ** wlst;
295 QChar ch;
296 QString buffer;
297 QByteArray encodedString;
298 QStringList suggWords;
299 BlockData* blockData;
300 block=c.block();
301 bool gonext=true;
302 while (gonext && c.position() < endpos+deltacol && block.isValid() )
303 {
304 ui.listWidget->setEnabled(false);
305 ui.lineEditNew->setEnabled(false);
306 ui.pushButtonIgnore->setEnabled(false);
307 ui.pushButtonAlwaysIgnore->setEnabled(false);
308 ui.pushButtonReplace->setEnabled(false);
309 ui.lineEditOriginal->setEnabled(false);
310 ui.lineEditOriginal->clear();
311 ui.listWidget->clear();
312 ui.lineEditNew->clear();
313 ui.labelMessage->setText("<b>"+tr("No more misspelled words")+"</b>");
314 i=0;
315 text=block.text();
316 blockData= (BlockData*)block.userData();
317 while (gonext && i < text.length())
318 	{
319 	buffer = QString::null;
320 	ch = text.at( i );
321 	offset=0;
322 	while ((blockData->code[i]!=1) && (!isSpace(ch)))
323 	      {
324 	      buffer += ch;
325 	      i++;
326 	      if (i < text.length()) ch = text.at( i );
327 	      else break;
328 	      }
329 	while (buffer.startsWith('\''))
330 	  {
331 	  buffer=buffer.right(buffer.size()-1);
332 	  }
333 	while (buffer.endsWith('\''))
334 	  {
335 	  buffer.chop(1);
336 	  offset++;
337 	  }
338 	if ( (i - buffer.length()-offset+block.position() <= endpos+deltacol) && (i-offset+block.position()>=c.position()) && (buffer.length() > 1) && (!ignoredwordList.contains(buffer)) && (!hardignoredwordList.contains(buffer)))
339 	  {
340 	  encodedString = codec->fromUnicode(buffer);
341 	  if (pChecker) check = pChecker->spell(encodedString.data());
342 	  else check=true;
343 	  if (!check)
344 		  {
345 		  editor->selectword(block.blockNumber(),i - buffer.length()-offset,buffer);
346 		  ui.listWidget->setEnabled(true);
347 		  ui.lineEditNew->setEnabled(true);
348 		  ui.pushButtonIgnore->setEnabled(true);
349 		  ui.pushButtonAlwaysIgnore->setEnabled(true);
350 		  ui.pushButtonReplace->setEnabled(true);
351 		  ui.lineEditOriginal->setEnabled(true);
352 		  ui.lineEditOriginal->setText(buffer);
353 		  ui.listWidget->clear();
354 		  ui.lineEditNew->clear();
355 		  ui.labelMessage->setText("");
356 		  gonext=false;
357 		  ns = pChecker->suggest(&wlst,encodedString.data());
358 		  if (ns > 0)
359 			  {
360 			  suggWords.clear();
361 			  for (int i=0; i < ns; i++)
362 				  {
363 				  suggWords.append(codec->toUnicode(wlst[i]));
364 			  //free(wlst[i]);
365 				  }
366 		  //free(wlst);
367 			  pChecker->free_list(&wlst, ns);
368 			  if (!suggWords.isEmpty())
369 				  {
370 				  if (suggWords.contains(buffer)) gonext=true;
371 				  else
372 					  {
373 					  ui.listWidget->addItems(suggWords);
374 					  ui.lineEditNew->setText(suggWords.at(0));
375 					  }
376 				  }
377 			  }
378 		  }
379 	  }
380 	i++;
381 	}
382 block = block.next();
383 }
384 QApplication::restoreOverrideCursor();
385 
386 }
387 
isSpace(QChar c) const388 bool SpellerDialog::isSpace(QChar c) const
389 {
390     return c == QLatin1Char(' ')
391         || c == QChar::Nbsp
392         || c == QChar::LineSeparator
393         || c == QLatin1Char('\t')
394         ;
395 }
396