lib Library API Documentation

koAutoFormat.cc

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., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.
00019 */
00020 
00021 #include "koAutoFormat.h"
00022 //#include "kotextdocument.h"
00023 
00024 #include <kdebug.h>
00025 #include <klocale.h>
00026 #include <kinstance.h>
00027 #include <kconfig.h>
00028 #include <kstandarddirs.h>
00029 
00030 #include <qfile.h>
00031 
00032 #include <kotextobject.h>
00033 #include <qdom.h>
00034 #include <kglobal.h>
00035 #include <koDocument.h>
00036 #include "kovariable.h"
00037 #include "koparagcounter.h"
00038 #include <kcommand.h>
00039 //#include <kotextformat.h>
00040 #include <kcompletion.h>
00041 #include <koSearchDia.h>
00042 #include <kozoomhandler.h>
00043 #include <koGlobal.h>
00044 
00045 KoAutoFormatEntry::KoAutoFormatEntry(const QString& replace)
00046     : m_replace( replace )
00047 {
00048     m_formatOptions= 0L;
00049 }
00050 
00051 KoAutoFormatEntry::~KoAutoFormatEntry()
00052 {
00053     delete m_formatOptions;
00054     m_formatOptions=0L;
00055 }
00056 
00057 KoSearchContext *KoAutoFormatEntry::formatEntryContext() const
00058 {
00059     return m_formatOptions;
00060 }
00061 
00062 void KoAutoFormatEntry::createNewEntryContext()
00063 {
00064     if ( !m_formatOptions )
00065     {
00066         m_formatOptions = new KoSearchContext();
00067     }
00068 }
00069 
00070 void KoAutoFormatEntry::setFormatEntryContext( KoSearchContext *_cont )
00071 {
00072     delete m_formatOptions;
00073     m_formatOptions=_cont;
00074 }
00075 
00076 void KoAutoFormatEntry::clearFormatEntryContext( )
00077 {
00078     delete m_formatOptions;
00079     m_formatOptions = 0L;
00080 }
00081 
00082 
00083 /******************************************************************/
00084 /* Class: KoAutoFormat                        */
00085 /******************************************************************/
00086 KoAutoFormat::KoAutoFormat( KoDocument *_doc, KoVariableCollection *_varCollection, KoVariableFormatCollection *_varFormatCollection )
00087     : m_doc( _doc ),
00088       m_varCollection(_varCollection),
00089       m_varFormatCollection(_varFormatCollection),
00090       m_autoFormatLanguage( QString::null),
00091       m_configRead( false ),
00092       m_convertUpperCase( false ), m_convertUpperUpper( false ),
00093       m_advancedAutoCorrect( true ),
00094       m_autoDetectUrl( false ),
00095       m_ignoreDoubleSpace( false ),
00096       m_removeSpaceBeginEndLine( false ),
00097       m_useBulletStyle(false),
00098       m_autoChangeFormat(false),
00099       m_autoReplaceNumber(false),
00100       m_useAutoNumberStyle(false),
00101       m_completion(false),
00102       m_completionAppendSpace(false),
00103       m_addCompletionWord(true),
00104       m_includeTwoUpperLetterException(false),
00105       m_includeAbbreviation(false),
00106       m_ignoreUpperCase(false),
00107       m_bAutoFormatActive(true),
00108       m_bAutoSuperScript( false ),
00109       m_bAutoCorrectionWithFormat( false ),
00110       m_bCapitalizeNameOfDays( false ),
00111       m_bulletStyle(),
00112       m_typographicSimpleQuotes(),
00113       m_typographicDoubleQuotes(),
00114       m_typographicDefaultDoubleQuotes(),
00115       m_typographicDefaultSimpleQuotes(),
00116       m_listCompletion( new KCompletion ),
00117       m_entries(),
00118       m_superScriptEntries(),
00119       m_upperCaseExceptions(),
00120       m_twoUpperLetterException(),
00121       m_maxFindLength( 0 ),
00122       m_minCompletionWordLength( 5 ),
00123       m_nbMaxCompletionWord( 500 )
00124 {
00125     //load once this list not each time that we "readConfig"
00126     loadListOfWordCompletion();
00127     m_listCompletion->setIgnoreCase( true );
00128     KLocale klocale(m_doc->instance()->instanceName());
00129     for (int i = 0; i <7; i++)
00130         m_cacheNameOfDays.append(klocale.weekDayName( i ).lower());
00131 }
00132 
00133 KoAutoFormat::KoAutoFormat( const KoAutoFormat& format )
00134     : m_doc( format.m_doc ),
00135       m_varCollection( format.m_varCollection ),
00136       m_varFormatCollection( format.m_varFormatCollection ),
00137       m_autoFormatLanguage( format.m_autoFormatLanguage),
00138       m_configRead( format.m_configRead ),
00139       m_convertUpperCase( format.m_convertUpperCase ),
00140       m_convertUpperUpper( format.m_convertUpperUpper ),
00141       m_advancedAutoCorrect( format.m_advancedAutoCorrect ),
00142       m_autoDetectUrl( format.m_autoDetectUrl ),
00143       m_ignoreDoubleSpace( format.m_ignoreDoubleSpace ),
00144       m_removeSpaceBeginEndLine( format.m_removeSpaceBeginEndLine ),
00145       m_useBulletStyle( format.m_useBulletStyle ),
00146       m_autoChangeFormat( format.m_autoChangeFormat ),
00147       m_autoReplaceNumber( format.m_autoReplaceNumber ),
00148       m_useAutoNumberStyle( format.m_useAutoNumberStyle ),
00149       m_completion( format.m_completion ),
00150       m_completionAppendSpace( format.m_completionAppendSpace ),
00151       m_addCompletionWord( format.m_addCompletionWord ),
00152       m_includeTwoUpperLetterException( format.m_includeTwoUpperLetterException ),
00153       m_includeAbbreviation( format.m_includeAbbreviation ),
00154       m_ignoreUpperCase( format.m_ignoreUpperCase ),
00155       m_bAutoFormatActive( format.m_bAutoFormatActive ),
00156       m_bAutoSuperScript( format.m_bAutoSuperScript ),
00157       m_bAutoCorrectionWithFormat( format.m_bAutoCorrectionWithFormat),
00158       m_bCapitalizeNameOfDays( format.m_bCapitalizeNameOfDays),
00159       m_bulletStyle( format.m_bulletStyle ),
00160       m_typographicSimpleQuotes( format.m_typographicSimpleQuotes ),
00161       m_typographicDoubleQuotes( format.m_typographicDoubleQuotes ),
00162       m_typographicDefaultDoubleQuotes( format.m_typographicDefaultDoubleQuotes),
00163       m_typographicDefaultSimpleQuotes( format.m_typographicDefaultSimpleQuotes),
00164       m_listCompletion( 0L ), // don't copy it!
00165       m_entries( ),//don't copy it.
00166       m_superScriptEntries ( format.m_superScriptEntries ),
00167       m_upperCaseExceptions( format.m_upperCaseExceptions ),
00168       m_twoUpperLetterException( format.m_twoUpperLetterException ),
00169       m_maxFindLength( format.m_maxFindLength ),
00170       m_minCompletionWordLength( format.m_minCompletionWordLength ),
00171       m_nbMaxCompletionWord( format.m_nbMaxCompletionWord ),
00172       m_cacheNameOfDays( format.m_cacheNameOfDays)
00173 {
00174     //m_listCompletion=new KCompletion();
00175     //m_listCompletion->setItems( autoFormat.listCompletion() );
00176     //copyAutoFormatEntries( autoFormat );
00177 }
00178 
00179 KoAutoFormat::~KoAutoFormat()
00180 {
00181     delete m_listCompletion;
00182     m_entries.setAutoDelete( true );
00183     m_entries.clear();
00184 }
00185 
00186 void KoAutoFormat::loadListOfWordCompletion()
00187 {
00188     KConfig* config = KoGlobal::kofficeConfig();
00189     KConfigGroupSaver cgs( config, "Completion Word" );
00190     m_listCompletion->insertItems(config->readListEntry( "list" ));
00191 }
00192 
00193 void KoAutoFormat::readConfig(bool force)
00194 {
00195     // Read the autoformat configuration
00196     // This is done on demand (when typing the first char, or when opening the config dialog)
00197     // so that loading is faster and to avoid doing it for readonly documents.
00198     if ( m_configRead && !force )
00199         return;
00200     KConfig* config = KoGlobal::kofficeConfig();
00201     KConfigGroupSaver cgs( config, "AutoFormat" );
00202     //when we force don't load format language.
00203     if ( !force)
00204         m_autoFormatLanguage = config->readEntry("formatLanguage", QString::null);
00205 
00206     m_convertUpperCase = config->readBoolEntry( "ConvertUpperCase", false );
00207     m_convertUpperUpper = config->readBoolEntry( "ConvertUpperUpper", false );
00208     m_includeTwoUpperLetterException = config->readBoolEntry( "includeTwoLetterException", false );
00209     m_includeAbbreviation = config->readBoolEntry( "includeAbbreviation", false );
00210 
00211     m_advancedAutoCorrect = config->readBoolEntry( "AdvancedAutocorrect", true );
00212     m_bAutoCorrectionWithFormat = config->readBoolEntry( "AutoCorrectionWithFormat",false );
00213     m_bCapitalizeNameOfDays = config->readBoolEntry( "CapitalizeNameOfDays",false );
00214 
00215     m_autoDetectUrl = config->readBoolEntry("AutoDetectUrl",false);
00216     m_ignoreDoubleSpace = config->readBoolEntry("IgnoreDoubleSpace",false);
00217     m_removeSpaceBeginEndLine = config->readBoolEntry("RemoveSpaceBeginEndLine",false);
00218 
00219     m_useBulletStyle = config->readBoolEntry("UseBulletStyle",false);
00220     QString tmp = config->readEntry( "BulletStyle", "" );
00221     m_bulletStyle = tmp.isEmpty() ? QChar() : tmp[0];
00222 
00223     m_autoChangeFormat = config->readBoolEntry( "AutoChangeFormat", false );
00224 
00225     m_autoReplaceNumber = config->readBoolEntry( "AutoReplaceNumber", false );
00226 
00227     m_useAutoNumberStyle = config->readBoolEntry( "AutoNumberStyle", false );
00228 
00229 
00230     QString beginDoubleQuote = config->readEntry( "TypographicQuotesBegin" );
00231     QString endDoubleQuote = config->readEntry( "TypographicQuotesEnd" );
00232 
00233     m_typographicDoubleQuotes.replace = config->readBoolEntry( "TypographicQuotesEnabled", false );
00234 
00235     QString begin = config->readEntry( "TypographicSimpleQuotesBegin" );
00236     QString end = config->readEntry( "TypographicSimpleQuotesEnd" );
00237     m_typographicSimpleQuotes.replace = config->readBoolEntry( "TypographicSimpleQuotesEnabled", false );
00238 
00239     m_bAutoSuperScript = config->readBoolEntry( "AutoSuperScript", false );
00240 
00241     config->setGroup( "completion" );
00242     m_completion = config->readBoolEntry( "completion", false );
00243 
00244     m_completionAppendSpace = config->readBoolEntry( "CompletionAppendSpace", false );
00245     m_minCompletionWordLength = config->readUnsignedNumEntry( "CompletionMinWordLength", 5 );
00246     m_nbMaxCompletionWord = config->readUnsignedNumEntry( "NbMaxCompletionWord", 100 );
00247     m_addCompletionWord = config->readBoolEntry( "AddCompletionWord", true );
00248 
00249     if ( force )
00250     {
00251         m_entries.setAutoDelete(true);
00252         m_entries.clear();
00253         m_entries.setAutoDelete(false);
00254         m_upperCaseExceptions.clear();
00255         m_superScriptEntries.clear();
00256         m_twoUpperLetterException.clear();
00257 
00258     }
00259 
00260     Q_ASSERT( m_entries.isEmpty() ); // readConfig is only called once...
00261     config->setGroup( "AutoFormatEntries" );
00262 
00263     bool fileNotFound = false;
00264     QFile xmlFile;
00265     KLocale klocale(m_doc->instance()->instanceName());
00266 
00267     if ( m_autoFormatLanguage.isEmpty() )
00268     {
00269         xmlFile.setName(locate( "data", "koffice/autocorrect/" + klocale.languageList().front() + ".xml", m_doc->instance() ));
00270         if(!xmlFile.open(IO_ReadOnly)) {
00271             xmlFile.setName(locate( "data", "koffice/autocorrect/autocorrect.xml", m_doc->instance() ));
00272             if(!xmlFile.open(IO_ReadOnly)) {
00273                 fileNotFound = true;
00274             }
00275         }
00276     }
00277     else
00278     {
00279         xmlFile.setName(locate( "data", "koffice/autocorrect/" + m_autoFormatLanguage + ".xml", m_doc->instance() ));
00280         if(!xmlFile.open(IO_ReadOnly))
00281         {
00282             xmlFile.setName(locate( "data", "koffice/autocorrect/" + klocale.languageList().front() + ".xml", m_doc->instance() ));
00283             if(!xmlFile.open(IO_ReadOnly)) {
00284                 xmlFile.setName(locate( "data", "koffice/autocorrect/autocorrect.xml", m_doc->instance() ));
00285                 if(!xmlFile.open(IO_ReadOnly)) {
00286                     fileNotFound = true;
00287                 }
00288             }
00289 
00290         }
00291     }
00292 
00293     if(!fileNotFound) {
00294         QDomDocument doc;
00295         if(!doc.setContent(&xmlFile)) {
00296             //return;
00297         }
00298         if(doc.doctype().name() != "autocorrection") {
00299             //return;
00300         }
00301         QDomElement de=doc.documentElement();
00302         QDomElement item = de.namedItem( "items" ).toElement();
00303         if(!item.isNull())
00304         {
00305             QDomNodeList nl = item.childNodes();
00306             m_maxFindLength=nl.count();
00307             for(uint i = 0; i < m_maxFindLength; i++) {
00308                 loadEntry( nl.item(i).toElement());
00309             }
00310         }
00311 
00312         QDomElement upper = de.namedItem( "UpperCaseExceptions" ).toElement();
00313         if(!upper.isNull())
00314         {
00315             QDomNodeList nl = upper.childNodes();
00316             for(uint i = 0; i < nl.count(); i++)
00317             {
00318                 m_upperCaseExceptions+= nl.item(i).toElement().attribute("exception");
00319             }
00320         }
00321 
00322         QDomElement twoUpper = de.namedItem( "TwoUpperLetterExceptions" ).toElement();
00323         if(!twoUpper.isNull())
00324         {
00325             QDomNodeList nl = twoUpper.childNodes();
00326             for(uint i = 0; i < nl.count(); i++)
00327             {
00328                 m_twoUpperLetterException+= nl.item(i).toElement().attribute("exception");
00329             }
00330         }
00331 
00332         QDomElement superScript = de.namedItem( "SuperScript" ).toElement();
00333         if(!superScript.isNull())
00334         {
00335             QDomNodeList nl = superScript.childNodes();
00336             for(uint i = 0; i < nl.count() ; i++) {
00337                 //bug in qmap we overwrite = false doesn't work
00338                 //so we can't add multiple "othernb"
00339                 m_superScriptEntries.insert( nl.item(i).toElement().attribute("find"), KoAutoFormatEntry(nl.item(i).toElement().attribute("super")),FALSE );
00340             }
00341         }
00342 
00343         QDomElement doubleQuote = de.namedItem( "DoubleQuote" ).toElement();
00344         if(!doubleQuote.isNull())
00345         {
00346             QDomElement childItem = doubleQuote.namedItem("doublequote").toElement();
00347             if ( !childItem.isNull() )
00348             {
00349                 QString attr = childItem.attribute( "begin" );
00350                 if ( !attr.isEmpty() && attr[0] != 0 )
00351                     m_typographicDefaultDoubleQuotes.begin = attr[0];
00352                 attr = childItem.attribute( "end" );
00353                 if ( !attr.isEmpty() && attr[0] != 0 )
00354                     m_typographicDefaultDoubleQuotes.end = attr[0];
00355             }
00356         }
00357         QDomElement simpleQuote = de.namedItem( "SimpleQuote" ).toElement();
00358         if(!simpleQuote.isNull())
00359         {
00360             QDomElement childItem = simpleQuote.namedItem("simplequote").toElement();
00361             if ( !childItem.isNull() )
00362             {
00363                 QString attr = childItem.attribute( "begin" );
00364                 if ( !attr.isEmpty() && attr[0] != 0 )
00365                     m_typographicDefaultSimpleQuotes.begin = attr[0];
00366                 attr = childItem.attribute( "end" );
00367                 if ( !attr.isEmpty() && attr[0] != 0 )
00368                     m_typographicDefaultSimpleQuotes.end = attr[0];
00369             }
00370         }
00371     }
00372 
00373     if( beginDoubleQuote.isEmpty())
00374     {
00375         if( m_typographicDefaultDoubleQuotes.begin.isNull())
00376             m_typographicDoubleQuotes.begin = QChar('«');
00377         else
00378             m_typographicDoubleQuotes.begin = m_typographicDefaultDoubleQuotes.begin;
00379     }
00380     else
00381         m_typographicDoubleQuotes.begin = beginDoubleQuote[0];
00382 
00383     if( endDoubleQuote.isEmpty() )
00384     {
00385         if( m_typographicDefaultDoubleQuotes.end.isNull())
00386             m_typographicDoubleQuotes.end = QChar('»');
00387         else
00388             m_typographicDoubleQuotes.end = m_typographicDefaultDoubleQuotes.end;
00389     }
00390     else
00391         m_typographicDoubleQuotes.end = endDoubleQuote[0];
00392 
00393     m_typographicDoubleQuotes.replace = m_typographicDoubleQuotes.replace
00394                                         && !m_typographicDoubleQuotes.begin.isNull()
00395                                         && !m_typographicDoubleQuotes.end.isNull();
00396 
00397 
00398     if( begin.isEmpty())
00399     {
00400         if( m_typographicDefaultSimpleQuotes.begin.isNull())
00401             m_typographicSimpleQuotes.begin = QChar('\'');
00402         else
00403             m_typographicSimpleQuotes.begin = m_typographicDefaultSimpleQuotes.begin;
00404     }
00405     else
00406         m_typographicSimpleQuotes.begin = begin[0];
00407 
00408     if( end.isEmpty() )
00409     {
00410         if( m_typographicDefaultSimpleQuotes.end.isNull())
00411             m_typographicSimpleQuotes.end = QChar('\'');
00412         else
00413             m_typographicSimpleQuotes.end = m_typographicDefaultSimpleQuotes.end;
00414     }
00415     else
00416         m_typographicSimpleQuotes.end = end[0];
00417 
00418     m_typographicSimpleQuotes.replace = m_typographicSimpleQuotes.replace
00419                                         && !m_typographicSimpleQuotes.end.isNull()
00420                                         && !m_typographicSimpleQuotes.begin.isNull();
00421 
00422 
00423     xmlFile.close();
00424     buildMaxLen();
00425     autoFormatIsActive();
00426     m_configRead = true;
00427 }
00428 
00429 void KoAutoFormat::loadEntry( const QDomElement &nl)
00430 {
00431     KoAutoFormatEntry *tmp =new KoAutoFormatEntry(nl.attribute("replace"));
00432     if ( nl.hasAttribute("FONT"))
00433     {
00434         tmp->createNewEntryContext();
00435         tmp->formatEntryContext()->m_family=nl.attribute("FONT");
00436         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::Family;
00437     }
00438     if ( nl.hasAttribute("SIZE" ))
00439     {
00440         tmp->createNewEntryContext();
00441         tmp->formatEntryContext()->m_size = nl.attribute("SIZE" ).toInt();
00442         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::Size;
00443     }
00444     if (nl.hasAttribute("BOLD" ))
00445     {
00446         tmp->createNewEntryContext();
00447         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::Bold;
00448         QString value = nl.attribute("BOLD");
00449         if ( value.toInt() == 1 )
00450             tmp->formatEntryContext()->m_options |= KoSearchContext::Bold;
00451     }
00452     if (nl.hasAttribute("ITALIC" ))
00453     {
00454         tmp->createNewEntryContext();
00455         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::Italic;
00456         QString value = nl.attribute("ITALIC");
00457         if ( value.toInt() == 1 )
00458             tmp->formatEntryContext()->m_options |= KoSearchContext::Italic;
00459     }
00460     if (nl.hasAttribute("UNDERLINE" ))
00461     {
00462         tmp->createNewEntryContext();
00463         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::Underline;
00464         QString value = nl.attribute("UNDERLINE");
00465         if ( value =="single" )
00466             tmp->formatEntryContext()->m_underline = KoTextFormat::U_SIMPLE;
00467         else if ( value =="double" )
00468             tmp->formatEntryContext()->m_underline = KoTextFormat::U_DOUBLE;
00469         else if ( value =="single-bold" )
00470             tmp->formatEntryContext()->m_underline = KoTextFormat::U_SIMPLE_BOLD;
00471         else
00472             tmp->formatEntryContext()->m_underline = KoTextFormat::U_NONE;
00473     }
00474     if (nl.hasAttribute("STRIKEOUT" ))
00475     {
00476         tmp->createNewEntryContext();
00477         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::StrikeOut;
00478         QString value = nl.attribute("STRIKEOUT");
00479         if ( value =="single" )
00480             tmp->formatEntryContext()->m_strikeOut = KoTextFormat::S_SIMPLE;
00481         else if ( value =="double" )
00482             tmp->formatEntryContext()->m_strikeOut = KoTextFormat::S_DOUBLE;
00483         else if ( value =="single-bold" )
00484             tmp->formatEntryContext()->m_strikeOut = KoTextFormat::S_SIMPLE_BOLD;
00485         else
00486             tmp->formatEntryContext()->m_strikeOut = KoTextFormat::S_NONE;
00487     }
00488     if (nl.hasAttribute("VERTALIGN" ))
00489     {
00490         tmp->createNewEntryContext();
00491         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::VertAlign;
00492         QString value = nl.attribute("VERTALIGN");
00493         tmp->formatEntryContext()->m_vertAlign=static_cast<KoTextFormat::VerticalAlignment>( value.toInt() );
00494 
00495     }
00496     if ( nl.hasAttribute("TEXTCOLOR" ))
00497     {
00498         tmp->createNewEntryContext();
00499         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::Color;
00500         QColor col( nl.attribute("TEXTCOLOR" ));
00501         tmp->formatEntryContext()->m_color = col;
00502     }
00503     if ( nl.hasAttribute("TEXTBGCOLOR" ))
00504     {
00505         tmp->createNewEntryContext();
00506         tmp->formatEntryContext()->m_optionsMask |= KoSearchContext::BgColor;
00507         QColor col( nl.attribute("TEXTBGCOLOR" ));
00508         tmp->formatEntryContext()->m_backGroundColor = col;
00509     }
00510     m_entries.insert( nl.attribute("find"), tmp );
00511 }
00512 
00513 void KoAutoFormat::saveConfig()
00514 {
00515     KConfig* config = KoGlobal::kofficeConfig();
00516     KLocale klocale(m_doc->instance()->instanceName());
00517     KConfigGroupSaver cgs( config, "AutoFormat" );
00518     config->writeEntry( "ConvertUpperCase", m_convertUpperCase );
00519     config->writeEntry( "formatLanguage", m_autoFormatLanguage);
00520 
00521     config->writeEntry( "ConvertUpperUpper", m_convertUpperUpper );
00522     config->writeEntry( "includeTwoLetterException", m_includeTwoUpperLetterException );
00523     config->writeEntry( "includeAbbreviation", m_includeAbbreviation );
00524 
00525     config->writeEntry( "TypographicQuotesBegin", QString( m_typographicDoubleQuotes.begin ) );
00526     config->writeEntry( "TypographicQuotesEnd", QString( m_typographicDoubleQuotes.end ) );
00527     config->writeEntry( "TypographicQuotesEnabled", m_typographicDoubleQuotes.replace );
00528     config->writeEntry( "TypographicSimpleQuotesBegin", QString( m_typographicSimpleQuotes.begin ) );
00529     config->writeEntry( "TypographicSimpleQuotesEnd", QString( m_typographicSimpleQuotes.end ) );
00530     config->writeEntry( "TypographicSimpleQuotesEnabled", m_typographicSimpleQuotes.replace );
00531 
00532     config->writeEntry( "AdvancedAutocorrect", m_advancedAutoCorrect );
00533     config->writeEntry( "AutoCorrectionWithFormat", m_bAutoCorrectionWithFormat );
00534     config->writeEntry( "CapitalizeNameOfDays", m_bCapitalizeNameOfDays );
00535 
00536     config->writeEntry( "AutoDetectUrl",m_autoDetectUrl);
00537 
00538     config->writeEntry( "IgnoreDoubleSpace",m_ignoreDoubleSpace );
00539     config->writeEntry( "RemoveSpaceBeginEndLine",m_removeSpaceBeginEndLine );
00540 
00541     config->writeEntry( "UseBulletStyle", m_useBulletStyle);
00542     config->writeEntry( "BulletStyle", QString(m_bulletStyle));
00543 
00544     config->writeEntry( "AutoChangeFormat", m_autoChangeFormat);
00545 
00546     config->writeEntry( "AutoReplaceNumber", m_autoReplaceNumber);
00547 
00548     config->writeEntry( "AutoNumberStyle", m_useAutoNumberStyle );
00549 
00550     config->writeEntry( "AutoSuperScript", m_bAutoSuperScript );
00551 
00552     config->setGroup( "completion" );
00553     config->writeEntry( "completion", m_completion );
00554     config->writeEntry( "CompletionAppendSpace", m_completionAppendSpace );
00555     config->writeEntry( "CompletionMinWordLength", m_minCompletionWordLength);
00556     config->writeEntry( "NbMaxCompletionWord", m_nbMaxCompletionWord);
00557     config->writeEntry( "AddCompletionWord", m_addCompletionWord );
00558 
00559 
00560 
00561     config->setGroup( "AutoFormatEntries" );
00562     QDictIterator<KoAutoFormatEntry> it( m_entries );
00563 
00564     //refresh m_maxFindLength
00565     m_maxFindLength=0;
00566     QDomDocument doc("autocorrection");
00567 
00568     QDomElement begin = doc.createElement( "Word" );
00569     doc.appendChild( begin );
00570     QDomElement items;
00571     items = doc.createElement("items");
00572     QDomElement data;
00573     for ( ; it.current() ; ++it )
00574     {
00575     items.appendChild(saveEntry( it, doc));
00576         m_maxFindLength=QMAX(m_maxFindLength,it.currentKey().length());
00577     }
00578     begin.appendChild(items);
00579 
00580     QDomElement upper;
00581     upper = doc.createElement("UpperCaseExceptions");
00582     for ( QStringList::Iterator it = m_upperCaseExceptions.begin(); it != m_upperCaseExceptions.end();++it )
00583     {
00584     data = doc.createElement("word");
00585     data.setAttribute("exception",(*it) );
00586     upper.appendChild(data);
00587     }
00588     begin.appendChild(upper);
00589 
00590     QDomElement twoUpper;
00591     twoUpper = doc.createElement("TwoUpperLetterExceptions");
00592 
00593     for ( QStringList::Iterator it = m_twoUpperLetterException.begin(); it != m_twoUpperLetterException.end();++it )
00594     {
00595     data = doc.createElement("word");
00596     data.setAttribute("exception",(*it) );
00597     twoUpper.appendChild(data);
00598     }
00599     begin.appendChild(twoUpper);
00600 
00601     QDomElement super;
00602     super = doc.createElement("SuperScript");
00603     KoAutoFormatEntryMap::Iterator it2 = m_superScriptEntries.begin();
00604     for ( ; it2 != m_superScriptEntries.end() ; ++it2 )
00605     {
00606     data = doc.createElement("superscript");
00607     data.setAttribute("find", it2.key());
00608     data.setAttribute("super", it2.data().replace());
00609     super.appendChild(data);
00610     }
00611     begin.appendChild(super);
00612 
00613     QDomElement doubleQuote;
00614     doubleQuote = doc.createElement("DoubleQuote");
00615     data = doc.createElement("doublequote");
00616     data.setAttribute("begin", QString(m_typographicDefaultDoubleQuotes.begin));
00617     data.setAttribute("end", QString(m_typographicDefaultDoubleQuotes.end));
00618     doubleQuote.appendChild(data);
00619     begin.appendChild(doubleQuote);
00620 
00621 
00622     QDomElement simpleQuote;
00623     simpleQuote = doc.createElement("SimpleQuote");
00624     data = doc.createElement("simplequote");
00625     data.setAttribute("begin", QString(m_typographicDefaultSimpleQuotes.begin));
00626     data.setAttribute("end", QString(m_typographicDefaultSimpleQuotes.end));
00627     simpleQuote.appendChild(data);
00628     begin.appendChild(simpleQuote);
00629     QFile f;
00630     if ( m_autoFormatLanguage.isEmpty())
00631         f.setName(locateLocal("data", "koffice/autocorrect/"+klocale.languageList().front() + ".xml",m_doc->instance()));
00632     else
00633         f.setName(locateLocal("data", "koffice/autocorrect/"+m_autoFormatLanguage + ".xml",m_doc->instance()));
00634     if(!f.open(IO_WriteOnly)) {
00635         kdWarning()<<"Error during saving autoformat to " << f.name() << endl;
00636     return;
00637     }
00638     QTextStream ts(&f);
00639     doc.save(ts, 2);
00640     f.close();
00641     autoFormatIsActive();
00642     config->sync();
00643 }
00644 
00645 QDomElement KoAutoFormat::saveEntry( QDictIterator<KoAutoFormatEntry> _entry, QDomDocument doc)
00646 {
00647     QDomElement data;
00648     data = doc.createElement("item");
00649     data.setAttribute("find", _entry.currentKey());
00650     data.setAttribute("replace", _entry.current()->replace());
00651     if ( _entry.current()->formatEntryContext() )
00652     {
00653         KoSearchContext *tmp = _entry.current()->formatEntryContext();
00654         if ( tmp->m_optionsMask & KoSearchContext::Family )
00655         {
00656             data.setAttribute("FONT", tmp->m_family);
00657         }
00658         if ( tmp->m_optionsMask &  KoSearchContext::Size )
00659         {
00660             data.setAttribute("SIZE", tmp->m_size);
00661         }
00662         if ( tmp->m_optionsMask & KoSearchContext::Italic )
00663         {
00664             data.setAttribute("ITALIC", static_cast<bool>(tmp->m_options & KoSearchContext::Italic));
00665         }
00666         if ( tmp->m_optionsMask & KoSearchContext::Bold )
00667         {
00668             data.setAttribute("BOLD", static_cast<bool>(tmp->m_options & KoSearchContext::Bold));
00669         }
00670         if ( tmp->m_optionsMask & KoSearchContext::Shadow )
00671         {
00672             data.setAttribute("SHADOWTEXT", static_cast<bool>(tmp->m_options & KoSearchContext::Shadow));
00673         }
00674         if ( tmp->m_optionsMask & KoSearchContext::WordByWord )
00675         {
00676             data.setAttribute("WORDBYWORD", static_cast<bool>(tmp->m_options & KoSearchContext::WordByWord));
00677         }
00678 
00679         if ( tmp->m_optionsMask & KoSearchContext::Underline )
00680         {
00681             switch( tmp->m_underline )
00682             {
00683             case KoTextFormat::U_SIMPLE:
00684                 data.setAttribute("UNDERLINE", "single");
00685                 break;
00686             case KoTextFormat::U_DOUBLE:
00687                 data.setAttribute("UNDERLINE", "double");
00688                 break;
00689             case KoTextFormat::U_SIMPLE_BOLD:
00690                 data.setAttribute("UNDERLINE", "single-bold");
00691                 break;
00692             case KoTextFormat::U_WAVE:
00693                 data.setAttribute("UNDERLINE", "wave");
00694                 break;
00695             case KoTextFormat::U_NONE:
00696                 data.setAttribute("UNDERLINE", "none");
00697                 break;
00698             }
00699         }
00700         if ( tmp->m_optionsMask & KoSearchContext::StrikeOut )
00701         {
00702             switch( tmp->m_strikeOut )
00703             {
00704             case KoTextFormat::S_SIMPLE:
00705                 data.setAttribute("STRIKEOUT", "single");
00706                 break;
00707             case KoTextFormat::S_DOUBLE:
00708                 data.setAttribute("STRIKEOUT", "double");
00709                 break;
00710             case KoTextFormat::S_NONE:
00711                 data.setAttribute("STRIKEOUT", "none");
00712                 break;
00713             case KoTextFormat::S_SIMPLE_BOLD:
00714                 data.setAttribute("STRIKEOUT", "single-bold");
00715                 break;
00716             }
00717         }
00718         if ( tmp->m_optionsMask & KoSearchContext::Attribute )
00719         {
00720             data.setAttribute("FONTATTRIBUTE", KoTextFormat::attributeFontToString( tmp->m_attribute ) );
00721         }
00722 
00723         if ( tmp->m_optionsMask & KoSearchContext::VertAlign)
00724         {
00725             data.setAttribute( "VERTALIGN", static_cast<int>(tmp->m_vertAlign) );
00726         }
00727         if ( tmp->m_optionsMask & KoSearchContext::BgColor )
00728         {
00729             data.setAttribute( "TEXTCOLOR", tmp->m_color.name());
00730         }
00731         if ( tmp->m_optionsMask & KoSearchContext::Color )
00732         {
00733             data.setAttribute( "TEXTCOLOR", tmp->m_color.name());
00734         }
00735         if ( tmp->m_optionsMask & KoSearchContext::BgColor )
00736         {
00737             data.setAttribute( "TEXTBGCOLOR", tmp->m_backGroundColor.name());
00738         }
00739         if ( tmp->m_optionsMask & KoSearchContext::Language )
00740             data.setAttribute( "LANGUAGE", tmp->m_language );
00741     }
00742     return data;
00743 }
00744 
00745 void KoAutoFormat::addAutoFormatEntry( const QString &key, const QString &replace )
00746 {
00747     KoAutoFormatEntry *findEntry = m_entries.find( key);
00748     if ( findEntry )
00749     {
00750         if ( findEntry->replace() == replace )
00751             return;
00752     }
00753 
00754     KoAutoFormatEntry *tmp = new KoAutoFormatEntry( replace );
00755     m_entries.insert( key, tmp );
00756     saveConfig();
00757     buildMaxLen();
00758 }
00759 
00760 QString KoAutoFormat::getLastWord(KoTextParag *parag, int index)
00761 {
00762     QString lastWord;
00763     KoTextString *s = parag->string();
00764     for ( int i = index - 1; i >= 0; --i )
00765     {
00766         QChar ch = s->at( i ).c;
00767         if ( ch.isSpace() || ch.isPunct() )
00768             break;
00769         lastWord.prepend( ch );
00770     }
00771     return lastWord;
00772 }
00773 
00774 QString KoAutoFormat::getWordAfterSpace(KoTextParag *parag, int index)
00775 {
00776     QString word;
00777     KoTextString *s = parag->string();
00778     for ( int i = index - 1; i >= 0; --i )
00779     {
00780         QChar ch = s->at( i ).c;
00781         if ( ch.isSpace() )
00782             break;
00783         word.prepend( ch );
00784     }
00785     return word;
00786 
00787 }
00788 
00789 void KoAutoFormat::doCompletion( KoTextCursor* textEditCursor, KoTextParag *parag, int index, KoTextObject *txtObj )
00790 {
00791     if( m_completion )
00792     {
00793         QString lastWord = getLastWord(parag, index+1);
00794         QString word=m_listCompletion->makeCompletion( lastWord.lower() );
00795         if( !word.isEmpty() && word!=lastWord )
00796         {
00797             unsigned int length = lastWord.length();
00798             int start = index+1 - length;
00799             KMacroCommand *macro = new KMacroCommand( i18n("Completion Word"));
00800 
00801             KoTextCursor cursor( parag->document() );
00802             cursor.setParag( parag );
00803             cursor.setIndex( start );
00804             KoTextDocument * textdoc = parag->textDocument();
00805             word=lastWord+word.right(word.length()-lastWord.length());
00806             if( m_completionAppendSpace )
00807                 word+=" ";
00808             textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
00809             cursor.setIndex( start + length );
00810             textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
00811 
00812             macro->addCommand( txtObj->replaceSelectionCommand( textEditCursor, word,
00813                                                               KoTextObject::HighlightSelection,
00814                                                               i18n("Completion Word") ));
00815             if ( m_completionAppendSpace && !m_ignoreUpperCase && (m_convertUpperUpper || m_convertUpperCase) )
00816             {
00817                 int newPos = word.length() + index - 3;
00818                 lastWord = getLastWord(parag, newPos);
00819                 KCommand *cmd = doUpperCase( textEditCursor, parag, newPos, lastWord, txtObj );
00820                 if( cmd )
00821                     macro->addCommand( cmd );
00822             }
00823             txtObj->emitNewCommand( macro );
00824 
00825             // The space/tab/CR that we inserted is still there but delete/insert moved the cursor
00826             // -> go right
00827             txtObj->emitHideCursor();
00828             textEditCursor->gotoRight();
00829             txtObj->emitShowCursor();
00830         }
00831     }
00832 }
00833 
00834 void KoAutoFormat::autoFormatIsActive()
00835 {
00836     m_bAutoFormatActive = m_useBulletStyle ||
00837                           m_removeSpaceBeginEndLine ||
00838                           m_autoDetectUrl ||
00839                           m_convertUpperUpper ||
00840                           m_convertUpperCase ||
00841                           m_autoReplaceNumber ||
00842                           m_autoChangeFormat ||
00843                           m_completion ||
00844                           m_typographicDoubleQuotes.replace ||
00845                           m_typographicSimpleQuotes.replace ||
00846        m_entries.count()!=0;
00847 }
00848 
00849 void KoAutoFormat::doAutoFormat( KoTextCursor* textEditCursor, KoTextParag *parag, int index, QChar ch,KoTextObject *txtObj )
00850 {
00851     if ( !m_configRead )
00852         readConfig();
00853 
00854     if ( !m_bAutoFormatActive )
00855         return;
00856 
00857     if( ch.isSpace())
00858     {
00859         //a link doesn't have a space
00860         //=>m_ignoreUpperCase = false
00861         m_ignoreUpperCase=false;
00862 
00863         QString word=getWordAfterSpace(parag,index);
00864 
00865         if ( m_autoChangeFormat && index > 3)
00866         {
00867             KCommand *cmd =doAutoChangeFormat( textEditCursor, parag, index, word, txtObj );
00868             if ( cmd )
00869                 txtObj->emitNewCommand( cmd );
00870 
00871         }
00872         if ( m_autoDetectUrl && index > 0 )
00873         {
00874             doAutoDetectUrl( textEditCursor, parag, index, word, txtObj );
00875         }
00876         if ( m_autoReplaceNumber )
00877         {
00878             KCommand *cmd = doAutoReplaceNumber( textEditCursor, parag, index, word, txtObj );
00879             if ( cmd )
00880                 txtObj->emitNewCommand( cmd );
00881         }
00882     }
00883 
00884     if( ch =='\n' )
00885     {
00886         if( m_removeSpaceBeginEndLine && index > 1)
00887         {
00888             KCommand *cmd =doRemoveSpaceBeginEndLine( textEditCursor, parag, txtObj );
00889             if ( cmd )
00890                 txtObj->emitNewCommand( cmd );
00891         }
00892         if( m_useBulletStyle  && index > 3)
00893         {
00894             KCommand *cmd =doUseBulletStyle( textEditCursor, parag, txtObj, index );
00895             if ( cmd )
00896                 txtObj->emitNewCommand( cmd );
00897         }
00898         if( m_useAutoNumberStyle && index > 3 )
00899         {
00900             KCommand *cmd =doUseNumberStyle( textEditCursor, parag, txtObj, index );
00901             if ( cmd )
00902                 txtObj->emitNewCommand( cmd );
00903         }
00904         if( m_convertUpperUpper && m_includeTwoUpperLetterException )
00905             doAutoIncludeUpperUpper(textEditCursor, parag, txtObj );
00906         if( m_convertUpperCase && m_includeAbbreviation )
00907             doAutoIncludeAbbreviation(textEditCursor, parag, txtObj );
00908     }
00909 
00910     //kdDebug(32500) << "KoAutoFormat::doAutoFormat ch=" << QString(ch) << endl;
00911     //if ( !m_enabled )
00912     //    return;
00913     // Auto-correction happens when pressing space, tab, CR, punct etc.
00914     if ( ( ch.isSpace() || ch.isPunct() ) && index > 0 )
00915     {
00916         QString lastWord = getLastWord(parag, index);
00917         //kdDebug(32500)<<" m_listCompletion->items() :"<<m_listCompletion->items()<<endl;
00918         if( m_completion && m_addCompletionWord && m_listCompletion->items().count() < m_nbMaxCompletionWord
00919             && lastWord.length()>= m_minCompletionWordLength )
00920         {
00921             if ( m_listCompletion->makeCompletion( lastWord.lower() ).isEmpty())
00922                 m_listCompletion->addItem( lastWord.lower() );
00923         }
00924 
00925         detectStartOfLink(lastWord);
00926         //kdDebug(32500) << "KoAutoFormat::doAutoFormat lastWord=" << lastWord << endl;
00927         KMacroCommand *macro = 0L;
00928         int newPos = index;
00929         KCommand *cmd = doAutoCorrect( textEditCursor, parag, newPos, txtObj );
00930 
00931         if( cmd )
00932         {
00933             if (!macro)
00934                 macro = new KMacroCommand(i18n("Autocorrection"));
00935             macro->addCommand( cmd );
00936         }
00937         if ( m_bCapitalizeNameOfDays)
00938         {
00939             KCommand *cmd = doCapitalizeNameOfDays( textEditCursor, parag, newPos, lastWord, txtObj  );
00940 
00941             if( cmd )
00942             {
00943                 if (!macro)
00944                 macro = new KMacroCommand(i18n("Autocorrection"));
00945                 macro->addCommand( cmd );
00946             }
00947         }
00948 
00949         if ( !m_ignoreUpperCase && (m_convertUpperUpper || m_convertUpperCase) )
00950         {
00951             lastWord = getLastWord(parag, newPos);
00952             cmd = doUpperCase( textEditCursor, parag, newPos, lastWord, txtObj );
00953             if( cmd )
00954             {
00955                 if (!macro)
00956                     macro = new KMacroCommand(i18n("Autocorrection"));
00957                 macro->addCommand( cmd );
00958             }
00959         }
00960 
00961         if ( macro )
00962             txtObj->emitNewCommand( macro );
00963 
00964         if( m_bAutoSuperScript && m_superScriptEntries.count()>0)
00965         {
00966             KCommand * cmd = doAutoSuperScript( textEditCursor, parag, newPos, lastWord, txtObj  );
00967             if ( cmd )
00968                 txtObj->emitNewCommand( cmd );
00969         }
00970 
00971 
00972     }
00973     if ( ch == '"' && m_typographicDoubleQuotes.replace )
00974     {
00975         KCommand *cmd = doTypographicQuotes( textEditCursor, parag, index, txtObj, true /*double quote*/ );
00976         if ( cmd )
00977             txtObj->emitNewCommand( cmd );
00978     }
00979     else if ( ch == '\'' && m_typographicDoubleQuotes.replace )
00980     {
00981         KCommand *cmd = doTypographicQuotes( textEditCursor, parag, index, txtObj, false /* simple quote*/ );
00982         if ( cmd )
00983             txtObj->emitNewCommand( cmd );
00984     }
00985 }
00986 
00987 KCommand *KoAutoFormat::doAutoCorrect( KoTextCursor* textEditCursor, KoTextParag *parag, int &index, KoTextObject *txtObj )
00988 {
00989     if(!m_advancedAutoCorrect)
00990         return 0L;
00991     // Prepare an array with words of different lengths, all terminating at "index".
00992     // Obviously only full words are put into the array
00993     // But this allows 'find strings' with spaces and punctuation in them.
00994     QString * wordArray = new QString[m_maxFindLength+1];
00995     {
00996         QString word;
00997         KoTextString *s = parag->string();
00998         for ( int i = index - 1; i >= 0; --i )
00999         {
01000             QChar ch = s->at( i ).c;
01001             if ( ch.isSpace() || ch.isPunct() || i==0)
01002             {
01003                 if(i==0 && word.length()<m_maxFindLength)
01004                     word.prepend( ch );
01005                 wordArray[word.length()]=word;
01006             }
01007             word.prepend( ch );
01008             if (((index - 1)-i) == (int)m_maxFindLength)
01009                 break;
01010         }
01011     }
01012     KoTextDocument * textdoc = parag->textDocument();
01013 
01014     // Now for each entry in the autocorrect list, look if
01015     // the word of the same size in wordArray matches.
01016     // This allows an o(n) behaviour instead of an o(n^2).
01017     for(int i=m_maxFindLength;i>0;--i)
01018     {
01019         if ( !wordArray[i].isEmpty())
01020         {
01021             KoAutoFormatEntry* it = m_entries[ wordArray[i] ];
01022             if ( wordArray[i]!=0  && it )
01023             {
01024                 unsigned int length = wordArray[i].length();
01025                 int start = index - length;
01026                 KoTextCursor cursor( parag->document() );
01027                 cursor.setParag( parag );
01028                 cursor.setIndex( start );
01029                 textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01030                 cursor.setIndex( start + length );
01031                 textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01032                 KCommand *cmd = 0L;
01033                 if (!it->formatEntryContext() || !m_bAutoCorrectionWithFormat)
01034                     cmd = txtObj->replaceSelectionCommand( textEditCursor, it->replace(),
01035                                                            KoTextObject::HighlightSelection,
01036                                                            i18n("Autocorrect Word") );
01037                 else
01038                 {
01039                     int flags = 0;
01040                     KoTextFormat * lastFormat = parag->at( start )->format();
01041                     KoTextFormat * newFormat = new KoTextFormat(*lastFormat);
01042                     changeTextFormat(it->formatEntryContext(), newFormat, flags );
01043                     KMacroCommand *macro = new KMacroCommand( i18n("Autocorrect Word with Format"));
01044                     KCommand *cmd2=txtObj->replaceSelectionCommand( textEditCursor, it->replace(),
01045                                                                     KoTextObject::HighlightSelection,
01046                                                                     i18n("Autocorrect Word") );
01047                     if ( cmd2 )
01048                         macro->addCommand(cmd2);
01049                     KoTextCursor cursor( parag->document() );
01050                     cursor.setParag( parag );
01051                     cursor.setIndex( start );
01052                     textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01053                     cursor.setIndex( start + length + 1 );
01054                     textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01055 
01056 
01057                     cmd2 =txtObj->setFormatCommand( textEditCursor, &lastFormat, newFormat, flags, false, KoTextObject::HighlightSelection );
01058                     macro->addCommand( cmd2);
01059                     cmd = macro;
01060                 }
01061                 // The space/tab/CR that we inserted is still there but delete/insert moved the cursor
01062                 // -> go right
01063                 txtObj->emitHideCursor();
01064                 textEditCursor->gotoRight();
01065                 txtObj->emitShowCursor();
01066                 delete [] wordArray;
01067                 index = index - length + it->replace().length();
01068                 return cmd;
01069             }
01070         }
01071     }
01072     delete [] wordArray;
01073     return 0L;
01074 }
01075 
01076 KCommand *KoAutoFormat::doTypographicQuotes( KoTextCursor* textEditCursor, KoTextParag *parag, int index, KoTextObject *txtObj, bool doubleQuotes )
01077 {
01078     //kdDebug(32500) << "KoAutoFormat::doTypographicQuotes" << endl;
01079     KoTextDocument * textdoc = parag->textDocument();
01080     KoTextCursor cursor( parag->document() );
01081     cursor.setParag( parag );
01082     cursor.setIndex( index );
01083     textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01084     cursor.setIndex( index + 1 );
01085     textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01086 
01087     // Need to determine if we want a starting or ending quote.
01088     // I see two solutions: either simply alternate, or depend on leading space.
01089     // MSWord does the latter afaics...
01090     QString replacement;
01091     if ( index > 0 && !parag->at( index - 1 )->c.isSpace() )
01092     {
01093         if( doubleQuotes )
01094             replacement = m_typographicDoubleQuotes.end;
01095         else
01096             replacement = m_typographicSimpleQuotes.end;
01097     }
01098     else
01099     {
01100         if( doubleQuotes )
01101             replacement = m_typographicDoubleQuotes.begin;
01102         else
01103             replacement = m_typographicSimpleQuotes.begin;
01104     }
01105     return txtObj->replaceSelectionCommand( textEditCursor, replacement,
01106                               KoTextObject::HighlightSelection,
01107                                             i18n("Typographic Quote") );
01108 }
01109 
01110 KCommand * KoAutoFormat::doUpperCase( KoTextCursor *textEditCursor, KoTextParag *parag,
01111                                 int index, const QString & word, KoTextObject *txtObj )
01112 {
01113     KoTextDocument * textdoc = parag->textDocument();
01114     unsigned int length = word.length();
01115     int start = index - length;
01116     KoTextCursor backCursor( parag->document() );
01117     backCursor.setParag( parag );
01118     backCursor.setIndex( start );
01119 
01120     // backCursor now points at the first char of the word
01121     QChar firstChar = backCursor.parag()->at( backCursor.index() )->c;
01122     bool bNeedMove = false;
01123     KCommand *cmd = 0L;
01124     if ( m_convertUpperCase && isLower( firstChar ) )
01125     {
01126         bool beginningOfSentence = true; // true if beginning of text
01127         // Go back over any space/tab/CR
01128         while ( backCursor.index() > 0 || backCursor.parag()->prev() )
01129         {
01130             beginningOfSentence = false; // we could go back -> false unless we'll find '.'
01131             backCursor.gotoLeft();
01132             if ( !backCursor.parag()->at( backCursor.index() )->c.isSpace() )
01133                 break;
01134         }
01135         // We are now at the first non-space char before the word
01136         if ( !beginningOfSentence )
01137             beginningOfSentence = isMark( backCursor.parag()->at( backCursor.index() )->c ) && backCursor.parag()->at( backCursor.index()+1 )->c.isSpace();
01138 
01139         // Now look for exceptions
01140         if ( beginningOfSentence )
01141         {
01142             QChar punct = backCursor.parag()->at( backCursor.index() )->c;
01143             QString text = getLastWord( backCursor.parag(), backCursor.index() )
01144                            + punct;
01145             // text has the word at the end of the 'sentence', including the termination. Example: "Mr."
01146             beginningOfSentence = (m_upperCaseExceptions.findIndex(text)==-1); // Ok if we can't find it
01147         }
01148 
01149         if ( beginningOfSentence )
01150         {
01151             KoTextCursor cursor( parag->document() );
01152             cursor.setParag( parag );
01153             cursor.setIndex( start );
01154             textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01155             cursor.setIndex( start + 1 );
01156             textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01157             cmd = txtObj->replaceSelectionCommand( textEditCursor, QString( firstChar.upper() ),
01158                                       KoTextObject::HighlightSelection,
01159                                       i18n("Autocorrect (capitalize first letter)") );
01160             bNeedMove = true;
01161         }
01162     }
01163     else if ( m_convertUpperUpper && isUpper( firstChar ) && length > 2 )
01164     {
01165         backCursor.setIndex( backCursor.index() + 1 );
01166         QChar secondChar = backCursor.parag()->at( backCursor.index() )->c;
01167         //kdDebug(32500)<<" secondChar :"<<secondChar<<endl;
01168         if ( isUpper( secondChar ) )
01169         {
01170             // Check next letter - we still want to be able to write fully uppercase words...
01171             backCursor.setIndex( backCursor.index() + 1 );
01172             QChar thirdChar = backCursor.parag()->at( backCursor.index() )->c;
01173             if ( isLower( thirdChar ) && (m_twoUpperLetterException.findIndex(word)==-1))
01174             {
01175                 // Ok, convert
01176                 KoTextCursor cursor( parag->document() );
01177                 cursor.setParag( parag );
01178                 cursor.setIndex( start + 1 ); // After all the first letter's fine, so only change the second letter
01179                 textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01180                 cursor.setIndex( start + 2 );
01181                 textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01182 
01183                 QString replacement = word[1].lower();
01184                 cmd = txtObj->replaceSelectionCommand( textEditCursor, replacement,KoTextObject::HighlightSelection,i18n("Autocorrect (Convert two upper case letters to one upper case and one lower case letter.)") );
01185 
01186                 bNeedMove = true;
01187             }
01188         }
01189     }
01190     if ( bNeedMove )
01191     {
01192         txtObj->emitHideCursor();
01193         textEditCursor->setParag( parag );
01194         textEditCursor->setIndex( index );
01195         textEditCursor->gotoRight(); // not the same thing as index+1, in case of CR
01196         txtObj->emitShowCursor();
01197     }
01198     return cmd;
01199 }
01200 
01201 KCommand * KoAutoFormat::doAutoReplaceNumber( KoTextCursor* textEditCursor, KoTextParag *parag, int& index, const QString & word , KoTextObject *txtObj )
01202 {
01203     unsigned int length = word.length();
01204     if ( length != 3 )
01205         return 0L;
01206     KoTextDocument * textdoc = parag->textDocument();
01207     int start = index - length;
01208     if( word == QString("1/2") || word == QString("1/4") || word == QString("3/4") )
01209     {
01210         KoTextCursor cursor( parag->document() );
01211         cursor.setParag( parag );
01212         cursor.setIndex( start );
01213         textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01214         cursor.setIndex( start + length );
01215         textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01216         QString replacement;
01217         if( word == QString("1/2") )
01218             replacement=QString("½");
01219         else if (word == QString("1/4") )
01220             replacement=QString("¼");
01221         else if (word == QString("3/4") )
01222             replacement=QString("¾");
01223         QString cmdName=i18n("Autocorrect (replace 1/2... with ")+QString("½...)");
01224         KCommand *cmd =txtObj->replaceSelectionCommand( textEditCursor, replacement,
01225                                                            KoTextObject::HighlightSelection,
01226                                                                 cmdName );
01227         txtObj->emitHideCursor();
01228         textEditCursor->gotoRight();
01229         txtObj->emitShowCursor();
01230         index = index - length + replacement.length();
01231         return cmd;
01232     }
01233     return 0L;
01234 }
01235 
01236 void KoAutoFormat::detectStartOfLink(const QString &word)
01237 {
01238     if (word.find("http")!=-1 || word.find("https")!=-1 || word.find("mailto")!=-1
01239         || word.find("ftp")!=-1 || word.find("file")!=-1
01240         || word.find("news")!=-1 )
01241         m_ignoreUpperCase=true;
01242 }
01243 
01244 void KoAutoFormat::doAutoDetectUrl( KoTextCursor *textEditCursor, KoTextParag *parag, int& index, const QString & word, KoTextObject *txtObj )
01245 {
01246     if (word.find("http://")!=-1 || word.find("https://")!=-1 || word.find("mailto:")!=-1
01247         || word.find("ftp://")!=-1 || word.find("file:")!=-1
01248         || word.find("news:")!=-1)
01249     {
01250         unsigned int length = word.length();
01251         int start = index - length;
01252         KoTextCursor cursor( parag->document() );
01253         KoTextDocument * textdoc = parag->textDocument();
01254         cursor.setParag( parag );
01255         cursor.setIndex( start );
01256         textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01257         cursor.setIndex( start + length );
01258         textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01259         KoVariable *var=new KoLinkVariable( textdoc, word, word ,m_varFormatCollection->format( "STRING" ), m_varCollection );
01260 
01261         CustomItemsMap customItemsMap;
01262         customItemsMap.insert( 0, var );
01263         KoTextFormat * lastFormat = parag->at( start )->format();
01264         txtObj->insert( textEditCursor, lastFormat, KoTextObject::customItemChar(), false, true, i18n("Insert Variable"), customItemsMap,KoTextObject::HighlightSelection );
01265         var->recalc();
01266         parag->invalidate(0);
01267         parag->setChanged( true );
01268 
01269         txtObj->emitHideCursor();
01270         textEditCursor->gotoRight();
01271         txtObj->emitShowCursor();
01272 
01273         // adjust index
01274         index -= length-1; // we removed length chars and inserted one instead
01275     }
01276 
01277 }
01278 
01279 void KoAutoFormat::doAutoIncludeUpperUpper(KoTextCursor* /*textEditCursor*/, KoTextParag *parag, KoTextObject* /*txtObj*/ )
01280 {
01281     KoTextString *s = parag->string();
01282 
01283     if( s->length() < 2 )
01284         return;
01285 
01286     for (int i=0; i<=(s->length() - 1);i++)
01287     {
01288         QString word;
01289         for ( int j = i ; j < s->length() - 1; j++ )
01290         {
01291             QChar ch = s->at( j ).c;
01292             if ( ch.isSpace() )
01293                 break;
01294             word.append( ch );
01295         }
01296         if( word.length() > 2 && word.left(2)==word.left(2).upper() && word.at(3)!=word.at(3).upper() )
01297         {
01298             if ( m_twoUpperLetterException.findIndex(word )==-1)
01299                 m_twoUpperLetterException.append( word);
01300         }
01301         i+=word.length();
01302     }
01303 
01304 }
01305 
01306 
01307 void KoAutoFormat::doAutoIncludeAbbreviation(KoTextCursor* /*textEditCursor*/, KoTextParag *parag, KoTextObject* /*txtObj*/ )
01308 {
01309     KoTextString *s = parag->string();
01310 
01311     if( s->length() < 2 )
01312         return;
01313     for (int i=0; i<=(s->length() - 1);i++)
01314     {
01315         QString wordAfter;
01316         QString word;
01317 
01318         for ( int j = i ; j < s->length() - 1; j++ )
01319         {
01320             QChar ch = s->at( j ).c;
01321             if ( ch.isSpace() )
01322                 break;
01323             word.append( ch );
01324         }
01325         if ( isMark( word.at(word.length()-1)) )
01326         {
01327             for ( int j = i+word.length()+1 ; j < s->length() - 1; j++ )
01328             {
01329                 QChar ch = s->at( j ).c;
01330                 if ( ch.isSpace() )
01331                     break;
01332                 wordAfter.append( ch );
01333             }
01334             if( word.length()>1 && !wordAfter.isEmpty() && wordAfter.at(0)==wordAfter.at(0).lower())
01335             {
01336                 if ( m_upperCaseExceptions.findIndex(word )==-1)
01337                     m_upperCaseExceptions.append( word );
01338             }
01339         }
01340         i+=word.length();
01341         if( !wordAfter.isEmpty())
01342         {
01343             i+=wordAfter.length()+1;
01344         }
01345     }
01346 
01347 }
01348 
01349 
01350 KCommand * KoAutoFormat::doAutoChangeFormat( KoTextCursor *textEditCursor, KoTextParag *parag,int index, const QString & word, KoTextObject *txtObj )
01351 {
01352     bool underline = (word.at(0)=='_' && word.at(word.length()-1)=='_');
01353     bool bold = (word.at(0)=='*' && word.at(word.length()-1)=='*');
01354     if( bold || underline)
01355     {
01356         QString replacement=word.mid(1,word.length()-2);
01357         int start = index - word.length();
01358         KoTextDocument * textdoc = parag->textDocument();
01359         KMacroCommand *macro=new KMacroCommand(i18n("Autocorrection: Change Format"));
01360         KoTextCursor cursor( parag->document() );
01361 
01362         cursor.setParag( parag );
01363         cursor.setIndex( start );
01364         textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01365         cursor.setIndex( start + word.length() );
01366         textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01367         macro->addCommand(txtObj->replaceSelectionCommand( textEditCursor, replacement,
01368                                                            KoTextObject::HighlightSelection,
01369                                                            i18n("Autocorrect Word") ));
01370 
01371         KoTextFormat * lastFormat = parag->at( start )->format();
01372         KoTextFormat * newFormat = new KoTextFormat(*lastFormat);
01373         cursor.setIndex( start );
01374         textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01375         cursor.setIndex( start + word.length()-2 );
01376         textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01377 
01378         if( bold)
01379         {
01380             newFormat->setBold(true);
01381             macro->addCommand(txtObj->setFormatCommand( textEditCursor, 0L, newFormat, KoTextFormat::Bold , false,KoTextObject::HighlightSelection  ));
01382         }
01383         else if( underline )
01384         {
01385             newFormat->setUnderline(true);
01386             macro->addCommand(txtObj->setFormatCommand( textEditCursor, 0L, newFormat, KoTextFormat::Underline , false,KoTextObject::HighlightSelection  ));
01387         }
01388         txtObj->emitHideCursor();
01389         textEditCursor->gotoRight();
01390         txtObj->emitShowCursor();
01391         return macro;
01392     }
01393     return 0L;
01394 }
01395 
01396 KCommand *KoAutoFormat::doUseBulletStyle(KoTextCursor * /*textEditCursor*/, KoTextParag *parag, KoTextObject *txtObj, int& index )
01397 {
01398     KoTextDocument * textdoc = parag->textDocument();
01399     KoTextCursor cursor( parag->document() );
01400     KoTextString *s = parag->string();
01401     QChar ch = s->at( 0 ).c;
01402 
01403     if( m_useBulletStyle && (ch =='*' || ch == '-' || ch =='+') && (s->at(1).c).isSpace())
01404     {
01405         KMacroCommand *macroCmd = new KMacroCommand( i18n("Autocorrect (use bullet style)"));
01406         cursor.setParag( parag );
01407         cursor.setIndex( 0 );
01408         textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01409         cursor.setParag( parag );
01410         cursor.setIndex( 2 );
01411         textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01412         KCommand *cmd=txtObj->removeSelectedTextCommand( &cursor, KoTextObject::HighlightSelection  );
01413         // Adjust index
01414         index -= 2;
01415         if(cmd)
01416             macroCmd->addCommand(cmd);
01417 
01418         cursor.setParag( parag );
01419         cursor.setIndex( 0 );
01420         textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01421 
01422         cursor.setIndex( 2 );
01423         textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01424 
01425 
01426         KoParagCounter c;
01427         if( m_bulletStyle.isNull() && (ch == '*' || ch == '+' || ch == '-'))
01428         {
01429             if ( ch =='*')
01430             {
01431                 c.setNumbering( KoParagCounter::NUM_LIST );
01432                 c.setStyle( KoParagCounter::STYLE_DISCBULLET );
01433             }
01434             else if ( ch =='+' || ch=='-')
01435             {
01436                 c.setNumbering( KoParagCounter::NUM_LIST );
01437                 c.setStyle( KoParagCounter::STYLE_CUSTOMBULLET );
01438                 if ( ch =='-' )
01439                     c.setCustomBulletCharacter( '-' );
01440                 else if ( ch=='+')
01441                     c.setCustomBulletCharacter( '+' );
01442             }
01443         }
01444         else
01445         {
01446             c.setNumbering( KoParagCounter::NUM_LIST );
01447             c.setStyle( KoParagCounter::STYLE_CUSTOMBULLET );
01448             c.setCustomBulletCharacter( m_bulletStyle );
01449         }
01450         c.setSuffix(QString::null);
01451         cmd=txtObj->setCounterCommand( &cursor, c ,KoTextObject::HighlightSelection );
01452         if( cmd)
01453             macroCmd->addCommand(cmd);
01454         cursor.setParag( parag->next() );
01455         cursor.setIndex( 0 );
01456         textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01457         cursor.setIndex( 0 );
01458         textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01459         cmd=txtObj->setCounterCommand( &cursor, c ,KoTextObject::HighlightSelection );
01460         if(cmd)
01461             macroCmd->addCommand(cmd);
01462         return macroCmd;
01463     }
01464     return 0L;
01465 
01466 }
01467 
01468 KCommand *KoAutoFormat::doUseNumberStyle(KoTextCursor * /*textEditCursor*/, KoTextParag *parag, KoTextObject *txtObj, int& index )
01469 {
01470     KoTextDocument * textdoc = parag->textDocument();
01471     KoTextCursor cursor( parag->document() );
01472     KoTextString *s = parag->string();
01473     QString word;
01474     for ( int i = 0 ; i < s->length() - 1; i++ )
01475     {
01476         QChar ch = s->at( i ).c;
01477         if ( ch.isSpace() )
01478             break;
01479         word.append( ch );
01480     }
01481     QChar punct=word[word.length()-1];
01482     if( punct.isPunct() )
01483     {
01484         QString number=word.mid(0,word.length()-1);
01485         bool ok;
01486         uint val=number.toUInt(&ok);
01487         if( ok )
01488         {
01489             KMacroCommand *macroCmd = new KMacroCommand( i18n("Autocorrect (use number style)"));
01490             cursor.setParag( parag );
01491             cursor.setIndex( 0 );
01492             textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01493             cursor.setParag( parag );
01494             cursor.setIndex( word.length()+1 );
01495             textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01496             KCommand *cmd=txtObj->removeSelectedTextCommand( &cursor, KoTextObject::HighlightSelection  );
01497             // Adjust index
01498             index -= word.length()+1;
01499             if(cmd)
01500                 macroCmd->addCommand(cmd);
01501 
01502             // Apply counter to this paragraph
01503             cursor.setParag( parag );
01504             cursor.setIndex( 0 );
01505             textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01506 
01507             cursor.setIndex( 2 );
01508             textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01509 
01510             KoParagCounter c;
01511             c.setNumbering( KoParagCounter::NUM_LIST );
01512             c.setStyle( KoParagCounter::STYLE_NUM );
01513             c.setSuffix(QString( punct ));
01514             c.setStartNumber( (int)val);
01515 
01516             // Look at which number this parag will have without a restart counter flag,
01517             // to see if we need it. Thanks to Shaheed for number() taking a parag as param,
01518             // so that it works even if the parag doesn't have this counter yet!
01519             if ( c.number( parag ) != (int)val )
01520                 c.setRestartCounter( true );
01521 
01522             cmd=txtObj->setCounterCommand( &cursor, c, KoTextObject::HighlightSelection );
01523             if( cmd)
01524                 macroCmd->addCommand(cmd);
01525             // Apply counter to next paragraph too
01526             // but without restart
01527             c.setRestartCounter( false );
01528             cursor.setParag( parag->next() );
01529             cursor.setIndex( 0 );
01530             textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01531             cursor.setIndex( 0 );
01532             textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01533             cmd=txtObj->setCounterCommand( &cursor, c, KoTextObject::HighlightSelection );
01534             if(cmd)
01535                 macroCmd->addCommand(cmd);
01536             return macroCmd;
01537         }
01538     }
01539     return 0L;
01540 }
01541 
01542 
01543 KCommand * KoAutoFormat::doRemoveSpaceBeginEndLine( KoTextCursor *textEditCursor, KoTextParag *parag, KoTextObject *txtObj )
01544 {
01545     KoTextString *s = parag->string();
01546     KoTextDocument * textdoc = parag->textDocument();
01547     KoTextCursor cursor( parag->document() );
01548 
01549     KMacroCommand *macroCmd = 0L;
01550     // Cut away spaces at end of paragraph
01551     for ( int i = parag->string()->length()-1; i >= 0; --i )
01552     {
01553         QChar ch = s->at( i ).c;
01554         if( !ch.isSpace())
01555         {
01556             if( i == parag->string()->length()-1 )
01557                 break;
01558             cursor.setParag( parag );
01559             cursor.setIndex( i+1 );
01560             textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01561             cursor.setParag( parag );
01562             cursor.setIndex( parag->string()->length() -1); // -1 for the space QtRT always adds at the end.
01563             textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01564             KCommand *cmd=txtObj->replaceSelectionCommand( &cursor, "",KoTextObject::HighlightSelection , QString::null );
01565 
01566             if(cmd)
01567             {
01568                 if ( !macroCmd )
01569                     macroCmd = new KMacroCommand( i18n("Autocorrect (remove start and end line space)"));
01570                 macroCmd->addCommand(cmd);
01571             }
01572             break;
01573         }
01574     }
01575 
01576     s = parag->string();
01577 
01578     // Cut away spaces at start of parag.
01579     for ( int i = 0 ; i < parag->string()->length() ; i++ )
01580     {
01581         QChar ch = s->at( i ).c;
01582         if( !ch.isSpace())
01583         {
01584             if( i == 0 )
01585                 break;
01586 
01587             cursor.setParag( parag );
01588             cursor.setIndex( 0 );
01589             textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01590             cursor.setParag( parag );
01591             cursor.setIndex( i  );
01592             textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01593             KCommand *cmd=txtObj->replaceSelectionCommand( &cursor, "",KoTextObject::HighlightSelection , QString::null );
01594 
01595             if(cmd)
01596             {
01597                 if ( !macroCmd )
01598                     macroCmd = new KMacroCommand( i18n("Autocorrect (remove start and end line space)"));
01599                 macroCmd->addCommand(cmd);
01600             }
01601             break;
01602         }
01603     }
01604 
01605     if( macroCmd )
01606     {
01607         txtObj->emitHideCursor();
01608         textEditCursor->setParag( parag->next() );
01609         //textEditCursor->cursorgotoRight();
01610         txtObj->emitShowCursor();
01611     }
01612     return macroCmd;
01613 }
01614 
01615 KCommand *KoAutoFormat::doCapitalizeNameOfDays( KoTextCursor* textEditCursor, KoTextParag *parag, int index, const QString & word , KoTextObject *txtObj )
01616 {
01617     //m_cacheNameOfDays
01618     //todo
01619     int pos = m_cacheNameOfDays.findIndex( word.lower() );
01620     if ( pos == -1 )
01621         return 0L;
01622 
01623     KoTextDocument * textdoc = parag->textDocument();
01624     QString replaceStr= m_cacheNameOfDays[pos];
01625     int start = index - replaceStr.length();
01626     int length = replaceStr.length();
01627     if( word.at(0)==word.at(0).lower() )
01628     {
01629         KoTextCursor cursor( parag->document() );
01630         cursor.setParag( parag );
01631         cursor.setIndex( start );
01632         textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01633         cursor.setIndex( start + length );
01634         QString replacement = replaceStr.at(0).upper() + replaceStr.right( length-1 );
01635         textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01636         QString cmdName=i18n("Capitalize Name of Days");
01637         KCommand *cmd =txtObj->replaceSelectionCommand( textEditCursor, replacement,
01638                                                            KoTextObject::HighlightSelection,
01639                                                                 cmdName );
01640         txtObj->emitHideCursor();
01641         textEditCursor->gotoRight();
01642         txtObj->emitShowCursor();
01643         return cmd;
01644     }
01645     return 0L;
01646 }
01647 
01648 KCommand *KoAutoFormat::doAutoSuperScript( KoTextCursor* textEditCursor, KoTextParag *parag, int index, const QString & word , KoTextObject *txtObj )
01649 {
01650     KoAutoFormatEntryMap::Iterator it = m_superScriptEntries.begin();
01651     bool found = false;
01652     QString replace;
01653     for ( ; it != m_superScriptEntries.end() ; ++it )
01654     {
01655         if( it.key()==word)
01656         {
01657             replace = it.data().replace();
01658             found = true;
01659             break;
01660         }
01661         else if ( it.key()=="othernb")
01662         {
01663             QString tmp = it.data().replace();
01664             int pos = word.find( tmp );
01665             if( pos != -1)
01666             {
01667                 if( pos + tmp.length() == word.length())
01668                 {
01669                     bool ok;
01670                     word.left( pos ).toInt( &ok);
01671                     if( ok )
01672                     {
01673                         replace = tmp;
01674                         found = true;
01675                         break;
01676                     }
01677                 }
01678             }
01679         }
01680     }
01681     if (found )
01682     {
01683         KoTextDocument * textdoc = parag->textDocument();
01684 
01685         int start = index - replace.length();
01686         KoTextFormat * lastFormat = parag->at( start )->format();
01687         KoTextFormat * newFormat = new KoTextFormat(*lastFormat);
01688         KoTextCursor cursor( parag->document() );
01689 
01690         cursor.setParag( parag );
01691         cursor.setIndex( start );
01692         textdoc->setSelectionStart( KoTextObject::HighlightSelection, &cursor );
01693         cursor.setIndex( start + word.length() -1 );
01694         textdoc->setSelectionEnd( KoTextObject::HighlightSelection, &cursor );
01695         newFormat->setVAlign(KoTextFormat::AlignSuperScript);
01696         KCommand *cmd =txtObj->setFormatCommand( textEditCursor, 0L, newFormat, KoTextFormat::VAlign , false,KoTextObject::HighlightSelection  );
01697         textdoc->removeSelection( KoTextObject::HighlightSelection );
01698 
01699         return cmd;
01700     }
01701     return 0L;
01702 }
01703 
01704 bool KoAutoFormat::doIgnoreDoubleSpace( KoTextParag *parag, int index, QChar ch )
01705 {
01706     if( m_ignoreDoubleSpace && ch==' ' && index >=  0 )
01707     {
01708         KoTextString *s = parag->string();
01709         QChar ch = s->at( index ).c;
01710         if ( ch==' ' )
01711             return true;
01712     }
01713     return false;
01714 }
01715 
01716 void KoAutoFormat::configTypographicSimpleQuotes( TypographicQuotes _tq )
01717 {
01718     m_typographicSimpleQuotes = _tq;
01719 }
01720 
01721 void KoAutoFormat::configTypographicDoubleQuotes( TypographicQuotes _tq )
01722 {
01723     m_typographicDoubleQuotes = _tq;
01724 }
01725 
01726 void KoAutoFormat::configUpperCase( bool _uc )
01727 {
01728     m_convertUpperCase = _uc;
01729 }
01730 
01731 void KoAutoFormat::configUpperUpper( bool _uu )
01732 {
01733     m_convertUpperUpper = _uu;
01734 }
01735 
01736 void KoAutoFormat::configAdvancedAutocorrect( bool _aa )
01737 {
01738     m_advancedAutoCorrect = _aa;
01739 }
01740 
01741 void KoAutoFormat::configAutoDetectUrl(bool _au)
01742 {
01743     m_autoDetectUrl=_au;
01744 }
01745 
01746 void KoAutoFormat::configIgnoreDoubleSpace( bool _ids)
01747 {
01748     m_ignoreDoubleSpace=_ids;
01749 }
01750 
01751 void KoAutoFormat::configRemoveSpaceBeginEndLine( bool _space)
01752 {
01753     m_removeSpaceBeginEndLine=_space;
01754 }
01755 
01756 void KoAutoFormat::configUseBulletStyle( bool _ubs)
01757 {
01758     m_useBulletStyle=_ubs;
01759 }
01760 
01761 void KoAutoFormat::configBulletStyle( QChar b )
01762 {
01763     m_bulletStyle = b;
01764 }
01765 
01766 void KoAutoFormat::configAutoChangeFormat( bool b)
01767 {
01768     m_autoChangeFormat = b;
01769 }
01770 
01771 
01772 void KoAutoFormat::configAutoReplaceNumber( bool b )
01773 {
01774     m_autoReplaceNumber = b;
01775 }
01776 
01777 void KoAutoFormat::configAutoNumberStyle( bool b )
01778 {
01779     m_useAutoNumberStyle = b;
01780 }
01781 
01782 void KoAutoFormat::configCompletion( bool b )
01783 {
01784     m_completion = b;
01785 }
01786 
01787 void KoAutoFormat::configAppendSpace( bool b)
01788 {
01789     m_completionAppendSpace= b;
01790 }
01791 
01792 void KoAutoFormat::configMinWordLength( uint val )
01793 {
01794    m_minCompletionWordLength = val;
01795 }
01796 
01797 void KoAutoFormat::configNbMaxCompletionWord( uint val )
01798 {
01799     m_nbMaxCompletionWord = val;
01800 }
01801 
01802 
01803 void KoAutoFormat::configAddCompletionWord( bool b )
01804 {
01805     m_addCompletionWord= b;
01806 }
01807 
01808 bool KoAutoFormat::isUpper( const QChar &c )
01809 {
01810     return c.lower() != c;
01811 }
01812 
01813 bool KoAutoFormat::isLower( const QChar &c )
01814 {
01815     // Note that this is not the same as !isUpper !
01816     // For instance '1' is not lower nor upper,
01817     return c.upper() != c;
01818 }
01819 
01820 bool KoAutoFormat::isMark( const QChar &c )
01821 {
01822     return ( c == QChar( '.' ) ||
01823          c == QChar( '?' ) ||
01824          c == QChar( '!' ) );
01825 }
01826 
01827 bool KoAutoFormat::isSeparator( const QChar &c )
01828 {
01829     return ( !c.isLetter() && !c.isNumber() && !c.isDigit() );
01830 }
01831 
01832 void KoAutoFormat::buildMaxLen()
01833 {
01834     m_maxFindLength = 0;
01835 
01836     QDictIterator<KoAutoFormatEntry> it( m_entries );
01837     for( ; it.current(); ++it )
01838     m_maxFindLength = QMAX( m_maxFindLength, it.currentKey().length() );
01839 }
01840 
01841 QStringList KoAutoFormat::listCompletion() const
01842 {
01843    return m_listCompletion->items();
01844 }
01845 
01846 
01847 void KoAutoFormat::configIncludeTwoUpperUpperLetterException( bool b)
01848 {
01849     m_includeTwoUpperLetterException = b;
01850 }
01851 
01852 void KoAutoFormat::configIncludeAbbreviation( bool b )
01853 {
01854     m_includeAbbreviation = b;
01855 }
01856 
01857 void KoAutoFormat::configAutoSuperScript( bool b )
01858 {
01859     m_bAutoSuperScript = b;
01860 }
01861 
01862 void KoAutoFormat::configCorrectionWithFormat( bool b)
01863 {
01864     m_bAutoCorrectionWithFormat = b;
01865 }
01866 
01867 void KoAutoFormat::configCapitalizeNameOfDays( bool b)
01868 {
01869     m_bCapitalizeNameOfDays = b;
01870 }
01871 
01872 void KoAutoFormat::configAutoFormatLanguage( const QString &_lang)
01873 {
01874     m_autoFormatLanguage=_lang;
01875 }
01876 
01877 KCommand *KoAutoFormat::applyAutoFormat( KoTextObject * obj )
01878 {
01879     KoTextParag * parag = obj->textDocument()->firstParag();
01880     KMacroCommand *macro = 0L;
01881     while ( parag )
01882     {
01883         KCommand *cmd = scanParag( parag,obj );
01884         if ( cmd )
01885         {
01886             if ( !macro )
01887                 macro = new KMacroCommand( i18n("Apply Autoformat"));
01888             macro->addCommand( cmd);
01889         }
01890         parag = parag->next();
01891     }
01892     return macro;
01893 }
01894 
01895 KCommand *KoAutoFormat::scanParag( KoTextParag * parag, KoTextObject * obj )
01896 {
01897     KMacroCommand * macro = 0L;
01898     KoTextCursor *cursor = new KoTextCursor( obj->textDocument() );
01899 
01900     KoTextString *s = parag->string();
01901     for ( int i = 0; i < s->length(); i++ )
01902     {
01903         QChar ch = s->at( i ).c;
01904         if ( ch == '"' && m_typographicDoubleQuotes.replace )
01905         {
01906             KCommand *cmd =doTypographicQuotes( cursor, parag, i, obj, true /*double quote*/ );
01907             if ( cmd )
01908             {
01909                 if ( !macro )
01910                     macro = new KMacroCommand( i18n("Apply Autoformat"));
01911                 macro->addCommand( cmd );
01912             }
01913         }
01914         else if ( ch == '\'' && m_typographicDoubleQuotes.replace )
01915         {
01916             KCommand *cmd =doTypographicQuotes(  cursor, parag, i,obj, false /* simple quote*/ );
01917             if ( cmd )
01918             {
01919                 if ( !macro )
01920                     macro = new KMacroCommand( i18n("Apply Autoformat"));
01921                 macro->addCommand( cmd );
01922             }
01923         }
01924         else if( ch.isSpace())
01925         {
01926             //a link doesn't have a space
01927             //=>m_ignoreUpperCase = false
01928             m_ignoreUpperCase=false;
01929 
01930             QString word=getWordAfterSpace(parag,i);
01931 
01932             if ( m_autoChangeFormat && i > 3)
01933             {
01934                 KCommand *cmd =doAutoChangeFormat( cursor, parag,i, word, obj );
01935                 if ( cmd )
01936                 {
01937                     if ( !macro )
01938                         macro = new KMacroCommand( i18n("Apply Autoformat"));
01939                     macro->addCommand( cmd );
01940                 }
01941 
01942             }
01943             if ( m_autoDetectUrl && i > 0 )
01944             {
01945                 doAutoDetectUrl( cursor, parag,i, word, obj );
01946             }
01947             if ( m_autoReplaceNumber )
01948             {
01949                 KCommand *cmd = doAutoReplaceNumber( cursor, parag, i, word, obj );
01950                 if ( cmd )
01951                 {
01952                     if ( !macro )
01953                         macro = new KMacroCommand( i18n("Apply Autoformat"));
01954                     macro->addCommand( cmd );
01955                 }
01956             }
01957             if ( ( ch.isSpace() || ch.isPunct() ) && i > 0 )
01958             {
01959                 QString lastWord = getLastWord(parag, i);
01960                 //kdDebug(32500)<<" m_listCompletion->items() :"<<m_listCompletion->items()<<endl;
01961                 KMacroCommand *macro2 =0L;
01962                 int newPos = i;
01963                 KCommand *cmd = doAutoCorrect( cursor, parag, newPos , obj );
01964 
01965                 if( cmd )
01966                 {
01967                     if ( !macro2 )
01968                         macro2 =new KMacroCommand(i18n("Autocorrection"));
01969                     macro2->addCommand( cmd );
01970                 }
01971 
01972                 if ( m_bCapitalizeNameOfDays)
01973                 {
01974                     KCommand *cmd = doCapitalizeNameOfDays( cursor, parag, newPos, lastWord, obj  );
01975 
01976                     if( cmd )
01977                     {
01978                         if (!macro)
01979                             macro2 = new KMacroCommand(i18n("Autocorrection"));
01980                         macro2->addCommand( cmd );
01981                     }
01982                 }
01983 
01984                 if ( !m_ignoreUpperCase && (m_convertUpperUpper || m_convertUpperCase) )
01985                 {
01986                     lastWord = getLastWord(parag, newPos);
01987                     cmd = doUpperCase( cursor, parag, newPos, lastWord, obj );
01988                     if( cmd )
01989                     {
01990                         if ( !macro2 )
01991                             macro2 =new KMacroCommand(i18n("Autocorrection"));
01992                         macro2->addCommand( cmd );
01993                     }
01994                 }
01995                 if ( macro2 )
01996                 {
01997                     if ( !macro )
01998                         macro = new KMacroCommand( i18n("Apply Autoformat"));
01999                     macro->addCommand( macro2 );
02000                 }
02001                 if( m_bAutoSuperScript && m_superScriptEntries.count()>0)
02002                 {
02003                     KCommand * cmd =doAutoSuperScript( cursor, parag, newPos, lastWord, obj  );
02004                     if ( cmd )
02005                     {
02006                         if ( !macro )
02007                             macro = new KMacroCommand( i18n("Apply Autoformat"));
02008                         macro->addCommand( cmd );
02009                     }
02010                 }
02011             }
02012         }
02013     }
02014     delete cursor;
02015     return macro;
02016 }
02017 
02018 void KoAutoFormat::changeTextFormat(KoSearchContext *formatOptions, KoTextFormat * format, int & flags )
02019 {
02020     if (formatOptions )
02021     {
02022         if (formatOptions->m_optionsMask & KoSearchContext::Bold)
02023         {
02024             format->setBold( formatOptions->m_options & KoSearchContext::Bold);
02025             flags |=KoTextFormat::Bold;
02026         }
02027         if ( formatOptions->m_optionsMask & KoSearchContext::Size)
02028         {
02029             format->setPointSize( formatOptions->m_size );
02030             flags |=KoTextFormat::Size;
02031         }
02032         if ( formatOptions->m_optionsMask & KoSearchContext::Family)
02033         {
02034             format->setFamily( formatOptions->m_family );
02035             flags |=KoTextFormat::Family;
02036         }
02037         if ( formatOptions->m_optionsMask & KoSearchContext::Color)
02038         {
02039             format->setColor(formatOptions->m_color);
02040             flags |=KoTextFormat::Color;
02041         }
02042         if ( formatOptions->m_optionsMask & KoSearchContext::BgColor)
02043         {
02044             format->setTextBackgroundColor(formatOptions->m_backGroundColor);
02045             flags |=KoTextFormat::TextBackgroundColor;
02046         }
02047 
02048         if ( formatOptions->m_optionsMask & KoSearchContext::Italic)
02049         {
02050             format->setItalic( formatOptions->m_options & KoSearchContext::Italic);
02051             flags |=KoTextFormat::Italic;
02052         }
02053         if ( formatOptions->m_optionsMask & KoSearchContext::WordByWord)
02054         {
02055             format->setWordByWord( formatOptions->m_options & KoSearchContext::WordByWord );
02056             flags |=KoTextFormat::WordByWord;
02057         }
02058         if ( formatOptions->m_optionsMask & KoSearchContext::Shadow)
02059         {
02060             if ( formatOptions->m_options & KoSearchContext::Shadow )
02061                 format->setShadow( 1, 1, Qt::gray );
02062             else
02063                 format->setShadow( 0, 0, QColor() );
02064             flags |=KoTextFormat::ShadowText;
02065         }
02066 
02067         if ( formatOptions->m_optionsMask & KoSearchContext::Underline)
02068         {
02069             format->setUnderlineType(formatOptions->m_underline);
02070             flags |=KoTextFormat::ExtendUnderLine;
02071         }
02072         if ( formatOptions->m_optionsMask & KoSearchContext::StrikeOut)
02073         {
02074             format->setStrikeOutType(formatOptions->m_strikeOut);
02075             flags |= KoTextFormat::StrikeOut;
02076         }
02077         if ( formatOptions->m_optionsMask & KoSearchContext::VertAlign)
02078         {
02079             format->setVAlign(formatOptions->m_vertAlign);
02080             flags |=KoTextFormat::VAlign;
02081         }
02082         if ( formatOptions->m_optionsMask & KoSearchContext::Attribute)
02083         {
02084             format->setAttributeFont(formatOptions->m_attribute);
02085             flags |= KoTextFormat::Attribute;
02086         }
02087         if (formatOptions->m_optionsMask & KoSearchContext::Language)
02088         {
02089             flags |= KoTextFormat::Language;
02090             format->setLanguage( formatOptions->m_language );
02091         }
02092     }
02093 }
KDE Logo
This file is part of the documentation for lib Library Version 1.3.5.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Mar 20 14:25:24 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003