lib

KoAutoFormat.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
00003                  2001       Sven Leiber         <s.leiber@web.de>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "KoAutoFormat.h"
00022 
00023 #include "KoTextObject.h"
00024 #include "KoTextParag.h"
00025 #include "KoVariable.h"
00026 #include "KoParagCounter.h"
00027 #include <KoDocument.h>
00028 #include <KoSearchDia.h>
00029 #include <KoGlobal.h>
00030 
00031 #include <kdeversion.h>
00032 #include <kdebug.h>
00033 #include <klocale.h>
00034 #include <kinstance.h>
00035 #include <kconfig.h>
00036 #include <kstandarddirs.h>
00037 #include <kglobal.h>
00038 #include <kcommand.h>
00039 //#include <KoTextFormat.h>
00040 #include <kcompletion.h>
00041 #include <kcalendarsystem.h>
00042 
00043 #include <qfile.h>
00044 #include <qlabel.h>
00045 #include <qtooltip.h>
00046 #include <qwhatsthis.h>
00047 #include <qdom.h>
00048 #include <qregexp.h>
00049 
00050 
00051 KoCompletionBox::KoCompletionBox( QWidget * parent, const char * name, WFlags f)
00052   : QLabel(parent,name,f)
00053 {
00054   setBackgroundColor(QColor("#FFFFE6"));
00055   setFocusPolicy(QWidget::NoFocus);
00056   setFrameShape(QFrame::Box);
00057 }
00058 
00059 KoCompletionBox::~KoCompletionBox()
00060 {
00061 }
00062 
00063 void KoCompletionBox::mousePressEvent( QMouseEvent *)
00064 {
00065   hide();
00066 }
00067 
00068 QString& KoCompletionBox::lastWord()
00069 {
00070   return m_lastWord;
00071 }
00072 
00073 void KoCompletionBox::setLastWord( QString const &lastword)
00074 {
00075   m_lastWord = lastword;
00076 }
00077 
00078 KoAutoFormatEntry::KoAutoFormatEntry(const QString& replace)
00079     : m_replace( replace )
00080 {
00081     m_formatOptions= 0L;
00082 }
00083 
00084 KoAutoFormatEntry::~KoAutoFormatEntry()
00085 {
00086     delete m_formatOptions;
00087     m_formatOptions=0L;
00088 }
00089 
00090 KoSearchContext *KoAutoFormatEntry::formatEntryContext() const
00091 {
00092     return m_formatOptions;
00093 }
00094 
00095 void KoAutoFormatEntry::createNewEntryContext()
00096 {
00097     if ( !m_formatOptions )
00098     {
00099         m_formatOptions = new KoSearchContext();
00100     }
00101 }
00102 
00103 void KoAutoFormatEntry::setFormatEntryContext( KoSearchContext *_cont )
00104 {
00105     delete m_formatOptions;
00106     m_formatOptions=_cont;
00107 }
00108 
00109 void KoAutoFormatEntry::clearFormatEntryContext( )
00110 {
00111     delete m_formatOptions;
00112     m_formatOptions = 0L;
00113 }
00114 
00115 
00116 /******************************************************************/
00117 /* Class: KoAutoFormat                        */
00118 /******************************************************************/
00119 KoAutoFormat::KoAutoFormat( KoDocument *_doc, KoVariableCollection *_varCollection, KoVariableFormatCollection *_varFormatCollection )
00120     : m_doc( _doc ),
00121       m_varCollection(_varCollection),
00122       m_varFormatCollection(_varFormatCollection),
00123       m_autoFormatLanguage( QString::null),
00124       m_configRead( false ),
00125       m_convertUpperCase( false ), m_convertUpperUpper( false ),
00126       m_advancedAutoCorrect( true ),
00127       m_autoDetectUrl( false ),
00128       m_ignoreDoubleSpace( false ),
00129       m_removeSpaceBeginEndLine( false ),
00130       m_useBulletStyle(false),
00131       m_autoChangeFormat(false),
00132       m_autoReplaceNumber(false),
00133       m_useAutoNumberStyle(false),
00134       m_completion(false),
00135       m_toolTipCompletion(false),
00136       m_completionAppendSpace(false),
00137       m_addCompletionWord(true),
00138       m_includeTwoUpperLetterException(false),
00139       m_includeAbbreviation(false),
00140       m_ignoreUpperCase(false),
00141       m_bAutoFormatActive(true),
00142       m_bAutoSuperScript( false ),
00143       m_bAutoCorrectionWithFormat( false ),
00144       m_bCapitalizeNameOfDays( false ),
00145       m_wordInserted( false ),
00146       m_bulletStyle(),
00147       m_typographicSimpleQuotes(),
00148       m_typographicDoubleQuotes(),
00149       m_typographicDefaultDoubleQuotes(),
00150       m_typographicDefaultSimpleQuotes(),
00151       m_listCompletion( new KCompletion ),
00152       m_entries(17,false),
00153       m_allLanguages(17,false),
00154       m_superScriptEntries(),
00155       m_upperCaseExceptions(),
00156       m_twoUpperLetterException(),
00157       m_maxFindLength( 0 ),
00158       m_minCompletionWordLength( 5 ),
00159       m_nbMaxCompletionWord( 500 ),
00160       m_countMaxWords(0),
00161       m_completionBox(0),
00162       m_keyCompletionAction( Enter )
00163 
00164 {
00165     //load once this list not each time that we "readConfig"
00166     loadListOfWordCompletion();
00167     m_listCompletion->setIgnoreCase( true );
00168     updateMaxWords();
00169     KLocale klocale(m_doc->instance()->instanceName());
00170     for (int i = 1; i <=7; i++)
00171     {
00172         m_cacheNameOfDays.append(klocale.calendar()->weekDayName( i ).lower());
00173     }
00174 }
00175 
00176 KoAutoFormat::KoAutoFormat( const KoAutoFormat& format )
00177     : m_doc( format.m_doc ),
00178       m_varCollection( format.m_varCollection ),
00179       m_varFormatCollection( format.m_varFormatCollection ),
00180       m_autoFormatLanguage( format.m_autoFormatLanguage),
00181       m_configRead( format.m_configRead ),
00182       m_convertUpperCase( format.m_convertUpperCase ),
00183       m_convertUpperUpper( format.m_convertUpperUpper ),
00184       m_advancedAutoCorrect( format.m_advancedAutoCorrect ),
00185       m_autoDetectUrl( format.m_autoDetectUrl ),
00186       m_ignoreDoubleSpace( format.m_ignoreDoubleSpace ),
00187       m_removeSpaceBeginEndLine( format.m_removeSpaceBeginEndLine ),
00188       m_useBulletStyle( format.m_useBulletStyle ),
00189       m_autoChangeFormat( format.m_autoChangeFormat ),
00190       m_autoReplaceNumber( format.m_autoReplaceNumber ),
00191       m_useAutoNumberStyle( format.m_useAutoNumberStyle ),
00192       m_completion( format.m_completion ),
00193       m_toolTipCompletion( format.m_toolTipCompletion),
00194       m_completionAppendSpace( format.m_completionAppendSpace ),
00195       m_addCompletionWord( format.m_addCompletionWord ),
00196       m_includeTwoUpperLetterException( format.m_includeTwoUpperLetterException ),
00197       m_includeAbbreviation( format.m_includeAbbreviation ),
00198       m_ignoreUpperCase( format.m_ignoreUpperCase ),
00199       m_bAutoFormatActive( format.m_bAutoFormatActive ),
00200       m_bAutoSuperScript( format.m_bAutoSuperScript ),
00201       m_bAutoCorrectionWithFormat( format.m_bAutoCorrectionWithFormat),
00202       m_bCapitalizeNameOfDays( format.m_bCapitalizeNameOfDays),
00203       m_bulletStyle( format.m_bulletStyle ),
00204       m_typographicSimpleQuotes( format.m_typographicSimpleQuotes ),
00205       m_typographicDoubleQuotes( format.m_typographicDoubleQuotes ),
00206       m_typographicDefaultDoubleQuotes( format.m_typographicDefaultDoubleQuotes),
00207       m_typographicDefaultSimpleQuotes( format.m_typographicDefaultSimpleQuotes),
00208       m_listCompletion( 0L ), // don't copy it!
00209       m_entries(17,false ),//don't copy it.
00210       m_allLanguages(17,false), //don't copy it
00211       m_superScriptEntries ( format.m_superScriptEntries ),
00212       m_upperCaseExceptions( format.m_upperCaseExceptions ),
00213       m_twoUpperLetterException( format.m_twoUpperLetterException ),
00214       m_maxFindLength( format.m_maxFindLength ),
00215       m_minCompletionWordLength( format.m_minCompletionWordLength ),
00216       m_nbMaxCompletionWord( format.m_nbMaxCompletionWord ),
00217       m_cacheNameOfDays( format.m_cacheNameOfDays),
00218       m_completionBox(0),
00219       m_keyCompletionAction( format.m_keyCompletionAction )
00220 {
00221     //m_listCompletion=new KCompletion();
00222     //m_listCompletion->setItems( autoFormat.listCompletion() );
00223     //copyAutoFormatEntries( autoFormat );
00224 }
00225 
00226 KoAutoFormat::~KoAutoFormat()
00227 {
00228     delete m_listCompletion;
00229     m_entries.setAutoDelete( true );
00230     m_entries.clear();
00231     m_allLanguages.setAutoDelete( true );
00232     m_allLanguages.clear();
00233 }
00234 
00235 void KoAutoFormat::updateMaxWords()
00236 {
00237     QStringList list = m_listCompletion->items();
00238     for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
00239     {
00240         QString tmp = *it;
00241         uint maxword = 1;
00242 
00243         for (uint i=0; i < (uint)tmp.length(); i++)
00244                 if ( tmp.at(i).isSpace() || tmp.at(i).isPunct() )
00245                         maxword++;
00246         if (maxword >  m_countMaxWords )
00247                 m_countMaxWords = maxword;
00248     }
00249     kdDebug() << "m_countMaxWords: " << m_countMaxWords << endl;
00250 }
00251 
00252 void KoAutoFormat::loadListOfWordCompletion()
00253 {
00254     KConfig* config = KoGlobal::kofficeConfig();
00255     KConfigGroupSaver cgs( config, "Completion Word" );
00256     m_listCompletion->insertItems(config->readListEntry( "list" ));
00257 }
00258 
00259 void KoAutoFormat::readConfig(bool force)
00260 {
00261     // Read the autoformat configuration
00262     // This is done on demand (when typing the first char, or when opening the config dialog)
00263     // so that loading is faster and to avoid doing it for readonly documents.
00264     if ( m_configRead && !force )
00265         return;
00266     KConfig* config = KoGlobal::kofficeConfig();
00267     KConfigGroupSaver cgs( config, "AutoFormat" );
00268     //when we force don't load format language.
00269     if ( !force)
00270         m_autoFormatLanguage = config->readEntry("formatLanguage", QString::null);
00271 
00272     m_convertUpperCase = config->readBoolEntry( "ConvertUpperCase", false );
00273     m_convertUpperUpper = config->readBoolEntry( "ConvertUpperUpper", false );
00274     m_includeTwoUpperLetterException = config->readBoolEntry( "includeTwoLetterException", false );
00275     m_includeAbbreviation = config->readBoolEntry( "includeAbbreviation", false );
00276 
00277     m_advancedAutoCorrect = config->readBoolEntry( "AdvancedAutocorrect", true );
00278     m_bAutoCorrectionWithFormat = config->readBoolEntry( "AutoCorrectionWithFormat",false );
00279     m_bCapitalizeNameOfDays = config->readBoolEntry( "CapitalizeNameOfDays",false );
00280 
00281     m_autoDetectUrl = config->readBoolEntry("AutoDetectUrl",false);
00282     m_ignoreDoubleSpace = config->readBoolEntry("IgnoreDoubleSpace", true);
00283     m_removeSpaceBeginEndLine = config->readBoolEntry("RemoveSpaceBeginEndLine", true);
00284 
00285     m_useBulletStyle = config->readBoolEntry("UseBulletStyle",false);
00286     QString tmp = config->readEntry( "BulletStyle", "" );
00287     m_bulletStyle = tmp.isEmpty() ? QChar() : tmp[0];
00288 
00289     m_autoChangeFormat = config->readBoolEntry( "AutoChangeFormat", false );
00290 
00291     m_autoReplaceNumber = config->readBoolEntry( "AutoReplaceNumber", true );
00292 
00293     m_useAutoNumberStyle = config->readBoolEntry( "AutoNumberStyle", false );
00294 
00295 
00296     QString beginDoubleQuote = config->readEntry( "TypographicQuotesBegin" );
00297     QString endDoubleQuote = config->readEntry( "TypographicQuotesEnd" );
00298 
00299     m_typographicDoubleQuotes.replace = config->readBoolEntry( "TypographicQuotesEnabled", false );
00300 
00301     QString begin = config->readEntry( "TypographicSimpleQuotesBegin" );
00302     QString end = config->readEntry( "TypographicSimpleQuotesEnd" );
00303     m_typographicSimpleQuotes.replace = config->readBoolEntry( "TypographicSimpleQuotesEnabled", false );
00304 
00305     m_bAutoSuperScript = config->readBoolEntry( "AutoSuperScript", true );
00306 
00307     config->setGroup( "completion" );
00308     m_completion = config->readBoolEntry( "completion", false );
00309 
00310     m_completionAppendSpace = config->readBoolEntry( "CompletionAppendSpace", false );
00311     m_minCompletionWordLength = config->readUnsignedNumEntry( "CompletionMinWordLength", 5 );
00312     m_nbMaxCompletionWord = config->readUnsignedNumEntry( "NbMaxCompletionWord", 100 );
00313     m_addCompletionWord = config->readBoolEntry( "AddCompletionWord", true );
00314     m_toolTipCompletion = config->readBoolEntry( "ToolTipCompletion", true );
00315     m_keyCompletionAction = ( KoAutoFormat::KeyCompletionAction )config->readUnsignedNumEntry( "CompletionKeyAction", 0 );
00316 
00317     if ( force )
00318     {
00319         m_entries.setAutoDelete(true);
00320         m_entries.clear();
00321         m_entries.setAutoDelete(false);
00322         m_allLanguages.setAutoDelete(true);
00323         m_allLanguages.clear();
00324         m_allLanguages.setAutoDelete(false);
00325         m_upperCaseExceptions.clear();
00326         m_superScriptEntries.clear();
00327         m_twoUpperLetterException.clear();
00328 
00329     }
00330 
00331     //config->setGroup( "AutoFormatEntries" );
00332 
00333     readAutoCorrectConfig();
00334 
00335     if( beginDoubleQuote.isEmpty())
00336     {
00337         if( m_typographicDefaultDoubleQuotes.begin.isNull())
00338             m_typographicDoubleQuotes.begin = QChar('«');
00339         else
00340             m_typographicDoubleQuotes.begin = m_typographicDefaultDoubleQuotes.begin;
00341     }
00342     else
00343         m_typographicDoubleQuotes.begin = beginDoubleQuote[0];
00344 
00345     if( endDoubleQuote.isEmpty() )
00346     {
00347         if( m_typographicDefaultDoubleQuotes.end.isNull())
00348             m_typographicDoubleQuotes.end = QChar('»');
00349         else
00350             m_typographicDoubleQuotes.end = m_typographicDefaultDoubleQuotes.end;
00351     }
00352     else
00353         m_typographicDoubleQuotes.end = endDoubleQuote[0];
00354 
00355     m_typographicDoubleQuotes.replace = m_typographicDoubleQuotes.replace
00356                                         && !m_typographicDoubleQuotes.begin.isNull()
00357                                         && !m_typographicDoubleQuotes.end.isNull();
00358 
00359 
00360     if( begin.isEmpty())
00361     {
00362         if( m_typographicDefaultSimpleQuotes.begin.isNull())
00363             m_typographicSimpleQuotes.begin = QChar('\'');
00364         else
00365             m_typographicSimpleQuotes.begin = m_typographicDefaultSimpleQuotes.begin;
00366     }
00367     else
00368         m_typographicSimpleQuotes.begin = begin[0];
00369 
00370     if( end.isEmpty() )
00371     {
00372         if( m_typographicDefaultSimpleQuotes.end.isNull())
00373             m_typographicSimpleQuotes.end = QChar('\'');
00374         else
00375             m_typographicSimpleQuotes.end = m_typographicDefaultSimpleQuotes.end;
00376     }
00377     else
00378         m_typographicSimpleQuotes.end = end[0];
00379 
00380     m_typographicSimpleQuotes.replace = m_typographicSimpleQuotes.replace
00381                                         && !m_typographicSimpleQuotes.end.isNull()
00382                                         && !m_typographicSimpleQuotes.begin.isNull();
00383 
00384 
00385     loadAllLanguagesAutoCorrection();
00386     buildMaxLen();
00387     autoFormatIsActive();
00388     m_configRead = true;
00389 }
00390 
00391 void KoAutoFormat::readAutoCorrectConfig()
00392 {
00393     Q_ASSERT( m_entries.isEmpty() ); // readConfig is only called once...
00394     KLocale klocale(m_doc->instance()->instanceName());
00395     QString kdelang = klocale.languageList().front();
00396     kdelang.remove( QRegExp( "@.*" ) );
00397     kdDebug(32500) << "KoAutoFormat: m_autoFormatLanguage=" << m_autoFormatLanguage << " kdelang=" << kdelang << endl;
00398     QString fname;
00399     if ( !m_autoFormatLanguage.isEmpty() )
00400     {
00401         fname = locate( "data", "koffice/autocorrect/" + m_autoFormatLanguage + ".xml", m_doc->instance() );
00402     }
00403     if ( m_autoFormatLanguage != "all_languages" )
00404     {
00405         if ( fname.isEmpty() && !kdelang.isEmpty() )
00406             fname = locate( "data", "koffice/autocorrect/" + kdelang + ".xml", m_doc->instance() );
00407         if ( fname.isEmpty() && kdelang.contains("_") )
00408         {
00409             kdelang.remove( QRegExp( "_.*" ) );
00410             fname = locate( "data", "koffice/autocorrect/" + kdelang + ".xml", m_doc->instance() );
00411         }
00412         if ( fname.isEmpty() )
00413             fname = locate( "data", "koffice/autocorrect/autocorrect.xml", m_doc->instance() );
00414     }
00415     if ( fname.isEmpty() )
00416         return;
00417     QFile xmlFile(fname);
00418     if(!xmlFile.open(IO_ReadOnly))
00419         return;
00420 
00421     QDomDocument doc;
00422     if(!doc.setContent(&xmlFile))
00423         return;
00424 
00425     if(doc.doctype().name() != "autocorrection") {
00426         //return;
00427     }
00428     QDomElement de=doc.documentElement();
00429 
00430     loadAutoCorrection( de );
00431 
00432     QDomElement upper = de.namedItem( "UpperCaseExceptions" ).toElement();
00433     if(!upper.isNull())
00434     {
00435         QDomNodeList nl = upper.childNodes();
00436         for(uint i = 0; i < nl.count(); i++)
00437         {
00438             m_upperCaseExceptions+= nl.item(i).toElement().attribute("exception");
00439         }
00440     }
00441 
00442     QDomElement twoUpper = de.namedItem( "TwoUpperLetterExceptions" ).toElement();
00443     if(!twoUpper.isNull())
00444     {
00445         QDomNodeList nl = twoUpper.childNodes();
00446         for(uint i = 0; i < nl.count(); i++)
00447         {
00448             m_twoUpperLetterException+= nl.item(i).toElement().attribute("exception");
00449         }
00450     }
00451 
00452     QDomElement superScript = de.namedItem( "SuperScript" ).toElement();
00453     if(!superScript.isNull())
00454     {
00455         QDomNodeList nl = superScript.childNodes();
00456         for(uint i = 0; i < nl.count() ; i++) {
00457             //bug in qmap we overwrite = false doesn't work
00458             //so we can't add multiple "othernb"
00459             m_superScriptEntries.insert( nl.item(i).toElement().attribute("find"), KoAutoFormatEntry(nl.item(i).toElement().attribute("super")),FALSE );
00460         }
00461     }
00462 
00463     QDomElement doubleQuote = de.namedItem( "DoubleQuote" ).toElement();
00464     if(!doubleQuote.isNull())
00465     {
00466         QDomElement childItem = doubleQuote.namedItem("doublequote").toElement();
00467         if ( !childItem.isNull() )
00468         {
00469             QString attr = childItem.attribute( "begin" );
00470             if ( !attr.isEmpty() && attr[0] != 0 )
00471                 m_typographicDefaultDoubleQuotes.begin = attr[0];
00472             attr = childItem.attribute( "end" );
00473             if ( !attr.isEmpty() && attr[0] != 0 )
00474                 m_typographicDefaultDoubleQuotes.end = attr[0];
00475         }
00476     }
00477     QDomElement simpleQuote = de.namedItem( "SimpleQuote" ).toElement();
00478     if(!simpleQuote.isNull())
00479     {
00480         QDomElement childItem = simpleQuote.namedItem("simplequote").toElement();
00481         if ( !childItem.isNull() )
00482         {
00483             QString attr = childItem.attribute( "begin" );
00484             if ( !attr.isEmpty() && attr[0] != 0 )
00485                 m_typographicDefaultSimpleQuotes.begin = attr[0];
00486             attr = childItem.attribute( "end" );
00487             if ( !attr.isEmpty() && attr[0] != 0 )
00488                 m_typographicDefaultSimpleQuotes.end = attr[0];
00489         }
00490     }
00491 }
00492 
00493 void KoAutoFormat::loadAllLanguagesAutoCorrection()
00494 {
00495     QString fname = locate( "data", "koffice/autocorrect/all_languages.xml", m_doc->instance() );
00496     if ( fname.isEmpty() )
00497         return;
00498     QFile xmlFile( fname );
00499     if(xmlFile.open(IO_ReadOnly))
00500     {
00501         QDomDocument doc;
00502         if(!doc.setContent(&xmlFile)) {
00503             return;
00504         }
00505         if(doc.doctype().name() != "autocorrection") {
00506             //return;
00507         }
00508         QDomElement de=doc.documentElement();
00509 
00510         loadAutoCorrection( de, true );
00511         xmlFile.close();
00512     }
00513 }
00514 
00515 void KoAutoFormat::loadAutoCorrection( const QDomElement & _de, bool _allLanguages )
00516 {
00517     QDomElement item = _de.namedItem( "items" ).toElement();
00518     if(!item.isNull())
00519     {
00520         QDomNodeList nl = item.childNodes();
00521         m_maxFindLength=nl.count();
00522         for(uint i = 0; i < m_maxFindLength; i++) {
00523             loadEntry( nl.item(i).toElement(), _allLanguages);
00524         }
00525     }
00526 }
00527 
00528 void KoAutoFormat::loadEntry( const QDomElement &nl, bool _allLanguages)
00529 {
00530     KoAutoFormatEntry *tmp =new KoAutoFormatEntry(nl.attribute("replace"));
00531     if ( nl.hasAttribute("FONT"))
00532     {
00533         tmp->createNewEntryContext();
00534         tmp->formatEntryContext()->m_family=nl.attribute("FONT");
00535         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::Family;
00536     }
00537     if ( nl.hasAttribute("SIZE" ))
00538     {
00539         tmp->createNewEntryContext();
00540         tmp->formatEntryContext()->m_size = nl.attribute("SIZE" ).toInt();
00541         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::Size;
00542     }
00543     if (nl.hasAttribute("BOLD" ))
00544     {
00545         tmp->createNewEntryContext();
00546         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::Bold;
00547         QString value = nl.attribute("BOLD");
00548         if ( value.toInt() == 1 )
00549             tmp->formatEntryContext()->m_options |= KoSearchContext::Bold;
00550     }
00551     if (nl.hasAttribute("ITALIC" ))
00552     {
00553         tmp->createNewEntryContext();
00554         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::Italic;
00555         QString value = nl.attribute("ITALIC");
00556         if ( value.toInt() == 1 )
00557             tmp->formatEntryContext()->m_options |= KoSearchContext::Italic;
00558     }
00559     if (nl.hasAttribute("UNDERLINE" ))
00560     {
00561         tmp->createNewEntryContext();
00562         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::Underline;
00563         QString value = nl.attribute("UNDERLINE");
00564         if ( value =="single" )
00565             tmp->formatEntryContext()->m_underline = KoTextFormat::U_SIMPLE;
00566         else if ( value =="double" )
00567             tmp->formatEntryContext()->m_underline = KoTextFormat::U_DOUBLE;
00568         else if ( value =="single-bold" )
00569             tmp->formatEntryContext()->m_underline = KoTextFormat::U_SIMPLE_BOLD;
00570         else
00571             tmp->formatEntryContext()->m_underline = KoTextFormat::U_NONE;
00572     }
00573     if (nl.hasAttribute("STRIKEOUT" ))
00574     {
00575         tmp->createNewEntryContext();
00576         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::StrikeOut;
00577         QString value = nl.attribute("STRIKEOUT");
00578         if ( value =="single" )
00579             tmp->formatEntryContext()->m_strikeOut = KoTextFormat::S_SIMPLE;
00580         else if ( value =="double" )
00581             tmp->formatEntryContext()->m_strikeOut = KoTextFormat::S_DOUBLE;
00582         else if ( value =="single-bold" )
00583             tmp->formatEntryContext()->m_strikeOut = KoTextFormat::S_SIMPLE_BOLD;
00584         else
00585             tmp->formatEntryContext()->m_strikeOut = KoTextFormat::S_NONE;
00586     }
00587     if (nl.hasAttribute("VERTALIGN" ))
00588     {
00589         tmp->createNewEntryContext();
00590         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::VertAlign;
00591         QString value = nl.attribute("VERTALIGN");
00592         tmp->formatEntryContext()->m_vertAlign=static_cast<KoTextFormat::VerticalAlignment>( value.toInt() );
00593 
00594     }
00595     if ( nl.hasAttribute("TEXTCOLOR" ))
00596     {
00597         tmp->createNewEntryContext();
00598         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::Color;
00599         QColor col( nl.attribute("TEXTCOLOR" ));
00600         tmp->formatEntryContext()->m_color = col;
00601     }
00602     if ( nl.hasAttribute("TEXTBGCOLOR" ))
00603     {
00604         tmp->createNewEntryContext();
00605         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::BgColor;
00606         QColor col( nl.attribute("TEXTBGCOLOR" ));
00607         tmp->formatEntryContext()->m_backGroundColor = col;
00608     }
00609     if ( !_allLanguages )
00610         m_entries.insert( nl.attribute("find"), tmp );
00611     else
00612         m_allLanguages.insert( nl.attribute("find"), tmp );
00613 
00614 }
00615 
00616 void KoAutoFormat::saveConfig()
00617 {
00618     KConfig* config = KoGlobal::kofficeConfig();
00619     KLocale klocale(m_doc->instance()->instanceName());
00620 
00621     KConfigGroupSaver cgs( config, "AutoFormat" );
00622     config->writeEntry( "ConvertUpperCase", m_convertUpperCase );
00623     config->writeEntry( "formatLanguage", m_autoFormatLanguage=="all_languages" ? klocale.languageList().front() : m_autoFormatLanguage);
00624 
00625     config->writeEntry( "ConvertUpperUpper", m_convertUpperUpper );
00626     config->writeEntry( "includeTwoLetterException", m_includeTwoUpperLetterException );
00627     config->writeEntry( "includeAbbreviation", m_includeAbbreviation );
00628 
00629     config->writeEntry( "TypographicQuotesBegin", QString( m_typographicDoubleQuotes.begin ) );
00630     config->writeEntry( "TypographicQuotesEnd", QString( m_typographicDoubleQuotes.end ) );
00631     config->writeEntry( "TypographicQuotesEnabled", m_typographicDoubleQuotes.replace );
00632     config->writeEntry( "TypographicSimpleQuotesBegin", QString( m_typographicSimpleQuotes.begin ) );
00633     config->writeEntry( "TypographicSimpleQuotesEnd", QString( m_typographicSimpleQuotes.end ) );
00634     config->writeEntry( "TypographicSimpleQuotesEnabled", m_typographicSimpleQuotes.replace );
00635 
00636     config->writeEntry( "AdvancedAutocorrect", m_advancedAutoCorrect );
00637     config->writeEntry( "AutoCorrectionWithFormat", m_bAutoCorrectionWithFormat );
00638     config->writeEntry( "CapitalizeNameOfDays", m_bCapitalizeNameOfDays );
00639 
00640     config->writeEntry( "AutoDetectUrl",m_autoDetectUrl);
00641 
00642     config->writeEntry( "IgnoreDoubleSpace",m_ignoreDoubleSpace );
00643     config->writeEntry( "RemoveSpaceBeginEndLine",m_removeSpaceBeginEndLine );
00644 
00645     config->writeEntry( "UseBulletStyle", m_useBulletStyle);
00646     config->writeEntry( "BulletStyle", QString(m_bulletStyle));
00647 
00648     config->writeEntry( "AutoChangeFormat", m_autoChangeFormat);
00649 
00650     config->writeEntry( "AutoReplaceNumber", m_autoReplaceNumber);
00651 
00652     config->writeEntry( "AutoNumberStyle", m_useAutoNumberStyle );
00653 
00654     config->writeEntry( "AutoSuperScript", m_bAutoSuperScript );
00655 
00656     config->setGroup( "completion" );
00657     config->writeEntry( "completion", m_completion );
00658     config->writeEntry( "CompletionAppendSpace", m_completionAppendSpace );
00659     config->writeEntry( "CompletionMinWordLength", m_minCompletionWordLength);
00660     config->writeEntry( "NbMaxCompletionWord", m_nbMaxCompletionWord);
00661     config->writeEntry( "AddCompletionWord", m_addCompletionWord );
00662     config->writeEntry( "ToolTipCompletion", m_toolTipCompletion );
00663     config->writeEntry( "CompletionKeyAction", ( int )m_keyCompletionAction );
00664 
00665     config->setGroup( "AutoFormatEntries" );
00666     QDictIterator<KoAutoFormatEntry> it( m_entries );
00667 
00668     //refresh m_maxFindLength
00669     m_maxFindLength=0;
00670     QDomDocument doc("autocorrection");
00671 
00672     QDomElement begin = doc.createElement( "Word" );
00673     doc.appendChild( begin );
00674     QDomElement items;
00675     items = doc.createElement("items");
00676     QDomElement data;
00677     for ( ; it.current() ; ++it )
00678     {
00679     items.appendChild(saveEntry( it, doc));
00680         //m_maxFindLength=QMAX(m_maxFindLength,it.currentKey().length());
00681     }
00682     buildMaxLen();
00683     begin.appendChild(items);
00684 
00685     QDomElement upper;
00686     upper = doc.createElement("UpperCaseExceptions");
00687     for ( QStringList::Iterator it = m_upperCaseExceptions.begin(); it != m_upperCaseExceptions.end();++it )
00688     {
00689     data = doc.createElement("word");
00690     data.setAttribute("exception",(*it) );
00691     upper.appendChild(data);
00692     }
00693     begin.appendChild(upper);
00694 
00695     QDomElement twoUpper;
00696     twoUpper = doc.createElement("TwoUpperLetterExceptions");
00697 
00698     for ( QStringList::Iterator it = m_twoUpperLetterException.begin(); it != m_twoUpperLetterException.end();++it )
00699     {
00700     data = doc.createElement("word");
00701     data.setAttribute("exception",(*it) );
00702     twoUpper.appendChild(data);
00703     }
00704     begin.appendChild(twoUpper);
00705 
00706     QDomElement super;
00707     super = doc.createElement("SuperScript");
00708     KoAutoFormatEntryMap::Iterator it2 = m_superScriptEntries.begin();
00709     for ( ; it2 != m_superScriptEntries.end() ; ++it2 )
00710     {
00711     data = doc.createElement("superscript");
00712     data.setAttribute("find", it2.key());
00713     data.setAttribute("super", it2.data().replace());
00714     super.appendChild(data);
00715     }
00716     begin.appendChild(super);
00717 
00718     QDomElement doubleQuote;
00719     doubleQuote = doc.createElement("DoubleQuote");
00720     data = doc.createElement("doublequote");
00721     data.setAttribute("begin", QString(m_typographicDefaultDoubleQuotes.begin));
00722     data.setAttribute("end", QString(m_typographicDefaultDoubleQuotes.end));
00723     doubleQuote.appendChild(data);
00724     begin.appendChild(doubleQuote);
00725 
00726 
00727     QDomElement simpleQuote;
00728     simpleQuote = doc.createElement("SimpleQuote");
00729     data = doc.createElement("simplequote");
00730     data.setAttribute("begin", QString(m_typographicDefaultSimpleQuotes.begin));
00731     data.setAttribute("end", QString(m_typographicDefaultSimpleQuotes.end));
00732     simpleQuote.appendChild(data);
00733     begin.appendChild(simpleQuote);
00734     QFile f;
00735     if ( m_autoFormatLanguage.isEmpty())
00736         f.setName(locateLocal("data", "koffice/autocorrect/"+klocale.languageList().front() + ".xml",m_doc->instance()));
00737     else
00738         f.setName(locateLocal("data", "koffice/autocorrect/"+m_autoFormatLanguage + ".xml",m_doc->instance()));
00739     if(!f.open(IO_WriteOnly)) {
00740         kdWarning()<<"Error during saving autoformat to " << f.name() << endl;
00741     return;
00742     }
00743     QTextStream ts(&f);
00744     doc.save(ts, 2);
00745     f.close();
00746     autoFormatIsActive();
00747     config->sync();
00748 }
00749 
00750 QDomElement KoAutoFormat::saveEntry( QDictIterator<KoAutoFormatEntry> _entry, QDomDocument doc)
00751 {
00752     QDomElement data;
00753     data = doc.createElement("item");
00754     data.setAttribute("find", _entry.currentKey());
00755     data.setAttribute("replace", _entry.current()->replace());
00756     if ( _entry.current()->formatEntryContext() )
00757     {
00758         KoSearchContext *tmp = _entry.current()->formatEntryContext();
00759         if ( tmp->m_optionsMask & KoSearchContext::Family )
00760         {
00761             data.setAttribute("FONT", tmp->m_family);
00762         }
00763         if ( tmp->m_optionsMask &  KoSearchContext::Size )
00764         {
00765             data.setAttribute("SIZE", tmp->m_size);
00766         }
00767         if ( tmp->m_optionsMask & KoSearchContext::Italic )
00768         {
00769             data.setAttribute("ITALIC", static_cast<bool>(tmp->m_options & KoSearchContext::Italic));
00770         }
00771         if ( tmp->m_optionsMask & KoSearchContext::Bold )
00772         {
00773             data.setAttribute("BOLD", static_cast<bool>(tmp->m_options & KoSearchContext::Bold));
00774         }
00775         if ( tmp->m_optionsMask & KoSearchContext::Shadow )
00776         {
00777             data.setAttribute("SHADOWTEXT", static_cast<bool>(tmp->m_options & KoSearchContext::Shadow));
00778         }
00779         if ( tmp->m_optionsMask & KoSearchContext::WordByWord )
00780         {
00781             data.setAttribute("WORDBYWORD", static_cast<bool>(tmp->m_options & KoSearchContext::WordByWord));
00782         }
00783 
00784         if ( tmp->m_optionsMask & KoSearchContext::Underline )
00785         {
00786             switch( tmp->m_underline )
00787             {
00788             case KoTextFormat::U_SIMPLE:
00789                 data.setAttribute("UNDERLINE", "single");
00790                 break;
00791             case KoTextFormat::U_DOUBLE:
00792                 data.setAttribute("UNDERLINE", "double");
00793                 break;
00794             case KoTextFormat::U_SIMPLE_BOLD:
00795                 data.setAttribute("UNDERLINE", "single-bold");
00796                 break;
00797             case KoTextFormat::U_WAVE:
00798                 data.setAttribute("UNDERLINE", "wave");
00799                 break;
00800             case KoTextFormat::U_NONE:
00801                 data.setAttribute("UNDERLINE", "none");
00802                 break;
00803             }
00804         }
00805         if ( tmp->m_optionsMask & KoSearchContext::StrikeOut )
00806         {
00807             switch( tmp->m_strikeOut )
00808             {
00809             case KoTextFormat::S_SIMPLE:
00810                 data.setAttribute("STRIKEOUT", "single");
00811                 break;
00812             case KoTextFormat::S_DOUBLE:
00813                 data.setAttribute("STRIKEOUT", "double");
00814                 break;
00815             case KoTextFormat::S_NONE:
00816                 data.setAttribute("STRIKEOUT", "none");
00817                 break;
00818             case KoTextFormat::S_SIMPLE_BOLD:
00819                 data.setAttribute("STRIKEOUT", "single-bold");
00820                 break;
00821             }
00822         }
00823         if ( tmp->m_optionsMask & KoSearchContext::Attribute )
00824         {
00825             data.setAttribute("FONTATTRIBUTE", KoTextFormat::attributeFontToString( tmp->m_attribute ) );
00826         }
00827 
00828         if ( tmp->m_optionsMask & KoSearchContext::VertAlign)
00829         {
00830             data.setAttribute( "VERTALIGN", static_cast<int>(tmp->m_vertAlign) );
00831         }
00832         if ( tmp->m_optionsMask & KoSearchContext::BgColor )
00833         {
00834             data.setAttribute( "TEXTCOLOR", tmp->m_color.name());
00835         }
00836         if ( tmp->m_optionsMask & KoSearchContext::Color )
00837         {
00838             data.setAttribute( "TEXTCOLOR", tmp->m_color.name());
00839         }
00840         if ( tmp->m_optionsMask & KoSearchContext::BgColor )
00841         {
00842             data.setAttribute( "TEXTBGCOLOR", tmp->m_backGroundColor.name());
00843         }
00844         if ( tmp->m_optionsMask & KoSearchContext::Language )
00845             data.setAttribute( "LANGUAGE", tmp->m_language );
00846     }
00847     return data;
00848 }
00849 
00850 void KoAutoFormat::addAutoFormatEntry( const QString &key, const QString &replace )
00851 {
00852     KoAutoFormatEntry *findEntry = m_entries.find( key);
00853     if ( findEntry )
00854     {
00855         if ( findEntry->replace().lower() == replace.lower() )
00856             return;
00857     }
00858 
00859     KoAutoFormatEntry *tmp = new KoAutoFormatEntry( replace );
00860     m_entries.insert( key, tmp );
00861     saveConfig();
00862     buildMaxLen();
00863 }
00864 
00865 QString KoAutoFormat::getLastWord(KoTextParag *parag, int const index)
00866 {
00867     QString lastWord;
00868     KoTextString *s = parag->string();
00869     for ( int i = index - 1; i >= 0; --i )
00870     {
00871         QChar ch = s->at( i ).c;
00872         if ( ch.isSpace() || ch.isPunct() )
00873             break;
00874         lastWord.prepend( ch );
00875     }
00876     return lastWord;
00877 }
00878 
00879 QString KoAutoFormat::getLastWord(const int max_words, KoTextParag *parag, int const index)
00880 {
00881     QString lastWord;
00882     KoTextString const *s = parag->string();
00883     int words = 0;
00884     for ( int i = index - 1; i >= 0; --i )
00885     {
00886         QChar ch = s->at( i ).c;
00887         if ( ch.isSpace() || ch.isPunct() )
00888         {
00889                 ++words;
00890                 if (words >= max_words)
00891                         break;
00892         }
00893         lastWord.prepend( ch );
00894     }
00895     return lastWord;
00896 }
00897 
00898 QString KoAutoFormat::getWordAfterSpace(KoTextParag *parag, int const index)
00899 {
00900     QString word;
00901     KoTextString *s = parag->string();
00902     for ( int i = index - 1; i >= 0; --i )
00903     {
00904         QChar ch = s->at( i ).c;
00905         if ( ch.isSpace() )
00906             break;
00907         word.prepend( ch );
00908     }
00909     return word;
00910 
00911 }
00912 
00913 bool KoAutoFormat::doCompletion( KoTextCursor* textEditCursor, KoTextParag *parag, int const index, KoTextObject *txtObj )
00914 {
00915     if( m_completion )
00916     {
00917         bool part=false;
00918         QString lastWord, word;
00919         if (m_completionBox && m_completionBox->isShown() ) //word completion with the tool-tip box
00920         {
00921                 word = m_completionBox->text();
00922                 lastWord = m_completionBox->lastWord();
00923         }
00924         else
00925         {
00926                 QStringList wordlist, new_wordlist;
00927                 for (uint i=1; i <= m_countMaxWords; i++ )
00928                 {
00929                         lastWord = getLastWord(i, parag, index+1);
00930                         wordlist += m_listCompletion->substringCompletion( lastWord ); //find all completion words that contains lastWord
00931                 }
00932                 uint maxlength = 0;
00933                 for ( QStringList::ConstIterator it = wordlist.begin(); it != wordlist.end(); ++it ) // several completion words were found
00934                 {
00935                   if ( (*it).startsWith( lastWord, false ) && new_wordlist.find(*it) == new_wordlist.end() ) //the completion words that begin with lastWord
00936                   {
00937                     if ( (*it).length() > maxlength )
00938                       maxlength = (*it).length();
00939                     new_wordlist.append(*it);
00940                     //kdDebug() << "adding word completion:" << *it << endl;
00941                   }
00942                 }
00943                 if ( new_wordlist.isEmpty() )
00944                     return false;
00945                 if ( new_wordlist.count() == 1 ) // only one completion word was found
00946                   word = new_wordlist.first();
00947                 else
00948                 {
00949                   //we must extract the common part of the completions
00950                   for (uint i = lastWord.length(); i<maxlength && !part; i++) //iterate through all completion words
00951                   {
00952                     QChar ch = new_wordlist.first().at(i);
00953                     for (QStringList::ConstIterator it = new_wordlist.begin(); it != new_wordlist.end(); ++it )
00954                     {
00955                       if ( (*it).at(i).lower() != ch.lower() )
00956                       {
00957                         word = (*it).left(i); //the completion word is truncated here
00958                         //kdDebug() << "set the word completion to:" << word << endl;
00959                         part=true; // completion of a part of a word; a space-character after the completion should not be inserted
00960                         break;
00961                       }
00962                     }
00963                   }
00964                 }
00965                 if (word == lastWord)
00966                         return false;
00967 
00968                 word=lastWord+word.right(word.length()-lastWord.length() );
00969         }
00970         if( !word.isEmpty() )
00971         {
00972             int const lastword_length = lastWord.length();
00973             int const start = index+1 - lastword_length;
00974             int const length = word.length();
00975 
00976             KMacroCommand *macro = new KMacroCommand( i18n("Completion Word"));
00977             KoTextCursor cursor( parag->document() );
00978             cursor.setParag( parag );
00979             cursor.setIndex( start );
00980             KoTextDocument * textdoc = parag->textDocument();
00981             if( m_completionAppendSpace && !part)
00982                 word+=" ";
00983             textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
00984             cursor.setIndex( start + lastword_length );
00985             textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
00986 
00987             macro->addCommand( txtObj->replaceSelectionCommand( textEditCursor, word,
00988                                                                 i18n("Completion Word"),
00989                                                                 KoTextDocument::HighlightSelection ));
00990 
00991             if ( m_completionAppendSpace && !m_ignoreUpperCase && (m_convertUpperUpper || m_convertUpperCase) && !part)
00992             {
00993                 //find the first word
00994                 for (uint i=1; i < word.length(); i++)
00995                         if ( word.at(i).isSpace() || word.at(i).isPunct() )
00996                         {
00997                                word.truncate(i);
00998                                break;
00999                         }
01000                 int const newPos = start + word.length();// + index - 3;
01001                 KCommand *cmd = doUpperCase( textEditCursor, parag, newPos, word, txtObj );
01002                 if( cmd )
01003                     macro->addCommand( cmd );
01004                 txtObj->emitHideCursor();
01005                 textEditCursor->setIndex(start+ length+1);
01006             }
01007             else
01008             {
01009                 txtObj->emitHideCursor();
01010                 textEditCursor->setIndex(start+ length);
01011             }
01012             txtObj->emitNewCommand( macro );
01013 
01014             // The space/tab/CR that we inserted is still there but delete/insert moved the cursor
01015             // -> go right
01016 
01017             txtObj->emitShowCursor();
01018             removeToolTipCompletion();
01019             return true;
01020         }
01021     }
01022     return false;
01023 }
01024 
01025 bool KoAutoFormat::doToolTipCompletion( KoTextCursor* textEditCursor, KoTextParag *parag, int index, KoTextObject *txtObj, int keyPressed )
01026 {
01027     if( m_completion && m_toolTipCompletion && m_completionBox && m_completionBox->isShown() )
01028     {
01029         if ( ( keyPressed == Qt::Key_Return && m_keyCompletionAction==Enter )
01030              || ( keyPressed == Qt::Key_Enter && m_keyCompletionAction==Enter )
01031              || ( keyPressed == Qt::Key_Tab && m_keyCompletionAction==Tab )
01032              || ( keyPressed == Qt::Key_Space && m_keyCompletionAction==Space )
01033              || ( keyPressed == Qt::Key_End && m_keyCompletionAction==End )
01034              || ( keyPressed == Qt::Key_Right && m_keyCompletionAction==Right ))
01035         {
01036             return doCompletion(textEditCursor, parag, index, txtObj);
01037         }
01038     }
01039     return false;
01040 }
01041 void KoAutoFormat::showToolTipBox(KoTextParag *parag,  int index, QWidget *widget, const QPoint &pos )
01042 {
01043 
01044     if( m_completion && m_toolTipCompletion)
01045     {
01046         QString lastWord, word;
01047         for (uint i=1; i <= m_countMaxWords; i++ )
01048         {
01049                 lastWord = getLastWord(i, parag, index+1);
01050                 word=m_listCompletion->makeCompletion( lastWord );
01051                 if ( !word.isEmpty())
01052                         break;
01053         }
01054         if( !word.isEmpty() && word!=lastWord )
01055         {
01056             uint const length = lastWord.length();
01057             if (length<=3)
01058                 return;
01059             word=lastWord+word.right(word.length()-length);
01060             if (!m_completionBox)
01061                 m_completionBox = new KoCompletionBox(0,0,Qt::WType_Popup);
01062             QPoint const show_pos = widget->mapToGlobal(pos);
01063             m_completionBox->setText(word);
01064             m_completionBox->setLastWord(lastWord);
01065             m_completionBox->adjustSize();
01066             int const height = m_completionBox->sizeHint().height();
01067             m_completionBox->move( show_pos.x(), show_pos.y() - height );
01068 
01069             if (!m_completionBox->isShown() )
01070             {
01071                 m_completionBox->show();
01072                 widget->setFocus();
01073             }
01074         }
01075         else
01076                 removeToolTipCompletion();
01077     }
01078 }
01079 void KoAutoFormat::removeToolTipCompletion()
01080 {
01081     if (m_completion && m_toolTipCompletion && m_completionBox && m_completionBox->isShown())
01082         m_completionBox->hide();
01083 }
01084 
01085 void KoAutoFormat::autoFormatIsActive()
01086 {
01087     m_bAutoFormatActive = m_useBulletStyle ||
01088                           m_removeSpaceBeginEndLine ||
01089                           m_autoDetectUrl ||
01090                           m_convertUpperUpper ||
01091                           m_convertUpperCase ||
01092                           m_autoReplaceNumber ||
01093                           m_autoChangeFormat ||
01094                           m_completion ||
01095                           m_typographicDoubleQuotes.replace ||
01096                           m_typographicSimpleQuotes.replace ||
01097                           m_entries.count()!=0 ||
01098                           m_allLanguages.count()!=0;
01099 }
01100 
01101 void KoAutoFormat::doAutoFormat( KoTextCursor* textEditCursor, KoTextParag *parag, int index, QChar ch,KoTextObject *txtObj )
01102 {
01103     m_ignoreUpperCase = false;
01104 
01105     if ( !m_configRead )
01106         readConfig();
01107 
01108     if ( !m_bAutoFormatActive )
01109         return;
01110 
01111     if( ch.isSpace())
01112     {
01113         //a link doesn't have a space
01114         //=>m_ignoreUpperCase = false
01115         //m_ignoreUpperCase=false;
01116 
01117         QString word=getWordAfterSpace(parag,index);
01118 
01119         if ( m_autoChangeFormat && index > 3)
01120         {
01121             KCommand *cmd =doAutoChangeFormat( textEditCursor, parag, index, word, txtObj );
01122             if ( cmd )
01123                 txtObj->emitNewCommand( cmd );
01124 
01125         }
01126         if ( m_autoReplaceNumber )
01127         {
01128             KCommand *cmd = doAutoReplaceNumber( textEditCursor, parag, index, word, txtObj );
01129             if ( cmd )
01130                 txtObj->emitNewCommand( cmd );
01131         }
01132     }
01133 
01134     if( ch =='\n' )
01135     {
01136 
01137         if( m_removeSpaceBeginEndLine && index > 1)
01138         {
01139             KCommand *cmd = doRemoveSpaceBeginEndLine( textEditCursor, parag, txtObj, index );
01140             if ( cmd )
01141                 txtObj->emitNewCommand( cmd );
01142         }
01143         if( m_useBulletStyle  && index > 3)
01144         {
01145             KCommand *cmd =doUseBulletStyle( textEditCursor, parag, txtObj, index );
01146             if ( cmd )
01147                 txtObj->emitNewCommand( cmd );
01148         }
01149         if( m_useAutoNumberStyle && index > 3 )
01150         {
01151             KCommand *cmd =doUseNumberStyle( textEditCursor, parag, txtObj, index );
01152             if ( cmd )
01153                 txtObj->emitNewCommand( cmd );
01154         }
01155         if( m_convertUpperUpper && m_includeTwoUpperLetterException )
01156             doAutoIncludeUpperUpper(textEditCursor, parag, txtObj );
01157         if( m_convertUpperCase && m_includeAbbreviation )
01158             doAutoIncludeAbbreviation(textEditCursor, parag, txtObj );
01159     }
01160 
01161     //kdDebug(32500) << "KoAutoFormat::doAutoFormat ch=" << QString(ch) << endl;
01162     //if ( !m_enabled )
01163     //    return;
01164     // Auto-correction happens when pressing space, tab, CR, punct etc.
01165     if ( (ch.isSpace() || ch==':' || ch=='?' || ch=='!' || ch==',' || (m_advancedAutoCorrect && ch=='.') ) && index > 0 )
01166     {
01167         KCommand *cmd = 0L;
01168         KMacroCommand *macro = 0L;
01169         QString lastWord = getWordAfterSpace(parag, index);
01170         //kdDebug(32500) << "KoAutoFormat::doAutoFormat lastWord=" << lastWord << endl;
01171 
01172         if ( ch == '.')
01173                 detectStartOfLink( parag, index, true );
01174         else
01175                 detectStartOfLink( parag, index, false );
01176 
01177         if ( !m_wordInserted && m_advancedAutoCorrect && !m_ignoreUpperCase)
01178         {
01179                 int const completionBeginPos = index -lastWord.length();
01180                 int newPos = index;
01181                 cmd = doAutoCorrect( textEditCursor, parag, newPos, txtObj );
01182 
01183                 if( cmd )
01184                 {
01185                 if (!macro)
01186                         macro = new KMacroCommand(i18n("Autocorrection"));
01187                 macro->addCommand( cmd );
01188                 }
01189 
01190                 int const endPos=textEditCursor->index();
01191                 bool was_a_replacement;
01192                 if (index == newPos)
01193                         was_a_replacement = false;
01194                 else
01195                         was_a_replacement = true;
01196 
01197                 if( was_a_replacement) // a replacement took place
01198                 {
01199                         txtObj->emitHideCursor();
01200                         if(endPos==0) //new line, the user pressed enter
01201                         {
01202                                 textEditCursor->gotoUp();
01203                                 textEditCursor->gotoLineEnd();
01204                                 newPos=textEditCursor->index();
01205                         }
01206                         else
01207                                 newPos= endPos-1;
01208 
01209                         m_wordInserted = true; //don't allow other replacements in this replacement
01210                         for(int i=completionBeginPos; i<newPos;i++)
01211                         {
01212                                 textEditCursor->setIndex(i);
01213                                 doAutoFormat( textEditCursor, parag, i, parag->toString().at(i),txtObj );
01214 
01215                         }
01216                         textEditCursor->setIndex(newPos);
01217                         doAutoFormat( textEditCursor, parag, newPos, ch,txtObj );
01218                         m_wordInserted = false;
01219                         if (endPos==0)
01220                         {
01221                                 textEditCursor->gotoLineStart();
01222                                 textEditCursor->gotoDown();
01223                         }
01224                         else
01225                                 textEditCursor->setIndex(newPos+1);
01226                         txtObj->emitShowCursor();
01227                         return;
01228                 }
01229 
01230         }
01231 
01232         if (!m_ignoreUpperCase && m_bCapitalizeNameOfDays)
01233         {
01234             KCommand *cmd = doCapitalizeNameOfDays( textEditCursor, parag, index, lastWord, txtObj  );
01235 
01236             if( cmd )
01237             {
01238                 if (!macro)
01239                 macro = new KMacroCommand(i18n("Autocorrection"));
01240                 macro->addCommand( cmd );
01241                 m_ignoreUpperCase = true;
01242             }
01243         }
01244 
01245         if (ch=='.')
01246                 return;
01247 
01248         //kdDebug(32500)<<" m_listCompletion->items() :"<<m_listCompletion->items()<<endl;
01249         if( !m_ignoreUpperCase && m_completion && m_addCompletionWord && m_listCompletion->items().count() < m_nbMaxCompletionWord )
01250         {
01251                 QString completionWord("");
01252                 QChar ch;
01253                 for (uint i=0;i<lastWord.length();i++)
01254                 {
01255                         ch = lastWord.at(i);
01256                         if (ch.isPunct() && ch!='-' && ch!='=' )
01257                         {
01258                                 if (completionWord.at(0) == '-')
01259                                         completionWord.remove(0,1);
01260 
01261                                 if (completionWord.length()>= m_minCompletionWordLength  && !completionWord.isEmpty() && m_listCompletion->makeCompletion(completionWord).isEmpty())
01262                                 {
01263                                         kdDebug() << "Adding:" << completionWord << endl;
01264                                         m_listCompletion->addItem( completionWord );
01265                                         if ( completionWord.length() > m_countMaxWords )
01266                                             m_countMaxWords = completionWord.length();
01267 
01268                                 }
01269                                 completionWord = "";
01270                         }
01271                         else
01272                         {
01273                                 completionWord.append(ch);
01274                                 if (i==lastWord.length()-1)
01275                                 {
01276                                         if (completionWord.at(0) == '-')
01277                                                 completionWord.remove(0,1);
01278                                         if (completionWord.at(completionWord.length()-1) == '-')
01279                                                 completionWord.truncate(completionWord.length()-1);
01280                                         completionWord.remove('=');
01281                                         if (completionWord.length()>= m_minCompletionWordLength && !completionWord.isEmpty() && m_listCompletion->makeCompletion(completionWord).isEmpty())
01282                                         {
01283                                                 kdDebug() << "Adding:" << completionWord << endl;
01284                                                 m_listCompletion->addItem( completionWord );
01285                                                 if ( completionWord.length() > m_countMaxWords )
01286                                                     m_countMaxWords = completionWord.length();
01287                                         }
01288                                 }
01289                         }
01290                 }
01291         }
01292 
01293         if( m_autoDetectUrl && m_ignoreUpperCase && (ch!='?' || lastWord.at(lastWord.length()-1)=='?') )
01294         {
01295                 doAutoDetectUrl( textEditCursor, parag, index, lastWord, txtObj );
01296                 //textEditCursor->gotoRight();
01297         }
01298 
01299         if (!m_ignoreUpperCase && (m_convertUpperUpper || m_convertUpperCase) )
01300         {
01301             cmd = doUpperCase( textEditCursor, parag, index, lastWord, txtObj );
01302 
01303             if( cmd )
01304             {
01305                 if (!macro)
01306                     macro = new KMacroCommand(i18n("Autocorrection"));
01307                 macro->addCommand( cmd );
01308             }
01309         }
01310 
01311         if ( macro )
01312             txtObj->emitNewCommand( macro );
01313 
01314         if(!m_ignoreUpperCase &&  m_bAutoSuperScript && m_superScriptEntries.count()>0)
01315         {
01316             if( lastWord.at(0).isPunct() )
01317                 lastWord.remove(0,1);
01318             KCommand * cmd = doAutoSuperScript( textEditCursor, parag, index, lastWord, txtObj  );
01319             if ( cmd )
01320                 txtObj->emitNewCommand( cmd );
01321         }
01322 
01323     }
01324     else
01325     {
01326         if ( ch == '"' && m_typographicDoubleQuotes.replace )
01327         {
01328                 KCommand *cmd = doTypographicQuotes( textEditCursor, parag, index, txtObj, true /*double quote*/ );
01329                 if ( cmd )
01330                 txtObj->emitNewCommand( cmd );
01331         }
01332         else if ( ch == '\'' && m_typographicDoubleQuotes.replace )
01333         {
01334                 KCommand *cmd = doTypographicQuotes( textEditCursor, parag, index, txtObj, false /* simple quote*/ );
01335                 if ( cmd )
01336                 txtObj->emitNewCommand( cmd );
01337         }
01338     }
01339 }
01340 
01341 KCommand *KoAutoFormat::doAutoCorrect( KoTextCursor* textEditCursor, KoTextParag *parag, int &index, KoTextObject *txtObj )
01342 {
01343     //if(!m_advancedAutoCorrect)
01344       //  return 0L;
01345     // Prepare an array with words of different lengths, all terminating at "index".
01346     // Obviously only full words are put into the array
01347     // But this allows 'find strings' with spaces and punctuation in them.
01348     QString * wordArray = new QString[m_maxFindLength+1];
01349     {
01350         QString word;
01351         KoTextString *s = parag->string();
01352         for ( int i = index - 1; i >= 0; --i )
01353         {
01354             QChar ch = s->at( i ).c;
01355         // It's necessary to stop at spaces - #99063
01356             if ( ch.isSpace() /*|| ch.isPunct()*/ || i==0)
01357             {
01358                 if(i==0 && word.length()<m_maxFindLength)
01359                     word.prepend( ch );
01360                 wordArray[word.length()]=word;
01361             }
01362             word.prepend( ch );
01363             if (((index - 1)-i) == (int)m_maxFindLength)
01364                 break;
01365         }
01366 
01367     }
01368     KCommand *cmd = autoFormatWord( textEditCursor, parag, index, txtObj, wordArray, false );
01369     if ( !cmd )
01370         cmd = autoFormatWord( textEditCursor, parag, index, txtObj, wordArray, true );
01371     delete [] wordArray;
01372     return cmd;
01373 }
01374 
01375 
01376 KCommand *KoAutoFormat::autoFormatWord( KoTextCursor* textEditCursor, KoTextParag *parag, int &index, KoTextObject *txtObj, QString * _wordArray, bool _allLanguages )
01377 {
01378     KoTextDocument * textdoc = parag->textDocument();
01379 
01380     // Now for each entry in the autocorrect list, look if
01381     // the word of the same size in wordArray matches.
01382     // This allows an o(n) behaviour instead of an o(n^2).
01383     for(int i=m_maxFindLength;i>0;--i)
01384     {
01385         if ( !_wordArray[i].isEmpty())
01386         {
01387             KoAutoFormatEntry* it = 0L;
01388             if ( _allLanguages )
01389                 it = m_allLanguages[ _wordArray[i] ];
01390             else
01391                 it = m_entries[ _wordArray[i] ];
01392             if ( _wordArray[i]!=0  && it )
01393             {
01394                 unsigned int length = _wordArray[i].length();
01395                 int const start = index - length;
01396                 KoTextCursor cursor( parag->document() );
01397                 cursor.setParag( parag );
01398                 cursor.setIndex( start );
01399                 textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
01400                 cursor.setIndex( start + length );
01401                 textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
01402                 KCommand *cmd = 0L;
01403                 kdDebug()<<"it->replace() :"<<it->replace()<<endl;
01404                 if (!it->formatEntryContext() || !m_bAutoCorrectionWithFormat)
01405                 {
01406                     cmd = txtObj->replaceSelectionCommand( textEditCursor, it->replace(),
01407                                                            i18n("Autocorrect Word"),
01408                                                            KoTextDocument::HighlightSelection );
01409                 }
01410                 else
01411                 {
01412                     int flags = 0;
01413                     KoTextFormat * lastFormat = parag->at( start )->format();
01414                     KoTextFormat * newFormat = new KoTextFormat(*lastFormat);
01415                     changeTextFormat(it->formatEntryContext(), newFormat, flags );
01416                     KMacroCommand *macro = new KMacroCommand( i18n("Autocorrect Word with Format"));
01417                     KCommand *cmd2=txtObj->replaceSelectionCommand( textEditCursor, it->replace(),
01418                                                                     i18n("Autocorrect Word"),
01419                                                                     KoTextDocument::HighlightSelection );
01420                     if ( cmd2 )
01421                         macro->addCommand(cmd2);
01422                     KoTextCursor cursor( parag->document() );
01423                     cursor.setParag( parag );
01424                     cursor.setIndex( start );
01425                     textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
01426                     cursor.setIndex( start + it->replace().length()/*+ length + 1*/ );
01427                     textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
01428 
01429                     cmd2 =txtObj->setFormatCommand( textEditCursor, &lastFormat, newFormat, flags, false, KoTextDocument::HighlightSelection );
01430                     macro->addCommand( cmd2);
01431 
01432                     index = index - length + it->replace().length();
01433                     textEditCursor->setIndex(index+1);
01434                     cmd2 =txtObj->setFormatCommand( textEditCursor, &newFormat, lastFormat, 0 );
01435                     macro->addCommand( cmd2);
01436                     parag->at( index+1 )->setFormat(lastFormat);
01437 
01438                     cmd = macro;
01439                     txtObj->emitHideCursor();
01440                     textEditCursor->gotoRight();
01441                     txtObj->emitShowCursor();
01442 
01443                     return cmd;
01444                 }
01445                 // The space/tab/CR that we inserted is still there but delete/insert moved the cursor
01446                 // -> go right
01447 
01448                 txtObj->emitHideCursor();
01449                 textEditCursor->gotoRight();
01450                 txtObj->emitShowCursor();
01451                 index = index - length + it->replace().length();
01452                 return cmd;
01453             }
01454         }
01455     }
01456     return 0L;
01457 }
01458 
01459 KCommand *KoAutoFormat::doTypographicQuotes( KoTextCursor* textEditCursor, KoTextParag *parag, int index, KoTextObject *txtObj, bool doubleQuotes )
01460 {
01461     //kdDebug(32500) << "KoAutoFormat::doTypographicQuotes" << endl;
01462     KoTextDocument * textdoc = parag->textDocument();
01463     KoTextCursor cursor( parag->document() );
01464     cursor.setParag( parag );
01465     cursor.setIndex( index );
01466     textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
01467     cursor.setIndex( index + 1 );
01468     textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
01469 
01470     // Need to determine if we want a starting or ending quote.
01471     // we use a starting quote in three cases:
01472     //   1. if the previous character is a space
01473     //   2. if the previous character is some kind of opening punctuation (e.g., "(", "[", or "{")
01474     //      a. and the character before that is not an opening quote (so that we get quotations of single characters
01475     //         right)
01476     //  3. if the previous character is an opening quote (so that we get nested quotations right)
01477     //      a. and the character before that is not an opening quote (so that we get quotations of single characters
01478     //         right)
01479     //      b. and the previous quote of a different kind (so that we get empty quotations right)
01480     QString replacement;
01481     bool ending = true;
01482 
01483     if( index > 0 )
01484     {
01485     QChar::Category c1 = parag->at( index - 1 )->c.category();
01486 
01487     // case 1 and 2
01488     if ( c1 == QChar::Separator_Space || c1 == QChar::Separator_Line || c1 == QChar::Separator_Paragraph ||
01489         c1 == QChar::Punctuation_Open )
01490         ending = false;
01491 
01492     // case 3
01493     if ( c1 == QChar::Punctuation_InitialQuote )
01494     {
01495         QChar openingQuote;
01496 
01497         if( doubleQuotes )
01498         openingQuote = m_typographicDoubleQuotes.begin;
01499             else
01500         openingQuote = m_typographicSimpleQuotes.begin;
01501 
01502         // case 3b
01503         if( parag->at( index - 1 )->c != openingQuote )
01504         ending = false;
01505     }
01506     }
01507 
01508     // cases 2a and 3a
01509     if( index > 1 && !ending )
01510     {
01511     QChar::Category c2 = parag->at( index - 2 )->c.category();
01512     ending = (c2 == QChar::Punctuation_InitialQuote);
01513     }
01514 
01515     if( ending )
01516     {
01517         if( doubleQuotes )
01518             replacement = m_typographicDoubleQuotes.end;
01519         else
01520             replacement = m_typographicSimpleQuotes.end;
01521     }
01522     else
01523     {
01524         if( doubleQuotes )
01525             replacement = m_typographicDoubleQuotes.begin;
01526         else
01527             replacement = m_typographicSimpleQuotes.begin;
01528     }
01529     return txtObj->replaceSelectionCommand( textEditCursor, replacement,
01530                                             i18n("Typographic Quote"),
01531                                             KoTextDocument::HighlightSelection );
01532 }
01533 
01534 KCommand * KoAutoFormat::doUpperCase( KoTextCursor *textEditCursor, KoTextParag *parag,
01535                                 int index, const QString & word, KoTextObject *txtObj )
01536 {
01537     KoTextDocument * textdoc = parag->textDocument();
01538     unsigned int length = word.length();
01539     if (word.at(length-1) == '.' )
01540     {
01541         --index;
01542         --length;
01543     }
01544     int const start = index - length;
01545     KoTextCursor backCursor( parag->document() );
01546     backCursor.setParag( parag );
01547     backCursor.setIndex( start );
01548 
01549     // backCursor now points at the first char of the word
01550     QChar const firstChar = backCursor.parag()->at( backCursor.index() )->c;
01551 
01552     bool bNeedMove = false;
01553     KCommand *cmd = 0L;
01554     if ( m_convertUpperCase && isLower( firstChar ) )
01555     {
01556         bool beginningOfSentence = true; // true if beginning of text
01557         // Go back over any space/tab/CR
01558         while ( backCursor.index() > 0 || backCursor.parag()->prev() )
01559         {
01560             beginningOfSentence = false; // we could go back -> false unless we'll find '.'
01561             backCursor.gotoLeft();
01562             if ( !backCursor.parag()->at( backCursor.index() )->c.isSpace() )
01563                 break;
01564         }
01565         // We are now at the first non-space char before the word
01566         if ( !beginningOfSentence )
01567                 beginningOfSentence = isMark( backCursor.parag()->at( backCursor.index() )->c);
01568             //beginningOfSentence = isMark( backCursor.parag()->at( backCursor.index() )->c ) && (backCursor.parag()->at( backCursor.index()+1 )->c.isSpace());
01569         if ( !beginningOfSentence && start==0 )
01570             if ( parag->counter() || backCursor.parag()->at( backCursor.index() )->c.isPunct() )
01571                 beginningOfSentence = true;
01572 
01573         // Now look for exceptions
01574         if ( beginningOfSentence )
01575         {
01576             QChar const punct = backCursor.parag()->at( backCursor.index() )->c;
01577             QString const text = getLastWord( backCursor.parag(), backCursor.index() )
01578                            + punct;
01579                            kdDebug() << "text: " << text << endl;
01580             // text has the word at the end of the 'sentence', including the termination. Example: "Mr."
01581             beginningOfSentence = (m_upperCaseExceptions.findIndex(text)==-1); // Ok if we can't find it
01582         }
01583 
01584         if ( beginningOfSentence )
01585         {
01586             KoTextCursor cursor( parag->document() );
01587             cursor.setParag( parag );
01588             cursor.setIndex( start );
01589             textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
01590             cursor.setIndex( start + 1 );
01591             textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
01592             cmd = txtObj->replaceSelectionCommand( textEditCursor, QString( firstChar.upper() ),
01593                                                    i18n("Autocorrect (capitalize first letter)"),
01594                                                    KoTextDocument::HighlightSelection );
01595             bNeedMove = true;
01596         }
01597     }
01598     else if ( m_convertUpperUpper && isUpper( firstChar ) && length > 2 )
01599     {
01600         backCursor.setIndex( backCursor.index() + 1 );
01601         QChar secondChar = backCursor.parag()->at( backCursor.index() )->c;
01602         //kdDebug(32500)<<" secondChar :"<<secondChar<<endl;
01603         if ( isUpper( secondChar ) )
01604         {
01605             // Check next letter - we still want to be able to write fully uppercase words...
01606             backCursor.setIndex( backCursor.index() + 1 );
01607             QChar thirdChar = backCursor.parag()->at( backCursor.index() )->c;
01608             if ( isLower( thirdChar ) && (m_twoUpperLetterException.findIndex(word)==-1))
01609             {
01610                 // Ok, convert
01611                 KoTextCursor cursor( parag->document() );
01612                 cursor.setParag( parag );
01613                 cursor.setIndex( start + 1 ); // After all the first letter's fine, so only change the second letter
01614                 textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
01615                 cursor.setIndex( start + 2 );
01616                 textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
01617 
01618                 QString replacement = word[1].lower();
01619                 cmd = txtObj->replaceSelectionCommand( textEditCursor, replacement,
01620                                                        i18n("Autocorrect"),
01621                                                        KoTextDocument::HighlightSelection );
01622 
01623                 bNeedMove = true;
01624             }
01625         }
01626     }
01627     if ( bNeedMove )
01628     {
01629         if (word.at(word.length()-1) == '.' )
01630                 ++index;
01631         txtObj->emitHideCursor();
01632         textEditCursor->setParag( parag );
01633         textEditCursor->setIndex( index );
01634         textEditCursor->gotoRight(); // not the same thing as index+1, in case of CR
01635         txtObj->emitShowCursor();
01636     }
01637     return cmd;
01638 }
01639 
01640 KCommand * KoAutoFormat::doAutoReplaceNumber( KoTextCursor* textEditCursor, KoTextParag *parag, int& index, const QString & word , KoTextObject *txtObj )
01641 {
01642     unsigned int length = word.length();
01643     if ( length != 3 )
01644         return 0L;
01645     KoTextDocument * textdoc = parag->textDocument();
01646     int start = index - length;
01647     if( word == QString("1/2") || word == QString("1/4") || word == QString("3/4") )
01648     {
01649         KoTextCursor cursor( parag->document() );
01650         cursor.setParag( parag );
01651         cursor.setIndex( start );
01652         textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
01653         cursor.setIndex( start + length );
01654         textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
01655         QString replacement;
01656         if( word == QString("1/2") )
01657             replacement=QString("½");
01658         else if (word == QString("1/4") )
01659             replacement=QString("¼");
01660         else if (word == QString("3/4") )
01661             replacement=QString("¾");
01662         QString cmdName = i18n("Autocorrect for Fraction");
01663         KCommand *cmd =txtObj->replaceSelectionCommand( textEditCursor, replacement,
01664                                                         cmdName,
01665                                                         KoTextDocument::HighlightSelection );
01666         txtObj->emitHideCursor();
01667         textEditCursor->gotoRight();
01668         txtObj->emitShowCursor();
01669         index = index - length + replacement.length();
01670         return cmd;
01671     }
01672     return 0L;
01673 }
01674 
01675 void KoAutoFormat::detectStartOfLink(KoTextParag * parag, int const index, bool const insertedDot)
01676 {
01677     QString word;
01678     KoTextString *s = parag->string();
01679     for ( int i = 0; i < index; ++i )
01680     {
01681         word.append( s->at( i ).c );
01682     }
01683 
01684     if (word.find("http")!=-1 || word.find("https")!=-1 || word.find("mailto")!=-1 || word.find("ftp")!=-1 || word.find("file")!=-1
01685         || word.find("news")!=-1 || word.find('@')!=-1)
01686                 m_ignoreUpperCase=true;
01687     else
01688     {
01689         int const tmp_pos=word.find("www.");
01690         if (tmp_pos!=-1 && (word.find('.',tmp_pos+4)!=-1 || insertedDot) )
01691                m_ignoreUpperCase=true;
01692     }
01693 }
01694 
01695 void KoAutoFormat::doAutoDetectUrl( KoTextCursor *textEditCursor, KoTextParag *parag, int &index, QString & word, KoTextObject *txtObj )
01696 {
01697     kdDebug() << "link:" << word << endl;
01698     char link_type = 0;
01699     int pos = word.find("http://");
01700     int tmp_pos = word.find("https://");
01701     if(tmp_pos<pos && tmp_pos!=-1)
01702           pos = tmp_pos;
01703     tmp_pos = word.find("mailto:/");
01704     if((tmp_pos<pos || pos==-1 ) && tmp_pos!=-1)
01705           pos = tmp_pos;
01706     tmp_pos = word.find("ftp://");
01707     if((tmp_pos<pos || pos==-1 ) && tmp_pos!=-1)
01708           pos = tmp_pos;
01709     tmp_pos = word.find("ftp.");
01710     if((tmp_pos<pos || pos==-1 ) && tmp_pos!=-1)
01711     {
01712           pos = tmp_pos;
01713           link_type = 3;
01714     }
01715     tmp_pos = word.find("file:/");
01716     if((tmp_pos<pos || pos==-1 ) && tmp_pos!=-1)
01717           pos = tmp_pos;
01718     tmp_pos = word.find("news:");
01719     if((tmp_pos<pos || pos==-1 ) && tmp_pos!=-1)
01720           pos = tmp_pos;
01721     tmp_pos = word.find("www.");
01722     if((tmp_pos<pos || pos==-1 ) && tmp_pos!=-1 && word.find('.',tmp_pos+4)!=-1 )
01723     {
01724           pos = tmp_pos;
01725           link_type = 2;
01726     }
01727     tmp_pos = word.find('@');
01728     if ( pos == -1 && tmp_pos != -1 )
01729     {
01730           pos = tmp_pos-1;
01731           QChar c;
01732           while( pos>=0 )
01733           {
01734                 c = word.at(pos);
01735                 if ( c.isPunct() && c!='.'&& c!='_')    break;
01736                 else    --pos;
01737           }
01738           if ( pos == tmp_pos-1 ) //it not a valid address
01739           {
01740                 m_ignoreUpperCase = false;
01741                 pos = -1;
01742           }
01743           else
01744                 ++pos;
01745           link_type = 1;
01746     }
01747     if(pos!=-1)
01748     {
01749         // A URL inside e.g. quotes (like "http://www.koffice.org" with the quotes) shouldn't include the quote in the URL.
01750     while ( !word.at(word.length()-1).isLetter() &&  !word.at(word.length()-1).isDigit() && word.at(word.length()-1)!='/')
01751         {
01752                 word.truncate(word.length()-1);
01753                 --index;
01754         }
01755         word.remove(0,pos);
01756         unsigned int const length = word.length();
01757         int const start = index - length;
01758         KoTextCursor cursor( parag->document() );
01759         KoTextDocument * textdoc = parag->textDocument();
01760         cursor.setParag( parag );
01761         cursor.setIndex( start );
01762         textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
01763         cursor.setIndex( start + length );
01764         textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
01765         QString newWord = word;
01766         if(link_type==1)
01767             newWord = QString("mailto:") + word;
01768         else if(link_type==2)
01769             newWord = QString("http://") + word;
01770         else if(link_type==3)
01771             newWord = QString("ftp://") + word;
01772 
01773         KoVariable* var = new KoLinkVariable( textdoc, word, newWord, m_varFormatCollection->format( "STRING" ), m_varCollection );
01774         CustomItemsMap customItemsMap;
01775         customItemsMap.insert( 0, var );
01776         KoTextFormat * lastFormat = parag->at( start )->format();
01777         int origCursorIndex = textEditCursor->index();
01778         txtObj->insert( textEditCursor, lastFormat, KoTextObject::customItemChar(), i18n("Insert Variable"),
01779                         KoTextDocument::HighlightSelection, KoTextObject::DefaultInsertFlags, customItemsMap );
01780         var->recalc();
01781         parag->invalidate(0);
01782         parag->setChanged( true );
01783 
01784         // adjust index
01785         index -= length-1; // we removed length chars and inserted one instead
01786 
01787         txtObj->emitHideCursor();
01788         textEditCursor->setIndex( origCursorIndex - (length-1) );
01789         txtObj->emitShowCursor();
01790 
01791         // ###### TODO: Move to a common method, this code is duplicated...
01792         if ( m_completion && m_addCompletionWord && m_listCompletion->items().count() < m_nbMaxCompletionWord )
01793         {
01794             if (word.length()>= m_minCompletionWordLength  && !word.isEmpty() && m_listCompletion->makeCompletion(word).isEmpty())
01795             {
01796                 kdDebug() << "Adding:" << word << endl;
01797                 m_listCompletion->addItem( word );
01798                 if ( word.length() > m_countMaxWords )
01799                     m_countMaxWords = word.length();
01800             }
01801         }
01802     }
01803 }
01804 
01805 void KoAutoFormat::doAutoIncludeUpperUpper(KoTextCursor* /*textEditCursor*/, KoTextParag *parag, KoTextObject* /*txtObj*/ )
01806 {
01807     KoTextString *s = parag->string();
01808 
01809     if( s->length() < 2 )
01810         return;
01811 
01812     for (int i=0; i<=(s->length() - 1);i++)
01813     {
01814         QString word;
01815         for ( int j = i ; j < s->length() - 1; j++ )
01816         {
01817             QChar ch = s->at( j ).c;
01818             if ( ch.isSpace() )
01819                 break;
01820             word.append( ch );
01821         }
01822         if( word.length() > 2 && word.left(2)==word.left(2).upper() && word.at(3)!=word.at(3).upper() )
01823         {
01824             if ( m_twoUpperLetterException.findIndex(word )==-1)
01825                 m_twoUpperLetterException.append( word);
01826         }
01827         i+=word.length();
01828     }
01829 
01830 }
01831 
01832 
01833 void KoAutoFormat::doAutoIncludeAbbreviation(KoTextCursor* /*textEditCursor*/, KoTextParag *parag, KoTextObject* /*txtObj*/ )
01834 {
01835     KoTextString *s = parag->string();
01836     if( s->length() < 2 )
01837         return;
01838     for (int i=0; i<=(s->length() - 1);i++)
01839     {
01840         QString wordAfter;
01841         QString word;
01842 
01843         for ( int j = i ; j < s->length() - 1; j++ )
01844         {
01845             QChar ch = s->at( j ).c;
01846             if ( ch.isSpace() )
01847                 break;
01848             word.append( ch );
01849         }
01850         if ( isMark( word.at(word.length()-1)) )
01851         {
01852             for ( int j = i+word.length()+1 ; j < s->length() - 1; j++ )
01853             {
01854                 QChar ch = s->at( j ).c;
01855                 if ( ch.isSpace() )
01856                     break;
01857                 wordAfter.append( ch );
01858             }
01859             if( word.length()>1 && !wordAfter.isEmpty() && wordAfter.at(0)==wordAfter.at(0).lower())
01860             {
01861                 if ( m_upperCaseExceptions.findIndex(word )==-1)
01862                     m_upperCaseExceptions.append( word );
01863             }
01864         }
01865         i+=word.length();
01866         if( !wordAfter.isEmpty())
01867         {
01868             i+=wordAfter.length()+1;
01869         }
01870     }
01871 
01872 }
01873 
01874 
01875 KCommand * KoAutoFormat::doAutoChangeFormat( KoTextCursor *textEditCursor, KoTextParag *parag,int index, const QString & word, KoTextObject *txtObj )
01876 {
01877     bool underline = (word.at(0)=='_' && word.at(word.length()-1)=='_');
01878     bool bold = (word.at(0)=='*' && word.at(word.length()-1)=='*');
01879     if( bold || underline)
01880     {
01881         QString replacement=word.mid(1,word.length()-2);
01882         int start = index - word.length();
01883         KoTextDocument * textdoc = parag->textDocument();
01884         KMacroCommand *macro=new KMacroCommand(i18n("Autocorrection: Change Format"));
01885         KoTextCursor cursor( parag->document() );
01886 
01887         cursor.setParag( parag );
01888         cursor.setIndex( start );
01889         textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
01890         cursor.setIndex( start + word.length() );
01891         textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
01892         macro->addCommand(txtObj->replaceSelectionCommand( textEditCursor, replacement,
01893                                                            i18n("Autocorrect Word"),
01894                                                            KoTextDocument::HighlightSelection));
01895 
01896         KoTextFormat * lastFormat = parag->at( start )->format();
01897         KoTextFormat * newFormat = new KoTextFormat(*lastFormat);
01898         cursor.setIndex( start );
01899         textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
01900         cursor.setIndex( start + word.length()-2 );
01901         textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
01902 
01903         if( bold)
01904         {
01905             newFormat->setBold(true);
01906             macro->addCommand(txtObj->setFormatCommand( textEditCursor, 0L, newFormat, KoTextFormat::Bold , false,KoTextDocument::HighlightSelection  ));
01907         }
01908         else if( underline )
01909         {
01910             newFormat->setUnderline(true);
01911             macro->addCommand(txtObj->setFormatCommand( textEditCursor, 0L, newFormat, KoTextFormat::Underline , false,KoTextDocument::HighlightSelection  ));
01912         }
01913         txtObj->emitHideCursor();
01914         textEditCursor->gotoRight();
01915         txtObj->emitShowCursor();
01916         return macro;
01917     }
01918     return 0L;
01919 }
01920 
01921 KCommand *KoAutoFormat::doUseBulletStyle(KoTextCursor * /*textEditCursor*/, KoTextParag *parag, KoTextObject *txtObj, int& index )
01922 {
01923     KoTextDocument * textdoc = parag->textDocument();
01924     KoTextCursor cursor( parag->document() );
01925     KoTextString *s = parag->string();
01926     QChar ch = s->at( 0 ).c;
01927 
01928     if( m_useBulletStyle && (ch =='*' || ch == '-' || ch =='+') && (s->at(1).c).isSpace())
01929     {
01930         if ( parag->counter() && parag->counter()->numbering() == KoParagCounter::NUM_FOOTNOTE )
01931             return 0L;
01932         KMacroCommand *macroCmd = new KMacroCommand( i18n("Autocorrect (use bullet style)"));
01933         cursor.setParag( parag );
01934         cursor.setIndex( 0 );
01935         textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
01936         cursor.setParag( parag );
01937         cursor.setIndex( 2 );
01938         textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
01939         KCommand *cmd=txtObj->removeSelectedTextCommand( &cursor, KoTextDocument::HighlightSelection  );
01940         // Adjust index
01941         index -= 2;
01942         if(cmd)
01943             macroCmd->addCommand(cmd);
01944 
01945         cursor.setParag( parag );
01946         cursor.setIndex( 0 );
01947         textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
01948 
01949         cursor.setIndex( 2 );
01950         textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
01951 
01952 
01953         KoParagCounter c;
01954         if( m_bulletStyle.isNull() && (ch == '*' || ch == '+' || ch == '-'))
01955         {
01956             if ( ch =='*')
01957             {
01958                 c.setNumbering( KoParagCounter::NUM_LIST );
01959                 c.setStyle( KoParagCounter::STYLE_DISCBULLET );
01960             }
01961             else if ( ch =='+' || ch=='-')
01962             {
01963                 c.setNumbering( KoParagCounter::NUM_LIST );
01964                 c.setStyle( KoParagCounter::STYLE_CUSTOMBULLET );
01965                 if ( ch =='-' )
01966                     c.setCustomBulletCharacter( '-' );
01967                 else if ( ch=='+')
01968                     c.setCustomBulletCharacter( '+' );
01969             }
01970         }
01971         else
01972         {
01973             c.setNumbering( KoParagCounter::NUM_LIST );
01974             c.setStyle( KoParagCounter::STYLE_CUSTOMBULLET );
01975             c.setCustomBulletCharacter( m_bulletStyle );
01976         }
01977         c.setSuffix(QString::null);
01978         cmd=txtObj->setCounterCommand( &cursor, c ,KoTextDocument::HighlightSelection );
01979         if( cmd)
01980             macroCmd->addCommand(cmd);
01981         if (parag->next() )
01982                 cursor.setParag( parag->next() );
01983         else
01984               return 0L;
01985 
01986         cursor.setIndex( 0 );
01987         textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
01988         cursor.setIndex( 0 );
01989         textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
01990         cmd=txtObj->setCounterCommand( &cursor, c ,KoTextDocument::HighlightSelection );
01991         if(cmd)
01992             macroCmd->addCommand(cmd);
01993         return macroCmd;
01994     }
01995     return 0L;
01996 
01997 }
01998 
01999 KCommand *KoAutoFormat::doUseNumberStyle(KoTextCursor * /*textEditCursor*/, KoTextParag *parag, KoTextObject *txtObj, int& index )
02000 {
02001     if ( parag->counter() && parag->counter()->numbering() == KoParagCounter::NUM_FOOTNOTE )
02002         return 0L;
02003     KoTextDocument * textdoc = parag->textDocument();
02004     KoTextCursor cursor( parag->document() );
02005     KoTextString *s = parag->string();
02006     QString word;
02007     for ( int i = 0 ; i < s->length() - 1; i++ )
02008     {
02009         QChar ch = s->at( i ).c;
02010         if ( ch.isSpace() )
02011             break;
02012         word.append( ch );
02013     }
02014     QChar punct=word[word.length()-1];
02015     if( punct.isPunct() )
02016     {
02017         QString number=word.mid(0,word.length()-1);
02018         bool ok;
02019         uint val=number.toUInt(&ok);
02020         if( ok )
02021         {
02022             KMacroCommand *macroCmd = new KMacroCommand( i18n("Autocorrect (use number style)"));
02023             cursor.setParag( parag );
02024             cursor.setIndex( 0 );
02025             textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
02026             cursor.setParag( parag );
02027             cursor.setIndex( word.length()+1 );
02028             textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
02029             KCommand *cmd=txtObj->removeSelectedTextCommand( &cursor, KoTextDocument::HighlightSelection  );
02030             // Adjust index
02031             index -= word.length()+1;
02032             if(cmd)
02033                 macroCmd->addCommand(cmd);
02034 
02035             // Apply counter to this paragraph
02036             cursor.setParag( parag );
02037             cursor.setIndex( 0 );
02038             textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
02039 
02040             cursor.setIndex( 2 );
02041             textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
02042 
02043             KoParagCounter c;
02044             c.setNumbering( KoParagCounter::NUM_LIST );
02045             c.setStyle( KoParagCounter::STYLE_NUM );
02046             c.setSuffix(QString( punct ));
02047             c.setStartNumber( (int)val);
02048 
02049             // Look at which number this parag will have without a restart counter flag,
02050             // to see if we need it. Thanks to Shaheed for number() taking a parag as param,
02051             // so that it works even if the parag doesn't have this counter yet!
02052             if ( c.number( parag ) != (int)val )
02053                 c.setRestartCounter( true );
02054 
02055             cmd=txtObj->setCounterCommand( &cursor, c, KoTextDocument::HighlightSelection );
02056             if( cmd)
02057                 macroCmd->addCommand(cmd);
02058             // Apply counter to next paragraph too
02059             // but without restart
02060             c.setRestartCounter( false );
02061             cursor.setParag( parag->next() );
02062             cursor.setIndex( 0 );
02063             textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
02064             cursor.setIndex( 0 );
02065             textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
02066             cmd=txtObj->setCounterCommand( &cursor, c, KoTextDocument::HighlightSelection );
02067             if(cmd)
02068                 macroCmd->addCommand(cmd);
02069             return macroCmd;
02070         }
02071     }
02072     return 0L;
02073 }
02074 
02075 
02076 KCommand * KoAutoFormat::doRemoveSpaceBeginEndLine( KoTextCursor *textEditCursor, KoTextParag *parag, KoTextObject *txtObj, int &index )
02077 {
02078     KoTextString *s = parag->string();
02079     KoTextDocument * textdoc = parag->textDocument();
02080     KoTextCursor cursor( parag->document() );
02081 
02082     KMacroCommand *macroCmd = 0L;
02083     // Cut away spaces at end of paragraph
02084     for ( int i = parag->lastCharPos(); i >= 0; --i )
02085     {
02086         QChar ch = s->at( i ).c;
02087         if ( ch != ' ' )   // was: !ch.isSpace(), but this includes tabs, and this option is only about spaces
02088         {
02089             if( i == parag->lastCharPos() )
02090                 break;
02091             cursor.setParag( parag );
02092             cursor.setIndex( i+1 );
02093             textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
02094             cursor.setParag( parag );
02095             cursor.setIndex( parag->lastCharPos()+1 );
02096             textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
02097             KCommand *cmd=txtObj->replaceSelectionCommand( &cursor, "", QString::null, KoTextDocument::HighlightSelection );
02098 
02099             if(cmd)
02100             {
02101                 if ( index > i )
02102                     index = i;
02103                 if ( !macroCmd )
02104                     macroCmd = new KMacroCommand( i18n("Autocorrect (remove start and end line space)"));
02105                 macroCmd->addCommand(cmd);
02106             }
02107             break;
02108         }
02109     }
02110 
02111     // Cut away spaces at start of parag.
02112 
02113     for ( int i = 0 ; i <= parag->lastCharPos() ; i++ )
02114     {
02115         QChar ch = s->at( i ).c;
02116         if ( ch != ' ' )   // was: !ch.isSpace(), but this includes tabs, and this option is only about spaces
02117         {
02118             if( i == 0 )
02119                 break;
02120 
02121             cursor.setParag( parag );
02122             cursor.setIndex( 0 );
02123             textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
02124             cursor.setParag( parag );
02125             cursor.setIndex( i );
02126             textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
02127             KCommand *cmd=txtObj->replaceSelectionCommand( &cursor, "", QString::null, KoTextDocument::HighlightSelection );
02128 
02129             if(cmd)
02130             {
02131                 index -= i; // adjust index
02132                 if ( !macroCmd )
02133                     macroCmd = new KMacroCommand( i18n("Autocorrect (remove start and end line space)"));
02134                 macroCmd->addCommand(cmd);
02135             }
02136             break;
02137         }
02138     }
02139 
02140     if( macroCmd )
02141     {
02142         txtObj->emitHideCursor();
02143         textEditCursor->setParag( parag->next() );
02144         //textEditCursor->cursorgotoRight();
02145         txtObj->emitShowCursor();
02146     }
02147     return macroCmd;
02148 }
02149 
02150 KCommand *KoAutoFormat::doCapitalizeNameOfDays( KoTextCursor* textEditCursor, KoTextParag *parag, int index, const QString & word , KoTextObject *txtObj )
02151 {
02152     //m_cacheNameOfDays
02153     //todo
02154     int pos = m_cacheNameOfDays.findIndex( word.lower() );
02155     if ( pos == -1 )
02156         return 0L;
02157     KoTextDocument * textdoc = parag->textDocument();
02158     QString replaceStr= m_cacheNameOfDays[pos];
02159     int start = index - replaceStr.length();
02160     int length = replaceStr.length();
02161     if( word.at(0).isLetter() && word.at(0)==word.at(0).lower() )
02162     {
02163         KoTextCursor cursor( parag->document() );
02164         cursor.setParag( parag );
02165         cursor.setIndex( start );
02166         textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
02167         cursor.setIndex( start + length );
02168         QString replacement = replaceStr.at(0).upper() + replaceStr.right( length-1 );
02169         textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
02170         QString cmdName=i18n("Capitalize Name of Days");
02171         KCommand *cmd =txtObj->replaceSelectionCommand( textEditCursor, replacement,
02172                                                         cmdName,
02173                                                         KoTextDocument::HighlightSelection );
02174         txtObj->emitHideCursor();
02175         textEditCursor->gotoRight();
02176         txtObj->emitShowCursor();
02177         return cmd;
02178     }
02179     return 0L;
02180 }
02181 
02182 KCommand *KoAutoFormat::doAutoSuperScript( KoTextCursor* textEditCursor, KoTextParag *parag, int index, const QString & word , KoTextObject *txtObj )
02183 {
02184     KoAutoFormatEntryMap::Iterator it = m_superScriptEntries.begin();
02185     bool found = false;
02186     QString replace;
02187     for ( ; it != m_superScriptEntries.end() ; ++it )
02188     {
02189         if( it.key()==word)
02190         {
02191             replace = it.data().replace();
02192             found = true;
02193             break;
02194         }
02195         else if ( it.key()=="othernb")
02196         {
02197             QString tmp = it.data().replace();
02198             int pos = word.find( tmp );
02199             if( pos != -1)
02200             {
02201                 if( pos + tmp.length() == word.length())
02202                 {
02203                     bool ok;
02204                     word.left( pos ).toInt( &ok);
02205                     if( ok )
02206                     {
02207                         replace = tmp;
02208                         found = true;
02209                         break;
02210                     }
02211                 }
02212             }
02213         }
02214     }
02215     if (found )
02216     {
02217         KoTextDocument * textdoc = parag->textDocument();
02218 
02219         int start = index - replace.length();
02220         KoTextFormat * lastFormat = parag->at( start )->format();
02221         KoTextFormat * newFormat = new KoTextFormat(*lastFormat);
02222         KoTextCursor cursor( parag->document() );
02223 
02224         cursor.setParag( parag );
02225         cursor.setIndex( start );
02226         textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
02227         cursor.setIndex( start + word.length() -1 );
02228         textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
02229         newFormat->setVAlign(KoTextFormat::AlignSuperScript);
02230         KCommand *cmd =txtObj->setFormatCommand( textEditCursor, 0L, newFormat, KoTextFormat::VAlign , false,KoTextDocument::HighlightSelection  );
02231         textdoc->removeSelection( KoTextDocument::HighlightSelection );
02232 
02233         return cmd;
02234     }
02235     return 0L;
02236 }
02237 
02238 bool KoAutoFormat::doIgnoreDoubleSpace( KoTextParag *parag, int index, QChar ch )
02239 {
02240     if( m_ignoreDoubleSpace && ch==' ' && index >=  0 && !parag->hasAnySelection() )
02241     {
02242         KoTextString *s = parag->string();
02243         QChar ch = s->at( index ).c;
02244         if ( ch==' ' )
02245           return true;
02246     }
02247     return false;
02248 }
02249 
02250 void KoAutoFormat::configTypographicSimpleQuotes( TypographicQuotes _tq )
02251 {
02252     m_typographicSimpleQuotes = _tq;
02253 }
02254 
02255 void KoAutoFormat::configTypographicDoubleQuotes( TypographicQuotes _tq )
02256 {
02257     m_typographicDoubleQuotes = _tq;
02258 }
02259 
02260 void KoAutoFormat::configUpperCase( bool _uc )
02261 {
02262     m_convertUpperCase = _uc;
02263 }
02264 
02265 void KoAutoFormat::configUpperUpper( bool _uu )
02266 {
02267     m_convertUpperUpper = _uu;
02268 }
02269 
02270 void KoAutoFormat::configAdvancedAutocorrect( bool _aa )
02271 {
02272     m_advancedAutoCorrect = _aa;
02273 }
02274 
02275 void KoAutoFormat::configAutoDetectUrl(bool _au)
02276 {
02277     m_autoDetectUrl=_au;
02278 }
02279 
02280 void KoAutoFormat::configIgnoreDoubleSpace( bool _ids)
02281 {
02282     m_ignoreDoubleSpace=_ids;
02283 }
02284 
02285 void KoAutoFormat::configRemoveSpaceBeginEndLine( bool _space)
02286 {
02287     m_removeSpaceBeginEndLine=_space;
02288 }
02289 
02290 void KoAutoFormat::configUseBulletStyle( bool _ubs)
02291 {
02292     m_useBulletStyle=_ubs;
02293 }
02294 
02295 void KoAutoFormat::configBulletStyle( QChar b )
02296 {
02297     m_bulletStyle = b;
02298 }
02299 
02300 void KoAutoFormat::configAutoChangeFormat( bool b)
02301 {
02302     m_autoChangeFormat = b;
02303 }
02304 
02305 
02306 void KoAutoFormat::configAutoReplaceNumber( bool b )
02307 {
02308     m_autoReplaceNumber = b;
02309 }
02310 
02311 void KoAutoFormat::configAutoNumberStyle( bool b )
02312 {
02313     m_useAutoNumberStyle = b;
02314 }
02315 
02316 void KoAutoFormat::configCompletion( bool b )
02317 {
02318     m_completion = b;
02319 }
02320 
02321 void KoAutoFormat::configToolTipCompletion( bool b )
02322 {
02323     m_toolTipCompletion = b;
02324     if (!b && m_completionBox)
02325     {
02326         delete m_completionBox;
02327         m_completionBox = 0;
02328     }
02329 }
02330 
02331 void KoAutoFormat::configKeyCompletionAction( KeyCompletionAction action )
02332 {
02333     m_keyCompletionAction = action;
02334 }
02335 
02336 void KoAutoFormat::configAppendSpace( bool b)
02337 {
02338     m_completionAppendSpace= b;
02339 }
02340 
02341 void KoAutoFormat::configMinWordLength( uint val )
02342 {
02343    m_minCompletionWordLength = val;
02344 }
02345 
02346 void KoAutoFormat::configNbMaxCompletionWord( uint val )
02347 {
02348     m_nbMaxCompletionWord = val;
02349 }
02350 
02351 
02352 void KoAutoFormat::configAddCompletionWord( bool b )
02353 {
02354     m_addCompletionWord= b;
02355 }
02356 
02357 bool KoAutoFormat::isUpper( const QChar &c )
02358 {
02359     return c.lower() != c;
02360 }
02361 
02362 bool KoAutoFormat::isLower( const QChar &c )
02363 {
02364     // Note that this is not the same as !isUpper !
02365     // For instance '1' is not lower nor upper,
02366     return c.upper() != c;
02367 }
02368 
02369 bool KoAutoFormat::isMark( const QChar &c )
02370 {
02371     return ( c == QChar( '.' ) ||
02372          c == QChar( '?' ) ||
02373          c == QChar( '!' ) );
02374 }
02375 
02376 bool KoAutoFormat::isSeparator( const QChar &c )
02377 {
02378     return ( !c.isLetter() && !c.isNumber() && !c.isDigit() );
02379 }
02380 
02381 void KoAutoFormat::buildMaxLen()
02382 {
02383     m_maxFindLength = 0;
02384     QDictIterator<KoAutoFormatEntry> it( m_entries );
02385     for( ; it.current(); ++it )
02386     {
02387     m_maxFindLength = QMAX( m_maxFindLength, it.currentKey().length() );
02388     }
02389     QDictIterator<KoAutoFormatEntry> it2( m_allLanguages );
02390     for( ; it2.current(); ++it2 )
02391     {
02392     m_maxFindLength = QMAX( m_maxFindLength, it2.currentKey().length() );
02393     }
02394 }
02395 
02396 QStringList KoAutoFormat::listCompletion() const
02397 {
02398    return m_listCompletion->items();
02399 }
02400 
02401 
02402 void KoAutoFormat::configIncludeTwoUpperUpperLetterException( bool b)
02403 {
02404     m_includeTwoUpperLetterException = b;
02405 }
02406 
02407 void KoAutoFormat::configIncludeAbbreviation( bool b )
02408 {
02409     m_includeAbbreviation = b;
02410 }
02411 
02412 void KoAutoFormat::configAutoSuperScript( bool b )
02413 {
02414     m_bAutoSuperScript = b;
02415 }
02416 
02417 void KoAutoFormat::configCorrectionWithFormat( bool b)
02418 {
02419     m_bAutoCorrectionWithFormat = b;
02420 }
02421 
02422 void KoAutoFormat::configCapitalizeNameOfDays( bool b)
02423 {
02424     m_bCapitalizeNameOfDays = b;
02425 }
02426 
02427 void KoAutoFormat::configAutoFormatLanguage( const QString &_lang)
02428 {
02429     m_autoFormatLanguage=_lang;
02430 }
02431 
02432 KCommand *KoAutoFormat::applyAutoFormat( KoTextObject * obj )
02433 {
02434   KoTextParag * parag = obj->textDocument()->firstParag();
02435   KoTextCursor *cursor = new KoTextCursor( obj->textDocument() );
02436   KMacroCommand *macro = 0L;
02437   while ( parag )
02438   {
02439     cursor->setIndex(0);
02440     for (int i=0;i<parag->length();i++)
02441     {
02442       cursor->gotoRight();
02443       //kdDebug() << "ch:" << parag->string()->at(i).c << endl;
02444       if (i == parag->length()-1)
02445     doAutoFormat(cursor,parag,i,'\n',obj);
02446       else
02447     doAutoFormat(cursor,parag,i, parag->string()->at(i).c,obj);
02448     }
02449     parag = parag->next();
02450 
02451   }
02452   delete cursor;
02453   return macro;
02454 }
02455 
02456 void KoAutoFormat::changeTextFormat(KoSearchContext *formatOptions, KoTextFormat * format, int & flags )
02457 {
02458     if (formatOptions )
02459     {
02460         if (formatOptions->m_optionsMask & KoSearchContext::Bold)
02461         {
02462             format->setBold( formatOptions->m_options & KoSearchContext::Bold);
02463             flags |=KoTextFormat::Bold;
02464         }
02465         if ( formatOptions->m_optionsMask & KoSearchContext::Size)
02466         {
02467             format->setPointSize( formatOptions->m_size );
02468             flags |=KoTextFormat::Size;
02469         }
02470         if ( formatOptions->m_optionsMask & KoSearchContext::Family)
02471         {
02472             format->setFamily( formatOptions->m_family );
02473             flags |=KoTextFormat::Family;
02474         }
02475         if ( formatOptions->m_optionsMask & KoSearchContext::Color)
02476         {
02477             format->setColor(formatOptions->m_color);
02478             flags |=KoTextFormat::Color;
02479         }
02480         if ( formatOptions->m_optionsMask & KoSearchContext::BgColor)
02481         {
02482             format->setTextBackgroundColor(formatOptions->m_backGroundColor);
02483             flags |=KoTextFormat::TextBackgroundColor;
02484         }
02485 
02486         if ( formatOptions->m_optionsMask & KoSearchContext::Italic)
02487         {
02488             format->setItalic( formatOptions->m_options & KoSearchContext::Italic);
02489             flags |=KoTextFormat::Italic;
02490         }
02491         if ( formatOptions->m_optionsMask & KoSearchContext::WordByWord)
02492         {
02493             format->setWordByWord( formatOptions->m_options & KoSearchContext::WordByWord );
02494             flags |=KoTextFormat::WordByWord;
02495         }
02496         if ( formatOptions->m_optionsMask & KoSearchContext::Shadow)
02497         {
02498             if ( formatOptions->m_options & KoSearchContext::Shadow )
02499                 format->setShadow( 1, 1, Qt::gray );
02500             else
02501                 format->setShadow( 0, 0, QColor() );
02502             flags |=KoTextFormat::ShadowText;
02503         }
02504 
02505         if ( formatOptions->m_optionsMask & KoSearchContext::Underline)
02506         {
02507             format->setUnderlineType(formatOptions->m_underline);
02508             flags |=KoTextFormat::ExtendUnderLine;
02509         }
02510         if ( formatOptions->m_optionsMask & KoSearchContext::StrikeOut)
02511         {
02512             format->setStrikeOutType(formatOptions->m_strikeOut);
02513             flags |= KoTextFormat::StrikeOut;
02514         }
02515         if ( formatOptions->m_optionsMask & KoSearchContext::VertAlign)
02516         {
02517             format->setVAlign(formatOptions->m_vertAlign);
02518             flags |=KoTextFormat::VAlign;
02519         }
02520         if ( formatOptions->m_optionsMask & KoSearchContext::Attribute)
02521         {
02522             format->setAttributeFont(formatOptions->m_attribute);
02523             flags |= KoTextFormat::Attribute;
02524         }
02525         if (formatOptions->m_optionsMask & KoSearchContext::Language)
02526         {
02527             flags |= KoTextFormat::Language;
02528             format->setLanguage( formatOptions->m_language );
02529         }
02530     }
02531 }
02532 
02533 #include "KoAutoFormat.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys