2
Copyright (c) 2012 Montel Laurent <montel@kde.org>
3
code based on calligra autocorrection.
5
This program is free software; you can redistribute it and/or modify it
6
under the terms of the GNU General Public License, version 2, as
7
published by the Free Software Foundation.
9
This program is distributed in the hope that it will be useful, but
10
WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
General Public License for more details.
14
You should have received a copy of the GNU General Public License along
15
with this program; if not, write to the Free Software Foundation, Inc.,
16
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
#include "composerautocorrection.h"
20
#include "messagecomposersettings.h"
21
#include "import/importkmailautocorrection.h"
24
#include <KColorScheme>
25
#include <KCalendarSystem>
26
#include <KStandardDirs>
28
#include <QDomDocument>
31
using namespace MessageComposer;
33
ComposerAutoCorrection::ComposerAutoCorrection()
34
: mSingleSpaces(true),
35
mUppercaseFirstCharOfSentence(false),
36
mFixTwoUppercaseChars(false),
38
mCapitalizeWeekDays(false),
39
mReplaceDoubleQuotes(false),
40
mReplaceSingleQuotes(false),
42
mSuperScriptAppendix(false)
44
// default double quote open 0x201c
45
// default double quote close 0x201d
46
// default single quote open 0x2018
47
// default single quote close 0x2019
48
mTypographicSingleQuotes.begin = QChar(0x2018);
49
mTypographicSingleQuotes.end = QChar(0x2019);
50
mTypographicDoubleQuotes.begin = QChar(0x201c);
51
mTypographicDoubleQuotes.end = QChar(0x201d);
55
KLocale *locale = KGlobal::locale();
56
for (int i = 1; i <=7; i++)
57
mCacheNameOfDays.append(locale->calendar()->weekDayName(i).toLower());
61
ComposerAutoCorrection::~ComposerAutoCorrection()
66
void ComposerAutoCorrection::selectWord(QTextCursor &cursor, int cursorPosition)
68
cursor.setPosition(cursorPosition);
69
QTextBlock block = cursor.block();
70
cursor.setPosition(block.position());
71
cursorPosition -= block.position();
72
QString string = block.text();
75
QString::Iterator iter = string.begin();
76
while (iter != string.end()) {
77
if (iter->isSpace()) {
79
;// double spaces belong to the previous word
80
else if (pos < cursorPosition)
81
cursor.setPosition(pos + block.position() + 1); // +1 because we don't want to set it on the space itself
90
cursor.setPosition(pos + block.position(), QTextCursor::KeepAnchor);
94
void ComposerAutoCorrection::autocorrect(bool htmlMode, QTextDocument& document, int position)
98
mCursor = QTextCursor(&document);
99
selectWord(mCursor,position);
100
mWord = mCursor.selectedText();
106
done = autoFormatURLs();
108
done = autoBoldUnderline();
111
superscriptAppendix();
115
done = singleSpaces();
117
done = autoFractions();
119
advancedAutocorrect();
121
uppercaseFirstCharOfSentence();
123
fixTwoUppercaseChars();
125
capitalizeWeekDays();
127
replaceTypographicQuotes();
129
if (mCursor.selectedText() != mWord)
130
mCursor.insertText(mWord);
133
void ComposerAutoCorrection::readConfig()
135
mAutoBoldUnderline = MessageComposer::MessageComposerSettings::self()->autoBoldUnderline();
136
mAutoFormatUrl = MessageComposer::MessageComposerSettings::self()->autoFormatUrl();
137
mUppercaseFirstCharOfSentence = MessageComposer::MessageComposerSettings::self()->uppercaseFirstCharOfSentence();
138
mFixTwoUppercaseChars = MessageComposer::MessageComposerSettings::self()->fixTwoUppercaseChars();
139
mSingleSpaces = MessageComposer::MessageComposerSettings::self()->singleSpaces();
140
mAutoFractions = MessageComposer::MessageComposerSettings::self()->autoFractions();
141
mCapitalizeWeekDays = MessageComposer::MessageComposerSettings::self()->capitalizeWeekDays();
142
mAdvancedAutocorrect = MessageComposer::MessageComposerSettings::self()->advancedAutocorrect();
143
mReplaceDoubleQuotes = MessageComposer::MessageComposerSettings::self()->replaceDoubleQuotes();
144
mReplaceSingleQuotes = MessageComposer::MessageComposerSettings::self()->replaceSingleQuotes();
145
mEnabled = MessageComposer::MessageComposerSettings::self()->enabled();
146
mSuperScriptAppendix = MessageComposer::MessageComposerSettings::self()->superScript();
147
readAutoCorrectionXmlFile();
150
void ComposerAutoCorrection::writeConfig()
152
MessageComposer::MessageComposerSettings::self()->setAutoBoldUnderline(mAutoBoldUnderline);
153
MessageComposer::MessageComposerSettings::self()->setAutoFormatUrl(mAutoFormatUrl);
154
MessageComposer::MessageComposerSettings::self()->setUppercaseFirstCharOfSentence(mUppercaseFirstCharOfSentence);
155
MessageComposer::MessageComposerSettings::self()->setFixTwoUppercaseChars(mFixTwoUppercaseChars);
156
MessageComposer::MessageComposerSettings::self()->setSingleSpaces(mSingleSpaces);
157
MessageComposer::MessageComposerSettings::self()->setAutoFractions(mAutoFractions);
158
MessageComposer::MessageComposerSettings::self()->setCapitalizeWeekDays(mCapitalizeWeekDays);
159
MessageComposer::MessageComposerSettings::self()->setAdvancedAutocorrect(mAdvancedAutocorrect);
160
MessageComposer::MessageComposerSettings::self()->setReplaceDoubleQuotes(mReplaceDoubleQuotes);
161
MessageComposer::MessageComposerSettings::self()->setReplaceSingleQuotes(mReplaceSingleQuotes);
162
MessageComposer::MessageComposerSettings::self()->setEnabled(mEnabled);
163
MessageComposer::MessageComposerSettings::self()->setSuperScript(mSuperScriptAppendix);
164
MessageComposer::MessageComposerSettings::self()->requestSync();
165
writeAutoCorrectionXmlFile();
168
void ComposerAutoCorrection::addAutoCorrect(const QString ¤tWord, const QString &replaceWord)
170
mAutocorrectEntries.insert(currentWord, replaceWord);
171
writeAutoCorrectionXmlFile();
175
void ComposerAutoCorrection::setUpperCaseExceptions(const QSet<QString>& exceptions)
177
mUpperCaseExceptions = exceptions;
180
void ComposerAutoCorrection::setTwoUpperLetterExceptions(const QSet<QString>& exceptions)
182
mTwoUpperLetterExceptions = exceptions;
185
void ComposerAutoCorrection::setAutocorrectEntries(const QHash<QString, QString>& entries)
187
mAutocorrectEntries = entries;
191
ComposerAutoCorrection::TypographicQuotes ComposerAutoCorrection::typographicDefaultSingleQuotes()
193
ComposerAutoCorrection::TypographicQuotes quote;
194
quote.begin = QChar(0x2018);
195
quote.end = QChar(0x2019);
199
ComposerAutoCorrection::TypographicQuotes ComposerAutoCorrection::typographicDefaultDoubleQuotes()
201
ComposerAutoCorrection::TypographicQuotes quote;
202
quote.begin = QChar(0x201c);
203
quote.end = QChar(0x201d);
207
QSet<QString> ComposerAutoCorrection::upperCaseExceptions() const
209
return mUpperCaseExceptions;
212
QSet<QString> ComposerAutoCorrection::twoUpperLetterExceptions() const
214
return mTwoUpperLetterExceptions;
217
QHash<QString, QString> ComposerAutoCorrection::autocorrectEntries() const
219
return mAutocorrectEntries;
222
void ComposerAutoCorrection::superscriptAppendix()
224
if (!mSuperScriptAppendix) return;
226
QString trimmed = mWord.trimmed();
230
QHash<QString, QString>::const_iterator i = mSuperScriptEntries.constBegin();
231
while (i != mSuperScriptEntries.constEnd()) {
232
if (i.key() == trimmed) {
233
startPos = mCursor.selectionStart() + 1;
234
endPos = startPos - 1 + trimmed.length();
237
else if (i.key() == QLatin1String("othernb")) {
238
int pos = trimmed.indexOf(i.value());
240
QString number = trimmed.left(pos);
241
QString::ConstIterator constIter = number.constBegin();
243
// don't apply superscript to 1th, 2th and 3th
244
if (number.length() == 1 &&
245
(*constIter == QLatin1Char('1') || *constIter == QLatin1Char('2') || *constIter == QLatin1Char('3')))
248
while (constIter != number.constEnd()) {
249
if (!constIter->isNumber()) {
256
if (found && number.length() + i.value().length() == trimmed.length()) {
257
startPos = mCursor.selectionStart() + pos;
258
endPos = startPos - pos + trimmed.length();
266
if (startPos != -1 && endPos != -1) {
267
QTextCursor cursor(mCursor);
268
cursor.setPosition(startPos);
269
cursor.setPosition(endPos, QTextCursor::KeepAnchor);
271
QTextCharFormat format;
272
format.setVerticalAlignment(QTextCharFormat::AlignSuperScript);
273
cursor.mergeCharFormat(format);
277
bool ComposerAutoCorrection::autoBoldUnderline()
279
if (!mAutoBoldUnderline)
282
QString trimmed = mWord.trimmed();
284
if (trimmed.length() < 3)
287
bool underline = (trimmed.at(0) == QLatin1Char('_') && trimmed.at(trimmed.length() - 1) == QLatin1Char('_'));
288
bool bold = (trimmed.at(0) == QLatin1Char('*') && trimmed.at(trimmed.length() - 1) == QLatin1Char('*'));
290
if (underline || bold) {
291
int startPos = mCursor.selectionStart();
292
QString replacement = trimmed.mid(1, trimmed.length() - 2);
293
bool foundLetterNumber = false;
295
QString::ConstIterator constIter = replacement.constBegin();
296
while (constIter != replacement.constEnd()) {
297
if (constIter->isLetterOrNumber()) {
298
foundLetterNumber = true;
304
// if no letter/number found, don't apply autocorrection like in OOo 2.x
305
if (!foundLetterNumber)
308
mCursor.setPosition(startPos);
309
mCursor.setPosition(startPos + trimmed.length(), QTextCursor::KeepAnchor);
310
mCursor.insertText(replacement);
311
mCursor.setPosition(startPos);
312
mCursor.setPosition(startPos + replacement.length(), QTextCursor::KeepAnchor);
314
QTextCharFormat format;
315
format.setFontUnderline(underline ? true : mCursor.charFormat().fontUnderline());
316
format.setFontWeight(bold ? QFont::Bold : mCursor.charFormat().fontWeight());
317
mCursor.mergeCharFormat(format);
319
// to avoid the selection being replaced by mWord
320
mWord = mCursor.selectedText();
322
// don't do this again if the text is already underlined and bold
323
if(mCursor.charFormat().fontUnderline()
324
&& mCursor.charFormat().fontWeight() == QFont::Bold) {
327
return autoBoldUnderline();
336
bool ComposerAutoCorrection::autoFormatURLs()
341
QString link = autoDetectURL(mWord);
345
QString trimmed = mWord.trimmed();
346
int startPos = mCursor.selectionStart();
347
mCursor.setPosition(startPos);
348
mCursor.setPosition(startPos + trimmed.length(), QTextCursor::KeepAnchor);
350
QTextCharFormat format;
351
format.setAnchorHref(link);
352
format.setFontItalic(true);
353
format.setAnchor(true);
354
format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
355
format.setUnderlineColor(KColorScheme(QPalette::Active, KColorScheme::View).foreground(KColorScheme::LinkText).color());
356
format.setForeground(KColorScheme(QPalette::Active, KColorScheme::View).foreground(KColorScheme::LinkText).color());
357
mCursor.mergeCharFormat(format);
359
mWord = mCursor.selectedText();
363
QString ComposerAutoCorrection::autoDetectURL(const QString &_word) const
365
QString word = _word;
367
/* this method is ported from lib/kotext/KoAutoFormat.cpp KoAutoFormat::doAutoDetectUrl
368
* from Calligra 1.x branch */
369
// kDebug() <<"link:" << word;
372
int pos = word.indexOf(QLatin1String("http://"));
373
int tmp_pos = word.indexOf(QLatin1String("https://"));
375
if (tmp_pos < pos && tmp_pos != -1)
377
tmp_pos = word.indexOf(QLatin1String("mailto:/"));
378
if ((tmp_pos < pos || pos == -1) && tmp_pos != -1)
380
tmp_pos = word.indexOf(QLatin1String("ftp://"));
381
if ((tmp_pos < pos || pos == -1) && tmp_pos != -1)
383
tmp_pos = word.indexOf(QLatin1String("ftp."));
384
if ((tmp_pos < pos || pos == -1) && tmp_pos != -1) {
388
tmp_pos = word.indexOf(QLatin1String("file:/"));
389
if ((tmp_pos < pos || pos == -1) && tmp_pos != -1)
391
tmp_pos = word.indexOf(QLatin1String("news:"));
392
if ((tmp_pos < pos || pos == -1) && tmp_pos != -1)
394
tmp_pos = word.indexOf(QLatin1String("www."));
395
if ((tmp_pos < pos || pos == -1) && tmp_pos != -1 && word.indexOf(QLatin1Char('.'), tmp_pos+4) != -1 ) {
399
tmp_pos = word.indexOf(QLatin1Char('@'));
400
if (pos == -1 && tmp_pos != -1) {
406
if (c.isPunct() && c != QLatin1Char('.') && c != QLatin1Char('_')) break;
409
if (pos == tmp_pos - 1) // not a valid address
417
// A URL inside e.g. quotes (like "http://www.calligra.org" with the quotes) shouldn't include the quote in the URL.
418
while (!word.at(word.length()-1).isLetter() && !word.at(word.length()-1).isDigit() && word.at(word.length()-1) != QLatin1Char('/'))
419
word.truncate(word.length() - 1);
421
QString newWord = word;
424
newWord = QLatin1String("mailto:") + word;
425
else if (link_type == 2)
426
newWord = QLatin1String("http://") + word;
427
else if (link_type == 3)
428
newWord = QLatin1String("ftp://") + word;
430
kDebug() <<"newWord:" << newWord;
437
void ComposerAutoCorrection::fixTwoUppercaseChars()
439
if (!mFixTwoUppercaseChars)
441
if (mWord.length() <= 2)
444
if (mTwoUpperLetterExceptions.contains(mWord.trimmed()))
447
QChar firstChar = mWord.at(0);
448
QChar secondChar = mWord.at(1);
450
if (secondChar.isUpper()) {
451
QChar thirdChar = mWord.at(2);
453
if (firstChar.isUpper() && thirdChar.isLower())
454
mWord.replace(1, 1, secondChar.toLower());
459
bool ComposerAutoCorrection::singleSpaces()
463
if (!mCursor.atBlockStart() && mWord.length() == 1 && mWord.at(0) == QLatin1Char(' ')) {
464
// then when the prev char is also a space, don't insert one.
465
QTextBlock block = mCursor.block();
466
QString text = block.text();
467
if (text.at(mCursor.position() -1 - block.position()) == QLatin1Char(' ')) {
475
void ComposerAutoCorrection::capitalizeWeekDays()
477
if (!mCapitalizeWeekDays)
480
const QString trimmed = mWord.trimmed();
481
Q_FOREACH (const QString & name, mCacheNameOfDays) {
482
if (trimmed == name) {
483
int pos = mWord.indexOf(name);
484
mWord.replace(pos, 1, name.at(0).toUpper());
490
void ComposerAutoCorrection::uppercaseFirstCharOfSentence()
492
if (!mUppercaseFirstCharOfSentence)
495
int startPos = mCursor.selectionStart();
496
QTextBlock block = mCursor.block();
498
mCursor.setPosition(block.position());
499
mCursor.setPosition(startPos, QTextCursor::KeepAnchor);
501
int position = mCursor.selectionEnd();
503
QString text = mCursor.selectedText();
505
if (text.isEmpty()) // start of a paragraph
506
mWord.replace(0, 1, mWord.at(0).toUpper());
508
QString::ConstIterator constIter = text.constEnd();
511
while (constIter != text.constBegin()) {
512
while (constIter != text.begin() && constIter->isSpace()) {
517
if (constIter != text.constBegin() && (*constIter == QLatin1Char('.') || *constIter == QLatin1Char('!') || *constIter == QLatin1Char('?'))) {
519
while (constIter != text.constBegin() && !(constIter->isLetter())) {
524
selectWord(mCursor, --position);
525
QString prevWord = mCursor.selectedText();
527
// search for exception
528
if (mUpperCaseExceptions.contains(prevWord.trimmed()))
532
mWord.replace(0, 1, mWord.at(0).toUpper());
540
mCursor.setPosition(startPos);
541
mCursor.setPosition(startPos + mWord.length(), QTextCursor::KeepAnchor);
544
bool ComposerAutoCorrection::autoFractions()
549
QString trimmed = mWord.trimmed();
550
if (trimmed.length() > 3) {
551
QChar x = trimmed.at(3);
552
if (!(x.unicode() == '.' || x.unicode() == ',' || x.unicode() == '?' || x.unicode() == '!'
553
|| x.unicode() == ':' || x.unicode() == ';'))
555
} else if (trimmed.length() < 3) {
559
if (trimmed.startsWith(QLatin1String("1/2")))
560
mWord.replace(0, 3, QString::fromUtf8("½"));
561
else if (trimmed.startsWith(QLatin1String("1/4")))
562
mWord.replace(0, 3, QString::fromUtf8("¼"));
563
else if (trimmed.startsWith(QLatin1String("3/4")))
564
mWord.replace(0, 3, QString::fromUtf8("¾"));
571
void ComposerAutoCorrection::advancedAutocorrect()
573
if (!mAdvancedAutocorrect)
576
int startPos = mCursor.selectionStart();
577
int length = mWord.length();
579
QString trimmedWord = mWord.toLower().trimmed();
580
QString actualWord = trimmedWord;
582
if (actualWord.isEmpty())
585
// If the last char is punctuation, drop it for now
586
bool hasPunctuation = false;
587
QChar lastChar = actualWord.at(actualWord.length() - 1);
588
if (lastChar.unicode() == '.' || lastChar.unicode() == ',' || lastChar.unicode() == '?' ||
589
lastChar.unicode() == '!' || lastChar.unicode() == ':' || lastChar.unicode() == ';') {
590
hasPunctuation = true;
594
if (mAutocorrectEntries.contains(actualWord)) {
595
int pos = mWord.toLower().indexOf(trimmedWord);
596
QString replacement = mAutocorrectEntries.value(actualWord);
597
// Keep capitalized words capitalized.
598
// (Necessary to make sure the first letters match???)
599
if (actualWord.at(0) == replacement.at(0).toLower()) {
600
if (mWord.at(0).isUpper()) {
601
replacement[0] = replacement[0].toUpper();
605
// If a punctuation mark was on the end originally, add it back on
606
if (hasPunctuation) {
607
replacement.append(lastChar);
610
mWord.replace(pos, pos + trimmedWord.length(), replacement);
612
// We do replacement here, since the length of new word might be different from length of
613
// the old world. Length difference might affect other type of autocorrection
614
mCursor.setPosition(startPos);
615
mCursor.setPosition(startPos + length, QTextCursor::KeepAnchor);
616
mCursor.insertText(mWord);
617
mCursor.setPosition(startPos); // also restore the selection
618
mCursor.setPosition(startPos + mWord.length(), QTextCursor::KeepAnchor);
622
void ComposerAutoCorrection::replaceTypographicQuotes()
624
/* this method is ported from lib/kotext/KoAutoFormat.cpp KoAutoFormat::doTypographicQuotes
625
* from Calligra 1.x branch */
627
if (!(mReplaceDoubleQuotes && mWord.contains(QLatin1Char('"'))) &&
628
!(mReplaceSingleQuotes && mWord.contains(QLatin1Char('\'')))) return;
630
// Need to determine if we want a starting or ending quote.
631
// we use a starting quote in three cases:
632
// 1. if the previous character is a space
633
// 2. if the previous character is some kind of opening punctuation (e.g., "(", "[", or "{")
634
// a. and the character before that is not an opening quote (so that we get quotations of single characters
636
// 3. if the previous character is an opening quote (so that we get nested quotations right)
637
// a. and the character before that is not an opening quote (so that we get quotations of single characters
639
// b. and the previous quote of a different kind (so that we get empty quotations right)
642
QString::Iterator iter = mWord.end();
645
while (iter != mWord.begin()) {
646
if (*iter == QLatin1Char('"') || *iter == QLatin1Char('\'')) {
647
bool doubleQuotes = *iter == QLatin1Char('"');
649
if ((iter - 1) != mWord.begin()) {
650
QChar::Category c1 = (*(iter - 1)).category();
653
if (c1 == QChar::Separator_Space || c1 == QChar::Separator_Line || c1 == QChar::Separator_Paragraph ||
654
c1 == QChar::Punctuation_Open || c1 == QChar::Other_Control)
658
if (c1 == QChar::Punctuation_InitialQuote) {
662
openingQuote = mTypographicDoubleQuotes.begin;
664
openingQuote = mTypographicSingleQuotes.begin;
667
if (*(iter - 1) != openingQuote)
673
if ((iter - 2) != mWord.constBegin() && !ending)
675
QChar::Category c2 = (*(iter - 2)).category();
676
ending = (c2 == QChar::Punctuation_InitialQuote);
679
if (doubleQuotes && mReplaceDoubleQuotes) {
681
*iter = mTypographicDoubleQuotes.begin;
683
*iter = mTypographicDoubleQuotes.end;
685
else if (mReplaceSingleQuotes) {
687
*iter = mTypographicSingleQuotes.begin;
689
*iter = mTypographicSingleQuotes.end;
696
if (*iter == QLatin1Char('"') && mReplaceDoubleQuotes)
697
*iter = mTypographicDoubleQuotes.begin;
698
else if (*iter == QLatin1Char('\'') && mReplaceSingleQuotes)
699
*iter = mTypographicSingleQuotes.begin;
703
void ComposerAutoCorrection::readAutoCorrectionXmlFile( bool forceGlobal )
705
KLocale *locale = KGlobal::locale();
706
QString kdelang = locale->languageList().first();
707
kdelang.remove(QRegExp(QLatin1String("@.*")));
709
//qDebug()<<"void ComposerAutoCorrection::readAutoCorrectionXmlFile() "<<mAutoCorrectLang;
711
mUpperCaseExceptions.clear();
712
mAutocorrectEntries.clear();
713
mTwoUpperLetterExceptions.clear();
714
mSuperScriptEntries.clear();
718
//Look at local file:
720
if (!mAutoCorrectLang.isEmpty()) {
721
LocalFile = KGlobal::dirs()->findResource("data", QLatin1String("autocorrect/custom-") + mAutoCorrectLang + QLatin1String(".xml"));
723
if(!kdelang.isEmpty())
724
LocalFile = KGlobal::dirs()->findResource("data", QLatin1String("autocorrect/custom-") + kdelang + QLatin1String(".xml"));
725
if (LocalFile.isEmpty() && kdelang.contains(QLatin1String("_"))) {
726
kdelang.remove( QRegExp( QLatin1String("_.*") ) );
727
LocalFile = KGlobal::dirs()->findResource("data", QLatin1String("autocorrect/custom-") + kdelang + QLatin1String(".xml"));
732
//Load Global directly
733
if (!mAutoCorrectLang.isEmpty()) {
734
if(mAutoCorrectLang == QLatin1String("en_US")) {
735
fname = KGlobal::dirs()->findResource("data", QLatin1String("autocorrect/autocorrect.xml"));
737
fname = KGlobal::dirs()->findResource("data", QLatin1String("autocorrect/") + mAutoCorrectLang + QLatin1String(".xml"));
740
if (fname.isEmpty() && !kdelang.isEmpty())
741
fname = KGlobal::dirs()->findResource("data", QLatin1String("autocorrect/") + kdelang + QLatin1String(".xml"));
742
if (fname.isEmpty() && kdelang.contains(QLatin1String("_"))) {
743
kdelang.remove( QRegExp( QLatin1String("_.*") ) );
744
fname = KGlobal::dirs()->findResource("data", QLatin1String("autocorrect/") + kdelang + QLatin1String(".xml"));
748
fname = KGlobal::dirs()->findResource("data", QLatin1String("autocorrect/autocorrect.xml"));
751
if (mAutoCorrectLang.isEmpty())
752
mAutoCorrectLang = kdelang;
753
qDebug()<<" fname :"<<fname;
754
qDebug()<<" LocalFile:"<<LocalFile;
756
if(LocalFile.isEmpty()) {
757
if(fname.isEmpty()) {
758
mTypographicSingleQuotes = typographicDefaultSingleQuotes();
759
mTypographicDoubleQuotes = typographicDefaultDoubleQuotes();
761
ImportKMailAutocorrection import;
762
if (import.import(fname,ImportAbstractAutocorrection::All)) {
763
mUpperCaseExceptions = import.upperCaseExceptions();
764
mTwoUpperLetterExceptions = import.twoUpperLetterExceptions();
765
mAutocorrectEntries = import.autocorrectEntries();
766
mTypographicSingleQuotes = import.typographicSingleQuotes();
767
mTypographicDoubleQuotes = import.typographicDoubleQuotes();
768
mSuperScriptEntries = import.superScriptEntries();
772
ImportKMailAutocorrection import;
773
if (import.import(LocalFile,ImportAbstractAutocorrection::All)) {
774
mUpperCaseExceptions = import.upperCaseExceptions();
775
mTwoUpperLetterExceptions = import.twoUpperLetterExceptions();
776
mAutocorrectEntries = import.autocorrectEntries();
777
mTypographicSingleQuotes = import.typographicSingleQuotes();
778
mTypographicDoubleQuotes = import.typographicDoubleQuotes();
779
//Don't import it in local
780
//mSuperScriptEntries = import.superScriptEntries();
782
if (!fname.isEmpty() && import.import(fname,ImportAbstractAutocorrection::SuperScript)) {
783
mSuperScriptEntries = import.superScriptEntries();
785
qDebug()<<" mSuperScriptEntries"<<mSuperScriptEntries;
789
void ComposerAutoCorrection::writeAutoCorrectionXmlFile()
791
const QString fname = KGlobal::dirs()->locateLocal("data", QLatin1String("autocorrect/custom-") + (mAutoCorrectLang == QLatin1String("en_US") ? QLatin1String("autocorrect") : mAutoCorrectLang) + QLatin1String(".xml"));
793
if( !file.open( QIODevice::WriteOnly | QIODevice::Text ) ) {
794
kDebug()<<"We can't save in file :"<<fname;
797
QDomDocument root(QLatin1String("autocorrection"));
799
QDomElement word = root.createElement(QLatin1String( "Word" ));
800
root.appendChild(word);
801
QDomElement items = root.createElement(QLatin1String( "items" ));
803
QHashIterator<QString, QString> i(mAutocorrectEntries);
804
while (i.hasNext()) {
806
QDomElement item = root.createElement(QLatin1String( "item" ));
807
item.setAttribute(QLatin1String("find"),i.key());
808
item.setAttribute(QLatin1String("replace"),i.value());
809
items.appendChild(item);
811
word.appendChild(items);
814
QDomElement upperCaseExceptions = root.createElement(QLatin1String( "UpperCaseExceptions" ));
815
QSet<QString>::const_iterator upper = mUpperCaseExceptions.constBegin();
816
while (upper != mUpperCaseExceptions.constEnd()) {
817
QDomElement item = root.createElement(QLatin1String( "word" ));
818
item.setAttribute(QLatin1String("exception"),*upper);
819
upperCaseExceptions.appendChild(item);
822
word.appendChild(upperCaseExceptions);
824
QDomElement twoUpperLetterExceptions = root.createElement(QLatin1String( "TwoUpperLetterExceptions" ));
825
QSet<QString>::const_iterator twoUpper = mTwoUpperLetterExceptions.constBegin();
826
while (twoUpper != mTwoUpperLetterExceptions.constEnd()) {
827
QDomElement item = root.createElement(QLatin1String( "word" ));
828
item.setAttribute(QLatin1String("exception"),*twoUpper);
829
twoUpperLetterExceptions.appendChild(item);
832
word.appendChild(twoUpperLetterExceptions);
834
//Don't save it as discussed with Calligra dev
836
QDomElement supperscript = root.createElement(QLatin1String( "SuperScript" ));
837
QHashIterator<QString, QString> j(mSuperScriptEntries);
838
while (j.hasNext()) {
840
QDomElement item = root.createElement(QLatin1String( "superscript" ));
841
item.setAttribute(QLatin1String("find"), j.key());
842
item.setAttribute(QLatin1String("super"), j.value());
843
supperscript.appendChild(item);
845
word.appendChild(supperscript);
848
QDomElement doubleQuote = root.createElement(QLatin1String( "DoubleQuote" ));
849
QDomElement item = root.createElement(QLatin1String( "doublequote" ));
850
item.setAttribute(QLatin1String("begin"),mTypographicDoubleQuotes.begin);
851
item.setAttribute(QLatin1String("end"),mTypographicDoubleQuotes.end);
852
doubleQuote.appendChild(item);
853
word.appendChild(doubleQuote);
855
QDomElement singleQuote = root.createElement(QLatin1String( "SimpleQuote" ));
856
item = root.createElement(QLatin1String( "simplequote" ));
857
item.setAttribute(QLatin1String("begin"),mTypographicSingleQuotes.begin);
858
item.setAttribute(QLatin1String("end"),mTypographicSingleQuotes.end);
859
singleQuote.appendChild(item);
860
word.appendChild(singleQuote);
863
QTextStream ts( &file );
864
ts << root.toString();
869
QString ComposerAutoCorrection::language() const
871
return mAutoCorrectLang;
874
void ComposerAutoCorrection::setLanguage(const QString &lang, bool forceGlobal)
876
if(mAutoCorrectLang != lang || forceGlobal) {
877
mAutoCorrectLang = lang;
879
readAutoCorrectionXmlFile(forceGlobal);