F:/KPlato/koffice/libs/kotext/KoTextObject.cpp

Aller à la documentation de ce fichier.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2001-2006 David Faure <faure@kde.org>
00003    Copyright (C) 2005 Martin Ellis <martin.ellis@kdemail.net>
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 "KoTextObject.h"
00022 #include "KoTextParag.h"
00023 #include "KoParagCounter.h"
00024 #include "KoTextZoomHandler.h"
00025 #include "KoTextCommand.h"
00026 #include "KoStyleCollection.h"
00027 #include "KoFontDia.h"
00028 #include "KoOasisContext.h"
00029 #include "KoVariable.h"
00030 #include "KoAutoFormat.h"
00031 #include <KoXmlNS.h>
00032 #include <KoDom.h>
00033 
00034 #include <klocale.h>
00035 #include <kdebug.h>
00036 #include <kapplication.h>
00037 
00038 #include <QTimer>
00039 #include <QRegExp>
00040 #include <QProgressDialog>
00041 //Added by qt3to4:
00042 #include <QByteArray>
00043 #include <Q3MemArray>
00044 #include <Q3ValueList>
00045 #include <QMimeData>
00046 
00047 #include <assert.h>
00048 
00049 //#define DEBUG_FORMATS
00050 //#define DEBUG_FORMAT_MORE
00051 
00052 const char KoTextObject::s_customItemChar = '#'; // Has to be transparent to kspell but still be saved (not space)
00053 
00054 struct KoTextObject::KoTextObjectPrivate
00055 {
00056 public:
00057     KoTextObjectPrivate() {
00058         afterFormattingEmitted = false;
00059         abortFormatting = false;
00060     }
00061     bool afterFormattingEmitted;
00062     bool abortFormatting;
00063 };
00064 
00065 KoTextObject::KoTextObject( KoTextZoomHandler *zh, const QFont& defaultFont,
00066                             const QString &defaultLanguage, bool hyphenation,
00067                             KoParagStyle* defaultStyle, int tabStopWidth,
00068                             QObject* parent, const char* /*name*/ )
00069     : QObject( parent ), m_defaultStyle( defaultStyle ), undoRedoInfo( this )
00070 {
00071     textdoc = new KoTextDocument( zh, new KoTextFormatCollection( defaultFont, QColor(),defaultLanguage, hyphenation ) );
00072     if ( tabStopWidth != -1 )
00073         textdoc->setTabStops( tabStopWidth );
00074     init();
00075 }
00076 
00077 KoTextObject::KoTextObject( KoTextDocument* _textdoc, KoParagStyle* defaultStyle,
00078                             QObject* parent, const char* /*name*/ )
00079  : QObject( parent ), m_defaultStyle( defaultStyle ), undoRedoInfo( this )
00080 {
00081     textdoc = _textdoc;
00082     init();
00083 }
00084 
00085 void KoTextObject::init()
00086 {
00087     d = new KoTextObjectPrivate;
00088     m_needsSpellCheck = true;
00089     m_protectContent = false;
00090     m_visible=true;
00091     m_availableHeight = -1;
00092     m_lastFormatted = textdoc->firstParag();
00093     m_highlightSelectionAdded = false;
00094     interval = 0;
00095     startTimer = new QTimer( this );
00096     connect( startTimer, SIGNAL( timeout() ),
00097              this, SLOT( doChangeInterval() ) );
00098 
00099     formatTimer = new QTimer( this );
00100     connect( formatTimer, SIGNAL( timeout() ),
00101              this, SLOT( formatMore() ) );
00102 
00103     // Apply default style to initial paragraph
00104     if ( m_lastFormatted && m_defaultStyle )
00105         m_lastFormatted->applyStyle( m_defaultStyle );
00106 
00107     connect( textdoc, SIGNAL( paragraphDeleted( KoTextParag* ) ),
00108              this, SIGNAL( paragraphDeleted( KoTextParag* ) ) );
00109     connect( textdoc, SIGNAL( paragraphDeleted( KoTextParag* ) ),
00110              this, SLOT( slotParagraphDeleted( KoTextParag* ) ) );
00111     connect( textdoc, SIGNAL( newCommand( KCommand* ) ),
00112              this, SIGNAL( newCommand( KCommand* ) ) );
00113     connect( textdoc, SIGNAL( repaintChanged() ),
00114              this, SLOT( emitRepaintChanged() ) );
00115 
00116     connect( this, SIGNAL(paragraphModified( KoTextParag*, int, int , int ) ),
00117              this, SLOT(slotParagraphModified(KoTextParag *, int, int , int)));
00118     connect( this, SIGNAL(paragraphCreated( KoTextParag* )),
00119              this, SLOT(slotParagraphCreated(KoTextParag *)));
00120 }
00121 
00122 KoTextObject::~KoTextObject()
00123 {
00124     // Avoid crash in KoTextString::clear -> accessing deleted format collection,
00125     // if ~UndoRedoInfo still has a string to clear.
00126     undoRedoInfo.clear();
00127     delete textdoc; textdoc = 0;
00128     delete d;
00129 }
00130 
00131 int KoTextObject::availableHeight() const
00132 {
00133     if ( m_availableHeight == -1 )
00134         emit const_cast<KoTextObject *>(this)->availableHeightNeeded();
00135     Q_ASSERT( m_availableHeight != -1 );
00136     return m_availableHeight;
00137 }
00138 
00139 void KoTextObject::slotParagraphModified(KoTextParag * /*parag*/, int /*ParagModifyType*/ _type, int , int)
00140 {
00141     if ( _type == ChangeFormat)
00142         return;
00143     m_needsSpellCheck = true;
00144 }
00145 
00146 void KoTextObject::slotParagraphCreated(KoTextParag * /*parag*/)
00147 {
00148     m_needsSpellCheck = true;
00149 }
00150 
00151 void KoTextObject::slotParagraphDeleted(KoTextParag * parag)
00152 {
00153     if ( m_lastFormatted == parag )
00154         m_lastFormatted = parag->next();
00155 
00156     // ### TODO: remove from kwbgspellcheck
00157     // not needed, since KoTextIterator takes care of that.
00158 }
00159 
00160 int KoTextObject::docFontSize( KoTextFormat * format ) const
00161 {
00162     Q_ASSERT( format );
00163     return format->pointSize();
00164 }
00165 
00166 int KoTextObject::zoomedFontSize( int docFontSize ) const
00167 {
00168     kDebug(32500) << "KoTextObject::zoomedFontSize: docFontSize=" << docFontSize
00169               << " - in LU: " << KoTextZoomHandler::ptToLayoutUnitPt( docFontSize ) << endl;
00170     return KoTextZoomHandler::ptToLayoutUnitPt( docFontSize );
00171 }
00172 
00173 // A visitor that looks for custom items in e.g. a selection
00174 class KoHasCustomItemVisitor : public KoParagVisitor
00175 {
00176 public:
00177     KoHasCustomItemVisitor() : KoParagVisitor() { }
00178     // returns false when cancelled, i.e. an item was _found_, and true if it proceeded to the end(!)
00179     virtual bool visit( KoTextParag *parag, int start, int end )
00180     {
00181         for ( int i = start ; i < end ; ++i )
00182         {
00183             KoTextStringChar * ch = parag->at( i );
00184             if ( ch->isCustom() )
00185                 return false; // found one -> stop here
00186         }
00187         return true;
00188     }
00189 };
00190 
00191 bool KoTextObject::selectionHasCustomItems( KoTextDocument::SelectionId selectionId ) const
00192 {
00193     KoHasCustomItemVisitor visitor;
00194     bool noneFound = textdoc->visitSelection( selectionId, &visitor );
00195     return !noneFound;
00196 }
00197 
00198 void KoTextObject::slotAfterUndoRedo()
00199 {
00200     formatMore( 2 );
00201     emit repaintChanged( this );
00202     emit updateUI( true );
00203     emit showCursor();
00204     emit ensureCursorVisible();
00205 }
00206 
00207 void KoTextObject::clearUndoRedoInfo()
00208 {
00209     undoRedoInfo.clear();
00210 }
00211 
00212 
00213 void KoTextObject::checkUndoRedoInfo( KoTextCursor * cursor, UndoRedoInfo::Type t )
00214 {
00215     if ( undoRedoInfo.valid() && ( t != undoRedoInfo.type || cursor != undoRedoInfo.cursor ) ) {
00216         undoRedoInfo.clear();
00217     }
00218     undoRedoInfo.type = t;
00219     undoRedoInfo.cursor = cursor;
00220 }
00221 
00222 void KoTextObject::undo()
00223 {
00224     undoRedoInfo.clear();
00225     emit hideCursor();
00226     KoTextCursor *cursor = new KoTextCursor( textdoc ); // Kindof a dummy cursor
00227     KoTextCursor *c = textdoc->undo( cursor );
00228     if ( !c ) {
00229         delete cursor;
00230         emit showCursor();
00231         return;
00232     }
00233     // We have to set this new cursor position in all views :(
00234     // It sucks a bit for useability, but otherwise one view might still have
00235     // a cursor inside a deleted paragraph -> crash.
00236     emit setCursor( c );
00237     setLastFormattedParag( textdoc->firstParag() );
00238     delete cursor;
00239     QTimer::singleShot( 0, this, SLOT( slotAfterUndoRedo() ) );
00240 }
00241 
00242 void KoTextObject::redo()
00243 {
00244     undoRedoInfo.clear();
00245     emit hideCursor();
00246     KoTextCursor *cursor = new KoTextCursor( textdoc ); // Kindof a dummy cursor
00247     KoTextCursor *c = textdoc->redo( cursor );
00248     if ( !c ) {
00249         delete cursor;
00250         emit showCursor();
00251         return;
00252     }
00253     emit setCursor( c ); // see undo
00254     setLastFormattedParag( textdoc->firstParag() );
00255     delete cursor;
00256     QTimer::singleShot( 0, this, SLOT( slotAfterUndoRedo() ) );
00257 }
00258 
00259 KoTextObject::UndoRedoInfo::UndoRedoInfo( KoTextObject *to )
00260     : type( Invalid ), textobj(to), cursor( 0 )
00261 {
00262     text = QString::null;
00263     id = -1;
00264     index = -1;
00265     placeHolderCmd = 0L;
00266 }
00267 
00268 bool KoTextObject::UndoRedoInfo::valid() const
00269 {
00270     return text.length() > 0 && id >= 0 && index >= 0;
00271 }
00272 
00273 void KoTextObject::UndoRedoInfo::clear()
00274 {
00275     if ( valid() ) {
00276         KoTextDocument* textdoc = textobj->textDocument();
00277         switch (type) {
00278             case Insert:
00279             case Return:
00280             {
00281                 KoTextDocCommand * cmd = new KoTextInsertCommand( textdoc, id, index, text.rawData(), customItemsMap, oldParagLayouts );
00282                 textdoc->addCommand( cmd );
00283                 Q_ASSERT( placeHolderCmd );
00284                 // Inserting any custom items -> macro command, to let custom items add their command
00285                 if ( !customItemsMap.isEmpty() )
00286                 {
00287                     CustomItemsMap::Iterator it = customItemsMap.begin();
00288                     for ( ; it != customItemsMap.end(); ++it )
00289                     {
00290                         KoTextCustomItem * item = it.value();
00291                         KCommand * itemCmd = item->createCommand();
00292                         if ( itemCmd )
00293                             placeHolderCmd->addCommand( itemCmd );
00294                     }
00295                     placeHolderCmd->addCommand( new KoTextCommand( textobj, /*cmd, */QString::null ) );
00296                 }
00297                 else
00298                 {
00299                     placeHolderCmd->addCommand( new KoTextCommand( textobj, /*cmd, */QString::null ) );
00300                 }
00301             } break;
00302             case Delete:
00303             case RemoveSelected:
00304             {
00305                 KoTextDocCommand * cmd = textobj->deleteTextCommand( textdoc, id, index, text.rawData(), customItemsMap, oldParagLayouts );
00306                 textdoc->addCommand( cmd );
00307                 Q_ASSERT( placeHolderCmd );
00308                 placeHolderCmd->addCommand( new KoTextCommand( textobj, /*cmd, */QString::null ) );
00309                 // Deleting any custom items -> let them add their command
00310                 if ( !customItemsMap.isEmpty() )
00311                 {
00312                     customItemsMap.deleteAll( placeHolderCmd );
00313                 }
00314            } break;
00315             case Invalid:
00316                 break;
00317         }
00318     }
00319     type = Invalid;
00320     // Before Qt-3.2.0, this called KoTextString::clear(), which called resize(0) on the array, which _detached_. Tricky.
00321     // Since Qt-3.2.0, resize(0) doesn't detach anymore -> KoTextDocDeleteCommand calls copy() itself.
00322     text = QString::null;
00323     id = -1;
00324     index = -1;
00325     oldParagLayouts.clear();
00326     customItemsMap.clear();
00327     placeHolderCmd = 0L;
00328 }
00329 
00330 void KoTextObject::copyCharFormatting( KoTextParag *parag, int position, int index /*in text*/, bool moveCustomItems )
00331 {
00332     KoTextStringChar * ch = parag->at( position );
00333     if ( ch->format() ) {
00334         ch->format()->addRef();
00335         undoRedoInfo.text.at( index ).setFormat( ch->format() );
00336     }
00337     if ( ch->isCustom() )
00338     {
00339         kDebug(32500) << "KoTextObject::copyCharFormatting moving custom item " << ch->customItem() << " to text's " << index << " char"  << endl;
00340         undoRedoInfo.customItemsMap.insert( index, ch->customItem() );
00341         // We copy the custom item to customItemsMap in all cases (see setFormat)
00342         // We only remove from 'ch' if moveCustomItems was specified
00343         if ( moveCustomItems )
00344             parag->removeCustomItem(position);
00345         //ch->loseCustomItem();
00346     }
00347 }
00348 
00349 // Based on QTextView::readFormats - with all code duplication moved to copyCharFormatting
00350 void KoTextObject::readFormats( KoTextCursor &c1, KoTextCursor &c2, bool copyParagLayouts, bool moveCustomItems )
00351 {
00352     //kDebug(32500) << "KoTextObject::readFormats moveCustomItems=" << moveCustomItems << endl;
00353     int oldLen = undoRedoInfo.text.length();
00354     if ( c1.parag() == c2.parag() ) {
00355         undoRedoInfo.text += c1.parag()->string()->toString().mid( c1.index(), c2.index() - c1.index() );
00356         for ( int i = c1.index(); i < c2.index(); ++i )
00357             copyCharFormatting( c1.parag(), i, oldLen + i - c1.index(), moveCustomItems );
00358     } else {
00359         int lastIndex = oldLen;
00360         int i;
00361         //kDebug(32500) << "KoTextObject::readFormats copying from " << c1.index() << " to " << c1.parag()->length()-1 << " into lastIndex=" << lastIndex << endl;
00362         // Replace the trailing spaces with '\n'. That char carries the formatting for the trailing space.
00363         undoRedoInfo.text += c1.parag()->string()->toString().mid( c1.index(), c1.parag()->length() - 1 - c1.index() ) + '\n';
00364         for ( i = c1.index(); i < c1.parag()->length(); ++i, ++lastIndex )
00365             copyCharFormatting( c1.parag(), i, lastIndex, moveCustomItems );
00366         //++lastIndex; // skip the '\n'.
00367         KoTextParag *p = c1.parag()->next();
00368         while ( p && p != c2.parag() ) {
00369             undoRedoInfo.text += p->string()->toString().left( p->length() - 1 ) + '\n';
00370             //kDebug(32500) << "KoTextObject::readFormats (mid) copying from 0 to "  << p->length()-1 << " into i+" << lastIndex << endl;
00371             for ( i = 0; i < p->length(); ++i )
00372                 copyCharFormatting( p, i, i + lastIndex, moveCustomItems );
00373             lastIndex += p->length(); // + 1; // skip the '\n'
00374             //kDebug(32500) << "KoTextObject::readFormats lastIndex now " << lastIndex << " - text is now " << undoRedoInfo.text.toString() << endl;
00375             p = p->next();
00376         }
00377         //kDebug(32500) << "KoTextObject::readFormats copying [last] from 0 to " << c2.index() << " into i+" << lastIndex << endl;
00378         undoRedoInfo.text += c2.parag()->string()->toString().left( c2.index() );
00379         for ( i = 0; i < c2.index(); ++i )
00380             copyCharFormatting( c2.parag(), i, i + lastIndex, moveCustomItems );
00381     }
00382 
00383     if ( copyParagLayouts ) {
00384         KoTextParag *p = c1.parag();
00385         while ( p ) {
00386             undoRedoInfo.oldParagLayouts << p->paragLayout();
00387             if ( p == c2.parag() )
00388                 break;
00389             p = p->next();
00390         }
00391     }
00392 }
00393 
00394 void KoTextObject::newPlaceHolderCommand( const QString & name )
00395 {
00396     Q_ASSERT( !undoRedoInfo.placeHolderCmd );
00397     if ( undoRedoInfo.placeHolderCmd ) kDebug(32500) << kBacktrace();
00398     undoRedoInfo.placeHolderCmd = new KMacroCommand( name );
00399     emit newCommand( undoRedoInfo.placeHolderCmd );
00400 }
00401 
00402 void KoTextObject::storeParagUndoRedoInfo( KoTextCursor * cursor, KoTextDocument::SelectionId selectionId )
00403 {
00404     undoRedoInfo.clear();
00405     undoRedoInfo.oldParagLayouts.clear();
00406     undoRedoInfo.text = " ";
00407     undoRedoInfo.index = 1;
00408     if ( cursor && !textdoc->hasSelection( selectionId, true ) ) {
00409         KoTextParag * p = cursor->parag();
00410         undoRedoInfo.id = p->paragId();
00411         undoRedoInfo.eid = p->paragId();
00412         undoRedoInfo.oldParagLayouts << p->paragLayout();
00413     }
00414     else{
00415         Q_ASSERT( textdoc->hasSelection( selectionId, true ) );
00416         KoTextParag *start = textdoc->selectionStart( selectionId );
00417         KoTextParag *end = textdoc->selectionEnd( selectionId );
00418         undoRedoInfo.id = start->paragId();
00419         undoRedoInfo.eid = end->paragId();
00420         for ( ; start && start != end->next() ; start = start->next() )
00421         {
00422             undoRedoInfo.oldParagLayouts << start->paragLayout();
00423             //kDebug(32500) << "KoTextObject:storeParagUndoRedoInfo storing counter " << start->paragLayout().counter.counterType << endl;
00424         }
00425     }
00426 }
00427 
00428 void KoTextObject::doKeyboardAction( KoTextCursor * cursor, KoTextFormat * & /*currentFormat*/, KeyboardAction action )
00429 {
00430     KoTextParag * parag = cursor->parag();
00431     setLastFormattedParag( parag );
00432     emit hideCursor();
00433     bool doUpdateCurrentFormat = true;
00434     switch ( action ) {
00435     case ActionDelete: {
00436         checkUndoRedoInfo( cursor, UndoRedoInfo::Delete );
00437         if ( !undoRedoInfo.valid() ) {
00438             newPlaceHolderCommand( i18n("Delete Text") );
00439             undoRedoInfo.id = parag->paragId();
00440             undoRedoInfo.index = cursor->index();
00441             undoRedoInfo.text = QString::null;
00442             undoRedoInfo.oldParagLayouts << parag->paragLayout();
00443         }
00444         if ( !cursor->atParagEnd() )
00445         {
00446             KoTextStringChar * ch = parag->at( cursor->index() );
00447             undoRedoInfo.text += ch->c;
00448             copyCharFormatting( parag, cursor->index(), undoRedoInfo.text.length()-1, true );
00449         }
00450         KoParagLayout paragLayout;
00451         if ( parag->next() )
00452             paragLayout = parag->next()->paragLayout();
00453 
00454         KoTextParag *old = cursor->parag();
00455         if ( cursor->remove() ) {
00456             if ( old != cursor->parag() && m_lastFormatted == old ) // 'old' has been deleted
00457                 m_lastFormatted = cursor->parag() ? cursor->parag()->prev() : 0;
00458             undoRedoInfo.text += "\n";
00459             undoRedoInfo.oldParagLayouts << paragLayout;
00460         } else
00461             emit paragraphModified( old, RemoveChar, cursor->index(), 1 );
00462     } break;
00463     case ActionBackspace: {
00464         // Remove counter
00465         if ( parag->counter() && parag->counter()->style() != KoParagCounter::STYLE_NONE && cursor->index() == 0 ) {
00466             // parag->decDepth(); // We don't have support for nested lists at the moment
00467                                   // (only in titles, but you don't want Backspace to move it up)
00468             KoParagCounter c;
00469             c.setDepth( parag->counter()->depth() );
00470             KCommand *cmd=setCounterCommand( cursor, c );
00471             if(cmd)
00472                 emit newCommand(cmd);
00473         }
00474         else if ( !cursor->atParagStart() )
00475         {
00476             checkUndoRedoInfo( cursor, UndoRedoInfo::Delete );
00477             if ( !undoRedoInfo.valid() ) {
00478                 newPlaceHolderCommand( i18n("Delete Text") );
00479                 undoRedoInfo.id = parag->paragId();
00480                 undoRedoInfo.index = cursor->index();
00481                 undoRedoInfo.text = QString::null;
00482                 undoRedoInfo.oldParagLayouts << parag->paragLayout();
00483             }
00484             undoRedoInfo.text.insert( 0, cursor->parag()->at( cursor->index()-1 ) );
00485             copyCharFormatting( cursor->parag(), cursor->index()-1, 0, true );
00486             undoRedoInfo.index = cursor->index()-1;
00487             //KoParagLayout paragLayout = cursor->parag()->paragLayout();
00488             cursor->removePreviousChar();
00489             emit paragraphModified( cursor->parag(), RemoveChar, cursor->index(),1 );
00490             m_lastFormatted = cursor->parag();
00491         } else if ( parag->prev() ) { // joining paragraphs
00492             emit paragraphDeleted( cursor->parag() );
00493             clearUndoRedoInfo();
00494             textdoc->setSelectionStart( KoTextDocument::Temp, cursor );
00495             cursor->gotoPreviousLetter();
00496             textdoc->setSelectionEnd( KoTextDocument::Temp, cursor );
00497             removeSelectedText( cursor, KoTextDocument::Temp, i18n( "Delete Text" ) );
00498             emit paragraphModified( cursor->parag(), AddChar, cursor->index(), cursor->parag()->length() - cursor->index() );
00499         }
00500     } break;
00501     case ActionReturn: {
00502         checkUndoRedoInfo( cursor, UndoRedoInfo::Return );
00503         if ( !undoRedoInfo.valid() ) {
00504             newPlaceHolderCommand( i18n("Insert Text") );
00505             undoRedoInfo.id = cursor->parag()->paragId();
00506             undoRedoInfo.index = cursor->index();
00507             undoRedoInfo.text = QString::null;
00508         }
00509         undoRedoInfo.text += "\n";
00510         if ( cursor->parag() )
00511         {
00512                 QString last_line = cursor->parag()->toString();
00513                 last_line.remove(0,last_line.indexOf(' ')+1);
00514 
00515                 if( last_line.isEmpty() && cursor->parag()->counter() && cursor->parag()->counter()->numbering() == KoParagCounter::NUM_LIST ) //if the previous line the in paragraph is empty
00516                 {
00517                         KoParagCounter c;
00518                         KCommand *cmd=setCounterCommand( cursor, c );
00519                         if(cmd)
00520                                 emit newCommand(cmd);
00521                         setLastFormattedParag( cursor->parag() );
00522                         cursor->parag()->setNoCounter();
00523 
00524                         formatMore( 2 );
00525                         emit repaintChanged( this );
00526                         emit ensureCursorVisible();
00527                         emit showCursor();
00528                         emit updateUI( doUpdateCurrentFormat );
00529                         return;
00530                 }
00531                 else
00532                         cursor->splitAndInsertEmptyParag();
00533         }
00534 
00535         Q_ASSERT( cursor->parag()->prev() );
00536         setLastFormattedParag( cursor->parag() );
00537 
00538         doUpdateCurrentFormat = false;
00539         KoParagStyle * style = cursor->parag()->prev()->style();
00540         if ( style )
00541         {
00542             KoParagStyle * newStyle = style->followingStyle();
00543             if ( newStyle && style != newStyle ) // different "following style" applied
00544             {
00545                 doUpdateCurrentFormat = true;
00546                 //currentFormat = textdoc->formatCollection()->format( cursor->parag()->paragFormat() );
00547                 //kDebug(32500) << "KoTextFrameSet::doKeyboardAction currentFormat=" << currentFormat << " " << currentFormat->key() << endl;
00548             }
00549         }
00550         if ( cursor->parag()->joinBorder() && cursor->parag()->bottomBorder().width() > 0 )
00551             cursor->parag()->prev()->setChanged( true );
00552         if ( cursor->parag()->joinBorder() && cursor->parag()->next() && cursor->parag()->next()->joinBorder() && cursor->parag()->bottomBorder() == cursor->parag()->next()->bottomBorder())
00553             cursor->parag()->next()->setChanged( true );
00554         emit paragraphCreated( cursor->parag() );
00555 
00556     } break;
00557     case ActionKill:
00558         // Nothing to kill if at end of very last paragraph
00559         if ( !cursor->atParagEnd() || cursor->parag()->next() ) {
00560             checkUndoRedoInfo( cursor, UndoRedoInfo::Delete );
00561             if ( !undoRedoInfo.valid() ) {
00562                 newPlaceHolderCommand( i18n("Delete Text") );
00563                 undoRedoInfo.id = cursor->parag()->paragId();
00564                 undoRedoInfo.index = cursor->index();
00565                 undoRedoInfo.text = QString::null;
00566                 undoRedoInfo.oldParagLayouts << parag->paragLayout();
00567             }
00568             if ( cursor->atParagEnd() ) {
00569                 // Get paraglayout from next parag (next can't be 0 here)
00570                 KoParagLayout paragLayout = parag->next()->paragLayout();
00571                 if ( cursor->remove() )
00572                 {
00573                     m_lastFormatted = cursor->parag();
00574                     undoRedoInfo.text += "\n";
00575                     undoRedoInfo.oldParagLayouts << paragLayout;
00576                 }
00577             } else {
00578                 int oldLen = undoRedoInfo.text.length();
00579                 undoRedoInfo.text += cursor->parag()->string()->toString().mid( cursor->index() );
00580                 for ( int i = cursor->index(); i < cursor->parag()->length(); ++i )
00581                     copyCharFormatting( cursor->parag(), i, oldLen + i - cursor->index(), true );
00582                 cursor->killLine();
00583                 emit paragraphModified( cursor->parag(), RemoveChar, cursor->index(), cursor->parag()->length()-cursor->index() );
00584             }
00585         }
00586         break;
00587     }
00588 
00589     if ( !undoRedoInfo.customItemsMap.isEmpty() )
00590         clearUndoRedoInfo();
00591 
00592     formatMore( 2 );
00593     emit repaintChanged( this );
00594     emit ensureCursorVisible();
00595     emit showCursor();
00596     emit updateUI( doUpdateCurrentFormat );
00597 }
00598 
00599 void KoTextObject::insert( KoTextCursor * cursor, KoTextFormat * currentFormat,
00600                            const QString &txt, const QString & commandName, KoTextDocument::SelectionId selectionId,
00601                            int insertFlags, CustomItemsMap customItemsMap )
00602 {
00603     if ( protectContent() )
00604         return;
00605     const bool checkNewLine = insertFlags & CheckNewLine;
00606     const bool removeSelected = ( insertFlags & DoNotRemoveSelected ) == 0;
00607     const bool repaint = ( insertFlags & DoNotRepaint ) == 0;
00608     //kDebug(32500) << "KoTextObject::insert txt=" << txt << endl;
00609     bool tinyRepaint = !checkNewLine;
00610     if ( repaint )
00611         emit hideCursor();
00612     if ( textdoc->hasSelection( selectionId, true ) && removeSelected ) {
00613         kDebug() << k_funcinfo << "removing selection " << selectionId << endl;
00614         // call replaceSelectionCommand, which will call insert() back, but this time without a selection.
00615         emitNewCommand(replaceSelectionCommand( cursor, txt, commandName, selectionId, insertFlags, customItemsMap ));
00616         return;
00617     }
00618     // Now implement overwrite mode, similarly.
00619     if ( insertFlags & OverwriteMode ) {
00620         textdoc->setSelectionStart( KoTextDocument::Temp, cursor );
00621         KoTextCursor oc = *cursor;
00622         kDebug(32500) << "overwrite: going to insert " << txt.length() << " chars; idx=" << oc.index() << endl;
00623         oc.setIndex( qMin( oc.index() + (int)txt.length(), oc.parag()->lastCharPos() + 1 ) );
00624         kDebug(32500) << "overwrite: removing from " << cursor->index() << " to " << oc.index() << endl;
00625         if ( oc.index() > cursor->index() )
00626         {
00627             textdoc->setSelectionEnd( KoTextDocument::Temp, &oc );
00628             int newInsertFlags = insertFlags & ~OverwriteMode;
00629             newInsertFlags &= ~DoNotRemoveSelected;
00630             emitNewCommand(replaceSelectionCommand( cursor, txt, commandName, KoTextDocument::Temp, newInsertFlags, customItemsMap ));
00631             return;
00632         }
00633     }
00634     KoTextCursor c2 = *cursor;
00635     // Make everything ready for undo/redo (new command, or add to current one)
00636     if ( !customItemsMap.isEmpty() )
00637         clearUndoRedoInfo();
00638     checkUndoRedoInfo( cursor, UndoRedoInfo::Insert );
00639     if ( !undoRedoInfo.valid() ) {
00640         if ( !commandName.isNull() ) // see replace-selection
00641             newPlaceHolderCommand( commandName );
00642         undoRedoInfo.id = cursor->parag()->paragId();
00643         undoRedoInfo.index = cursor->index();
00644         undoRedoInfo.text = QString::null;
00645     }
00646     int oldLen = undoRedoInfo.text.length();
00647     KoTextCursor oldCursor = *cursor;
00648     bool wasChanged = cursor->parag()->hasChanged();
00649     int origLine; // the line the cursor was on before the insert
00650     oldCursor.parag()->lineStartOfChar( oldCursor.index(), 0, &origLine );
00651 
00652     // insert the text - finally!
00653     cursor->insert( txt, checkNewLine );
00654 
00655     setLastFormattedParag( checkNewLine ? oldCursor.parag() : cursor->parag() );
00656 
00657     if ( !customItemsMap.isEmpty() ) {
00658         customItemsMap.insertItems( oldCursor, txt.length() );
00659         undoRedoInfo.customItemsMap = customItemsMap;
00660         tinyRepaint = false;
00661     }
00662 
00663     textdoc->setSelectionStart( KoTextDocument::Temp, &oldCursor );
00664     textdoc->setSelectionEnd( KoTextDocument::Temp, cursor );
00665     //kDebug(32500) << "KoTextObject::insert setting format " << currentFormat << endl;
00666     textdoc->setFormat( KoTextDocument::Temp, currentFormat, KoTextFormat::Format );
00667     textdoc->setFormat( KoTextDocument::InputMethodPreedit, currentFormat, KoTextFormat::Format );
00668     textdoc->removeSelection( KoTextDocument::Temp );
00669 
00670     if ( !customItemsMap.isEmpty() ) {
00671         // Some custom items (e.g. variables) depend on the format
00672         CustomItemsMap::Iterator it = customItemsMap.begin();
00673         for ( ; it != customItemsMap.end(); ++it )
00674             it.value()->resize();
00675     }
00676 
00677     // Speed optimization: if we only type a char, and it doesn't
00678     // invalidate the next parag, only format the current one
00679     // ### This idea is wrong. E.g. when the last parag grows and must create a new page.
00680 #if 0
00681     KoTextParag *parag = cursor->parag();
00682     if ( !checkNewLine && m_lastFormatted == parag && ( !parag->next() || parag->next()->isValid() ) )
00683     {
00684         parag->format();
00685         m_lastFormatted = m_lastFormatted->next();
00686     }
00687 #endif
00688     // Call formatMore until necessary. This will create new pages if needed.
00689     // Doing this here means callers don't have to do it, and cursor can be positionned correctly.
00690     ensureFormatted( cursor->parag() );
00691 
00692     // Speed optimization: if we only type a char, only repaint from current line
00693     // (In fact the one before. When typing a space, a word could move up to the
00694     // line before, we need to repaint it too...)
00695     if ( !checkNewLine && tinyRepaint && !wasChanged )
00696     {
00697         // insert() called format() which called setChanged().
00698         // We're reverting that, and calling setLineChanged() only.
00699         Q_ASSERT( cursor->parag() == oldCursor.parag() ); // no newline!
00700         KoTextParag* parag = cursor->parag();
00701         // If the new char led to a new line,
00702         // the wordwrap could have changed on the line above
00703         // This is why we use origLine and not calling lineStartOfChar here.
00704         parag->setChanged( false );
00705         parag->setLineChanged( origLine - 1 ); // if origLine=0, it'll pass -1, which is 'all'
00706     }
00707 
00708     if ( repaint ) {
00709         emit repaintChanged( this );
00710         emit ensureCursorVisible();
00711         emit showCursor();
00712         // we typed the first char of a paragraph in AlignAuto mode -> show correct alignment in UI
00713         if ( oldCursor.index() == 0 && oldCursor.parag()->alignment() == Qt::AlignLeft )
00714             emit updateUI( true );
00715 
00716     }
00717     undoRedoInfo.text += txt;
00718     for ( int i = 0; i < (int)txt.length(); ++i ) {
00719         if ( txt[ oldLen + i ] != '\n' )
00720             copyCharFormatting( c2.parag(), c2.index(), oldLen + i, false );
00721         c2.gotoNextLetter();
00722     }
00723 
00724     if ( !removeSelected ) {
00725         // ## not sure why we do this. I'd prefer leaving the selection unchanged...
00726         // but then it'd need adjustements in the offsets etc.
00727         if ( textdoc->removeSelection( selectionId ) && repaint )
00728             selectionChangedNotify(); // does the repaint
00729     }
00730     if ( !customItemsMap.isEmpty() ) {
00731         clearUndoRedoInfo();
00732     }
00733 
00734     // Notifications
00735     emit paragraphModified( oldCursor.parag(), AddChar, cursor->index(), txt.length() );
00736     if (checkNewLine) {
00737         KoTextParag* p = oldCursor.parag()->next();
00738         while ( p && p != cursor->parag() ) {
00739             emit paragraphCreated( p );
00740             p = p->next();
00741         }
00742     }
00743 }
00744 
00745 void KoTextObject::pasteText( KoTextCursor * cursor, const QString & text, KoTextFormat * currentFormat, bool removeSelected )
00746 {
00747     if ( protectContent() )
00748         return;
00749     kDebug(32500) << "KoTextObject::pasteText cursor parag=" << cursor->parag()->paragId() << endl;
00750     QString t = text;
00751     // Need to convert CRLF to NL
00752     QRegExp crlf( QString::fromLatin1("\r\n") );
00753     t.replace( crlf, QChar('\n') );
00754     // Convert non-printable chars
00755     for ( int i=0; i < t.length(); i++ )
00756     {
00757         if ( t[ i ] < ' ' && t[ i ] != '\n' && t[ i ] != '\t' )
00758             t[ i ] = ' ';
00759     }
00760     if ( !t.isEmpty() )
00761     {
00762         int insertFlags = CheckNewLine;
00763         if ( !removeSelected )
00764             insertFlags |= DoNotRemoveSelected;
00765         insert( cursor, currentFormat, t, i18n("Paste Text"),
00766                 KoTextDocument::Standard, insertFlags );
00767         formatMore( 2 );
00768         emit repaintChanged( this );
00769     }
00770 }
00771 
00772 KCommand* KoTextObject::setParagLayoutCommand( KoTextCursor * cursor, const KoParagLayout& paragLayout,
00773                                                KoTextDocument::SelectionId selectionId, int paragLayoutFlags,
00774                                                int marginIndex, bool createUndoRedo )
00775 {
00776     if ( protectContent() )
00777         return 0;
00778     storeParagUndoRedoInfo( cursor, selectionId );
00779     undoRedoInfo.type = UndoRedoInfo::Invalid; // tricky, we don't want clear() to create a command
00780     if ( paragLayoutFlags != 0 )
00781     {
00782         emit hideCursor();
00783         if ( !textdoc->hasSelection( selectionId, true ) ) {
00784             cursor->parag()->setParagLayout( paragLayout, paragLayoutFlags, marginIndex );
00785             setLastFormattedParag( cursor->parag() );
00786         } else {
00787             KoTextParag *start = textdoc->selectionStart( selectionId );
00788             KoTextParag *end = textdoc->selectionEnd( selectionId );
00789             for ( ; start && start != end->next() ; start = start->next() ) {
00790                 if ( paragLayoutFlags == KoParagLayout::BulletNumber && start->length() <= 1 )
00791                     continue; // don't apply to empty paragraphs (#25742, #34062)
00792                 start->setParagLayout( paragLayout, paragLayoutFlags, marginIndex );
00793             }
00794             setLastFormattedParag( start );
00795         }
00796 
00797         formatMore( 2 );
00798         emit repaintChanged( this );
00799         emit showCursor();
00800         emit updateUI( true );
00801 
00802         if ( createUndoRedo )
00803         {
00804             //kDebug(32500) << "KoTextObject::applyStyle KoTextParagCommand" << endl;
00805             KoTextDocCommand * cmd = new KoTextParagCommand( textdoc, undoRedoInfo.id, undoRedoInfo.eid,
00806                                                              undoRedoInfo.oldParagLayouts,
00807                                                              paragLayout, paragLayoutFlags,
00808                                                              (Q3StyleSheetItem::Margin)marginIndex );
00809             textdoc->addCommand( cmd );
00810             return new KoTextCommand( this, /*cmd, */"related to KoTextParagCommand" );
00811         }
00812     }
00813     return 0;
00814 }
00815 
00816 
00817 void KoTextObject::applyStyle( KoTextCursor * cursor, const KoParagStyle * newStyle,
00818                                KoTextDocument::SelectionId selectionId,
00819                                int paragLayoutFlags, int formatFlags,
00820                                bool createUndoRedo, bool interactive )
00821 {
00822     KCommand *cmd = applyStyleCommand( cursor, newStyle, selectionId,
00823                                        paragLayoutFlags, formatFlags,
00824                                        createUndoRedo, interactive );
00825     if ( createUndoRedo && cmd )
00826         emit newCommand( cmd );
00827     else
00828         Q_ASSERT( !cmd ); // mem leak, if applyStyleCommand created a command despite createUndoRedo==false!
00829 }
00830 
00831 KCommand *KoTextObject::applyStyleCommand( KoTextCursor * cursor, const KoParagStyle * newStyle,
00832                                KoTextDocument::SelectionId selectionId,
00833                                int paragLayoutFlags, int formatFlags,
00834                                bool createUndoRedo, bool interactive )
00835 {
00836     if ( protectContent())
00837         return 0L;
00838     if ( interactive )
00839         emit hideCursor();
00840     if ( !textdoc->hasSelection( selectionId, true ) && !cursor)
00841         return 0L;
00847     KMacroCommand * macroCmd = createUndoRedo ? new KMacroCommand( i18n("Apply Style %1").
00848                                                                    arg(newStyle->displayName() ) ) : 0;
00849 
00850     // 1
00851     //kDebug(32500) << "KoTextObject::applyStyle setParagLayout" << endl;
00852     KCommand* cmd = setParagLayoutCommand( cursor, newStyle->paragLayout(), selectionId, paragLayoutFlags, -1, createUndoRedo );
00853     if ( cmd )
00854         macroCmd->addCommand( cmd );
00855 
00856     // 2
00857     //kDebug(32500) << "KoTextObject::applyStyle gathering text and formatting" << endl;
00858     KoTextParag * firstParag;
00859     KoTextParag * lastParag;
00860     if ( !textdoc->hasSelection( selectionId, true ) ) {
00861         // No selection -> apply style formatting to the whole paragraph
00862         firstParag = cursor->parag();
00863         lastParag = cursor->parag();
00864     }
00865     else
00866     {
00867         firstParag = textdoc->selectionStart( selectionId );
00868         lastParag = textdoc->selectionEnd( selectionId );
00869     }
00870 
00871     if ( formatFlags != 0 )
00872     {
00873         KoTextFormat * newFormat = textdoc->formatCollection()->format( &newStyle->format() );
00874 
00875         if ( createUndoRedo )
00876         {
00877             Q3ValueList<KoTextFormat *> lstFormats;
00878             //QString str;
00879             for ( KoTextParag * parag = firstParag ; parag && parag != lastParag->next() ; parag = parag->next() )
00880             {
00881                 //str += parag->string()->toString() + '\n';
00882                 lstFormats.append( parag->paragFormat() );
00883             }
00884             KoTextCursor c1( textdoc );
00885             c1.setParag( firstParag );
00886             c1.setIndex( 0 );
00887             KoTextCursor c2( textdoc );
00888             c2.setParag( lastParag );
00889             c2.setIndex( lastParag->string()->length() );
00890             undoRedoInfo.clear();
00891             undoRedoInfo.type = UndoRedoInfo::Invalid; // same trick
00892             readFormats( c1, c2 ); // gather char-format info but not paraglayouts nor customitems
00893 
00894             KoTextDocCommand * cmd = new KoTextFormatCommand( textdoc, firstParag->paragId(), 0,
00895                                                          lastParag->paragId(), c2.index(),
00896                                                          undoRedoInfo.text.rawData(), newFormat,
00897                                                          formatFlags );
00898             textdoc->addCommand( cmd );
00899             macroCmd->addCommand( new KoTextCommand( this, /*cmd, */"related to KoTextFormatCommand" ) );
00900 
00901             // sub-command for '3' (paragFormat)
00902             cmd = new KoParagFormatCommand( textdoc, firstParag->paragId(), lastParag->paragId(),
00903                                             lstFormats, newFormat );
00904             textdoc->addCommand( cmd );
00905             macroCmd->addCommand( new KoTextCommand( this, /*cmd, */"related to KoParagFormatCommand" ) );
00906         }
00907 
00908         // apply '2' and '3' (format)
00909         for ( KoTextParag * parag = firstParag ; parag && parag != lastParag->next() ; parag = parag->next() )
00910         {
00911             //kDebug(32500) << "KoTextObject::applyStyle parag:" << parag->paragId()
00912             //               << ", from 0 to " << parag->string()->length() << ", format=" << newFormat << endl;
00913             parag->setFormat( 0, parag->string()->length(), newFormat, true, formatFlags );
00914             parag->setFormat( newFormat );
00915         }
00916         //currentFormat = textdoc->formatCollection()->format( newFormat );
00917         //kDebug(32500) << "KoTextObject::applyStyle currentFormat=" << currentFormat << " " << currentFormat->key() << endl;
00918     }
00919 
00920     //resize all variables after applying the style
00921     Q3PtrListIterator<KoTextCustomItem> cit( textdoc->allCustomItems() );
00922     for ( ; cit.current() ; ++cit )
00923         cit.current()->resize();
00924 
00925 
00926     if ( interactive )
00927     {
00928         setLastFormattedParag( firstParag );
00929         formatMore( 2 );
00930         emit repaintChanged( this );
00931         emit updateUI( true );
00932         emit showCursor();
00933     }
00934 
00935     undoRedoInfo.clear();
00936 
00937     return macroCmd;
00938 }
00939 
00940 void KoTextObject::applyStyleChange( KoStyleChangeDefMap changed )
00941 {
00942 #if 0 //#ifndef NDEBUG
00943     kDebug(32500) << "KoTextObject::applyStyleChange " << changed.count() << " styles." << endl;
00944     for( KoStyleChangeDefMap::const_iterator it = changed.begin(); it != changed.end(); ++it ) {
00945         kDebug(32500) << " " << it.key()->name()
00946                        << " paragLayoutChanged=" << (*it).paragLayoutChanged
00947                        << " formatChanged=" << (*it).formatChanged
00948                        << endl;
00949     }
00950 #endif
00951 
00952     KoTextParag *p = textdoc->firstParag();
00953     while ( p ) {
00954         KoStyleChangeDefMap::Iterator it = changed.find( p->style() );
00955         if ( it != changed.end() )
00956         {
00957             if ( (*it).paragLayoutChanged == -1 || (*it).formatChanged == -1 ) // Style has been deleted
00958             {
00959                 p->setStyle( m_defaultStyle ); // keeps current formatting
00960                 // TODO, make this undoable somehow
00961             }
00962             else
00963             {
00964                 // Apply this style again, to get the changes
00965                 KoTextCursor cursor( textdoc );
00966                 cursor.setParag( p );
00967                 cursor.setIndex( 0 );
00968                 //kDebug(32500) << "KoTextObject::applyStyleChange applying to paragraph " << p << " " << p->paragId() << endl;
00969                 applyStyle( &cursor, it.key(),
00970                             KoTextDocument::Temp, // A selection we can't have at this point
00971                             (*it).paragLayoutChanged, (*it).formatChanged,
00972                             false, false ); // don't create undo/redo, not interactive
00973             }
00974         } else {
00975             //kDebug(32500) << "KoTextObject::applyStyleChange leaving paragraph unchanged: " << p << " " << p->paragId() << endl;
00976         }
00977 
00978         p = p->next();
00979     }
00980     setLastFormattedParag( textdoc->firstParag() );
00981     formatMore( 2 );
00982     emit repaintChanged( this );
00983     emit updateUI( true );
00984 }
00985 
00987 KCommand *KoTextObject::setFormatCommand( const KoTextFormat *format, int flags, bool zoomFont )
00988 {
00989     textdoc->selectAll( KoTextDocument::Temp );
00990     KCommand *cmd = setFormatCommand( 0L, 0L, format, flags, zoomFont, KoTextDocument::Temp );
00991     textdoc->removeSelection( KoTextDocument::Temp );
00992     return cmd;
00993 }
00994 
00995 KCommand * KoTextObject::setFormatCommand( KoTextCursor * cursor, KoTextFormat ** pCurrentFormat, const KoTextFormat *format, int flags, bool /*zoomFont*/, KoTextDocument::SelectionId selectionId )
00996 {
00997     KCommand *ret = 0;
00998     if ( protectContent() )
00999         return ret;
01000 
01001     KoTextFormat* newFormat = 0;
01002     // Get new format from collection if
01003     // - caller has notion of a "current format" and new format is different
01004     // - caller has no notion of "current format", e.g. whole textobjects
01005     bool isNewFormat = ( pCurrentFormat && *pCurrentFormat && (*pCurrentFormat)->key() != format->key() );
01006     if ( isNewFormat || !pCurrentFormat )
01007     {
01008 #if 0
01009         int origFontSize = 0;
01010         if ( zoomFont ) // The format has a user-specified font (e.g. setting a style, or a new font size)
01011         {
01012             origFontSize = format->pointSize();
01013             format->setPointSize( zoomedFontSize( origFontSize ) );
01014             //kDebug(32500) << "KoTextObject::setFormatCommand format " << format->key() << " zoomed from " << origFontSize << " to " << format->font().pointSizeF() << endl;
01015         }
01016 #endif
01017         // Remove ref to current format, if caller wanted that
01018         if ( pCurrentFormat )
01019             (*pCurrentFormat)->removeRef();
01020         // Find format in collection
01021         newFormat = textdoc->formatCollection()->format( format );
01022         if ( newFormat->isMisspelled() ) {
01023             KoTextFormat fNoMisspelled( *newFormat );
01024             newFormat->removeRef();
01025             fNoMisspelled.setMisspelled( false );
01026             newFormat = textdoc->formatCollection()->format( &fNoMisspelled );
01027         }
01028         if ( pCurrentFormat )
01029             (*pCurrentFormat) = newFormat;
01030     }
01031 
01032     if ( textdoc->hasSelection( selectionId, true ) ) {
01033         emit hideCursor();
01034         KoTextCursor c1 = textdoc->selectionStartCursor( selectionId );
01035         KoTextCursor c2 = textdoc->selectionEndCursor( selectionId );
01036         undoRedoInfo.clear();
01037         int id = c1.parag()->paragId();
01038         int index = c1.index();
01039         int eid = c2.parag()->paragId();
01040         int eindex = c2.index();
01041         readFormats( c1, c2 ); // read previous formatting info
01042         //kDebug(32500) << "KoTextObject::setFormatCommand undoredo info done" << endl;
01043         textdoc->setFormat( selectionId, format, flags );
01044         if ( !undoRedoInfo.customItemsMap.isEmpty() )
01045         {
01046             // Some custom items (e.g. variables) depend on the format
01047             CustomItemsMap::Iterator it = undoRedoInfo.customItemsMap.begin();
01048             for ( ; it != undoRedoInfo.customItemsMap.end(); ++it )
01049                 it.value()->resize();
01050         }
01051         KoTextFormatCommand *cmd = new KoTextFormatCommand(
01052             textdoc, id, index, eid, eindex, undoRedoInfo.text.rawData(),
01053             format, flags );
01054         textdoc->addCommand( cmd );
01055         ret = new KoTextCommand( this, /*cmd, */i18n("Format Text") );
01056         undoRedoInfo.clear();
01057         setLastFormattedParag( c1.parag() );
01058         formatMore( 2 );
01059         emit repaintChanged( this );
01060         emit showCursor();
01061     }
01062     if ( isNewFormat ) {
01063         emit showCurrentFormat();
01064         //kDebug(32500) << "KoTextObject::setFormatCommand index=" << cursor->index() << " length-1=" << cursor->parag()->length() - 1 << endl;
01065         if ( cursor && cursor->index() == cursor->parag()->length() - 1 ) {
01066             newFormat->addRef();
01067             cursor->parag()->string()->setFormat( cursor->index(), newFormat, true );
01068             if ( cursor->parag()->length() == 1 ) {
01069                 newFormat->addRef();
01070                 cursor->parag()->setFormat( newFormat );
01071                 cursor->parag()->invalidate(0);
01072                 cursor->parag()->format();
01073                 emit repaintChanged( this );
01074             }
01075         }
01076     }
01077     return ret;
01078 }
01079 
01080 void KoTextObject::setFormat( KoTextCursor * cursor, KoTextFormat ** currentFormat, KoTextFormat *format, int flags, bool zoomFont )
01081 {
01082     if ( protectContent() )
01083         return;
01084     KCommand *cmd = setFormatCommand( cursor, currentFormat, format, flags, zoomFont );
01085     if (cmd)
01086         emit newCommand( cmd );
01087 }
01088 
01089 void KoTextObject::emitNewCommand(KCommand *cmd)
01090 {
01091     if(cmd)
01092         emit newCommand( cmd );
01093 }
01094 
01095 KCommand *KoTextObject::setCounterCommand( KoTextCursor * cursor, const KoParagCounter & counter, KoTextDocument::SelectionId selectionId  )
01096 {
01097     if ( protectContent() )
01098         return 0L;
01099     const KoParagCounter * curCounter = 0L;
01100     if(cursor)
01101         curCounter=cursor->parag()->counter();
01102     if ( !textdoc->hasSelection( selectionId, true ) &&
01103          curCounter && counter == *curCounter ) {
01104         return 0L;
01105     }
01106     emit hideCursor();
01107     storeParagUndoRedoInfo( cursor, selectionId );
01108     if ( !textdoc->hasSelection( selectionId, true ) && cursor) {
01109         cursor->parag()->setCounter( counter );
01110         setLastFormattedParag( cursor->parag() );
01111     } else {
01112         KoTextParag *start = textdoc->selectionStart( selectionId );
01113         KoTextParag *end = textdoc->selectionEnd( selectionId );
01114 #if 0
01115         // Special hack for BR25742, don't apply bullet to last empty parag of the selection
01116         if ( start != end && end->length() <= 1 )
01117         {
01118             end = end->prev();
01119             undoRedoInfo.eid = end->paragId();
01120         }
01121 #endif
01122         setLastFormattedParag( start );
01123         for ( ; start && start != end->next() ; start = start->next() )
01124         {
01125             if ( start->length() > 1 )  // don't apply to empty paragraphs (#25742, #34062)
01126                 start->setCounter( counter );
01127         }
01128     }
01129     formatMore( 2 );
01130     emit repaintChanged( this );
01131     if ( !undoRedoInfo.newParagLayout.counter )
01132         undoRedoInfo.newParagLayout.counter = new KoParagCounter;
01133     *undoRedoInfo.newParagLayout.counter = counter;
01134     KoTextParagCommand *cmd = new KoTextParagCommand(
01135         textdoc, undoRedoInfo.id, undoRedoInfo.eid,
01136         undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
01137         KoParagLayout::BulletNumber );
01138     textdoc->addCommand( cmd );
01139 
01140     undoRedoInfo.clear(); // type is still Invalid -> no command created
01141     emit showCursor();
01142     emit updateUI( true );
01143     return new KoTextCommand( this, /*cmd, */i18n("Change List Type") );
01144 }
01145 
01146 KCommand * KoTextObject::setAlignCommand( KoTextCursor * cursor, int align, KoTextDocument::SelectionId selectionId )
01147 {
01148     if ( protectContent() )
01149         return 0L;
01150     if ( !textdoc->hasSelection( selectionId, true ) && cursor &&
01151          (int)cursor->parag()->alignment() == align )
01152         return 0L; // No change needed.
01153 
01154     emit hideCursor();
01155     storeParagUndoRedoInfo( cursor ,selectionId );
01156     if ( !textdoc->hasSelection( selectionId, true ) &&cursor ) {
01157         cursor->parag()->setAlign(align);
01158         setLastFormattedParag( cursor->parag() );
01159     }
01160     else
01161     {
01162         KoTextParag *start = textdoc->selectionStart( selectionId );
01163         KoTextParag *end = textdoc->selectionEnd( selectionId  );
01164         setLastFormattedParag( start );
01165         for ( ; start && start != end->next() ; start = start->next() )
01166             start->setAlign(align);
01167     }
01168     formatMore( 2 );
01169     emit repaintChanged( this );
01170     undoRedoInfo.newParagLayout.alignment = align;
01171     KoTextParagCommand *cmd = new KoTextParagCommand(
01172         textdoc, undoRedoInfo.id, undoRedoInfo.eid,
01173         undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
01174         KoParagLayout::Alignment );
01175     textdoc->addCommand( cmd );
01176     undoRedoInfo.clear(); // type is still Invalid -> no command created
01177     emit showCursor();
01178     emit updateUI( true );
01179     return new KoTextCommand( this, /*cmd, */i18n("Change Alignment") );
01180 }
01181 
01182 KCommand * KoTextObject::setMarginCommand( KoTextCursor * cursor, Q3StyleSheetItem::Margin m, double margin , KoTextDocument::SelectionId selectionId ) {
01183     if ( protectContent() )
01184         return 0L;
01185 
01186     //kDebug(32500) << "KoTextObject::setMargin " << m << " to value " << margin << endl;
01187     //kDebug(32500) << "Current margin is " << cursor->parag()->margin(m) << endl;
01188     if ( !textdoc->hasSelection( selectionId, true ) && cursor &&
01189          cursor->parag()->margin(m) == margin )
01190         return 0L; // No change needed.
01191 
01192     emit hideCursor();
01193     storeParagUndoRedoInfo( cursor, selectionId );
01194     if ( !textdoc->hasSelection( selectionId, true )&&cursor ) {
01195         cursor->parag()->setMargin(m, margin);
01196         setLastFormattedParag( cursor->parag() );
01197     }
01198     else
01199     {
01200         KoTextParag *start = textdoc->selectionStart( selectionId );
01201         KoTextParag *end = textdoc->selectionEnd( selectionId );
01202         setLastFormattedParag( start );
01203         for ( ; start && start != end->next() ; start = start->next() )
01204             start->setMargin(m, margin);
01205     }
01206     formatMore( 2 );
01207     emit repaintChanged( this );
01208     undoRedoInfo.newParagLayout.margins[m] = margin;
01209     KoTextParagCommand *cmd = new KoTextParagCommand(
01210         textdoc, undoRedoInfo.id, undoRedoInfo.eid,
01211         undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
01212         KoParagLayout::Margins, m );
01213     textdoc->addCommand( cmd );
01214     QString name;
01215     if ( m == Q3StyleSheetItem::MarginFirstLine )
01216         name = i18n("Change First Line Indent");
01217     else if ( m == Q3StyleSheetItem::MarginLeft || m == Q3StyleSheetItem::MarginRight )
01218         name = i18n("Change Indent");
01219     else
01220         name = i18n("Change Paragraph Spacing");
01221     undoRedoInfo.clear();
01222     emit showCursor();
01223     emit updateUI( true );
01224     return  new KoTextCommand( this, /*cmd, */name );
01225 }
01226 
01227 KCommand * KoTextObject::setBackgroundColorCommand( KoTextCursor * cursor,
01228                                                     const QColor & color,
01229                                                     KoTextDocument::SelectionId selectionId ) {
01230     if ( protectContent() )
01231         return 0L;
01232 
01233     if ( !textdoc->hasSelection( selectionId, true ) && cursor &&
01234          cursor->parag()->backgroundColor() == color )
01235         return 0L; // No change needed.
01236 
01237     emit hideCursor();
01238     storeParagUndoRedoInfo( cursor, selectionId );
01239     if ( !textdoc->hasSelection( selectionId, true )&&cursor )
01240     {
01241         // Update a single paragraph
01242         cursor->parag()->setBackgroundColor(color);
01243         setLastFormattedParag( cursor->parag() );
01244     }
01245     else
01246     {
01247         // Update multiple paragraphs
01248         KoTextParag *start = textdoc->selectionStart( selectionId );
01249         KoTextParag *end = textdoc->selectionEnd( selectionId );
01250         setLastFormattedParag( start );
01251         for ( ; start && start != end->next() ; start = start->next() )
01252             start->setBackgroundColor(color);
01253     }
01254     formatMore( 2 );
01255     emit repaintChanged( this );
01256 
01257     // Update undo/redo info
01258     undoRedoInfo.newParagLayout.backgroundColor = color;
01259     KoTextParagCommand *cmd = new KoTextParagCommand(
01260         textdoc, undoRedoInfo.id, undoRedoInfo.eid,
01261         undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
01262         KoParagLayout::BackgroundColor );
01263     textdoc->addCommand( cmd );
01264     undoRedoInfo.clear();
01265 
01266     emit showCursor();
01267     emit updateUI( true );
01268     return new KoTextCommand( this, /*cmd, */ i18n("Change Paragraph Background Color" ) );
01269 }
01270 
01271 KCommand * KoTextObject::setLineSpacingCommand( KoTextCursor * cursor, double spacing, KoParagLayout::SpacingType _type, KoTextDocument::SelectionId selectionId )
01272 {
01273     if ( protectContent() )
01274         return 0L;
01275     //kDebug(32500) << "KoTextObject::setLineSpacing to value " << spacing << endl;
01276     //kDebug(32500) << "Current spacing is " << cursor->parag()->kwLineSpacing() << endl;
01277     //kDebug(32500) << "Comparison says " << ( cursor->parag()->kwLineSpacing() == spacing ) << endl;
01278     //kDebug(32500) << "hasSelection " << textdoc->hasSelection( selectionId ) << endl;
01279     if ( !textdoc->hasSelection( selectionId, true ) && cursor &&
01280          cursor->parag()->kwLineSpacing() == spacing
01281         && cursor->parag()->kwLineSpacingType() == _type)
01282         return 0L; // No change needed.
01283 
01284     emit hideCursor();
01285     storeParagUndoRedoInfo( cursor, selectionId );
01286     if ( !textdoc->hasSelection( selectionId, true ) && cursor ) {
01287         cursor->parag()->setLineSpacing(spacing);
01288         cursor->parag()->setLineSpacingType( _type);
01289         setLastFormattedParag( cursor->parag() );
01290     }
01291     else
01292     {
01293         KoTextParag *start = textdoc->selectionStart( selectionId );
01294         KoTextParag *end = textdoc->selectionEnd( selectionId );
01295         setLastFormattedParag( start );
01296         for ( ; start && start != end->next() ; start = start->next() )
01297         {
01298             start->setLineSpacing(spacing);
01299             start->setLineSpacingType( _type);
01300         }
01301     }
01302     formatMore( 2 );
01303     emit repaintChanged( this );
01304     undoRedoInfo.newParagLayout.setLineSpacingValue( spacing );
01305     undoRedoInfo.newParagLayout.lineSpacingType = _type;
01306     KoTextParagCommand *cmd = new KoTextParagCommand(
01307         textdoc, undoRedoInfo.id, undoRedoInfo.eid,
01308         undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
01309         KoParagLayout::LineSpacing );
01310     textdoc->addCommand( cmd );
01311 
01312     undoRedoInfo.clear();
01313     emit showCursor();
01314     return new KoTextCommand( this, /*cmd, */i18n("Change Line Spacing") );
01315 }
01316 
01317 
01318 KCommand * KoTextObject::setBordersCommand( KoTextCursor * cursor, const KoBorder& leftBorder, const KoBorder& rightBorder, const KoBorder& topBorder, const KoBorder& bottomBorder , KoTextDocument::SelectionId selectionId )
01319 {
01320     if ( protectContent() )
01321         return 0L;
01322   if ( !textdoc->hasSelection( selectionId, true ) && cursor &&
01323        cursor->parag()->leftBorder() ==leftBorder &&
01324        cursor->parag()->rightBorder() ==rightBorder &&
01325        cursor->parag()->topBorder() ==topBorder &&
01326        cursor->parag()->bottomBorder() ==bottomBorder )
01327         return 0L; // No change needed.
01328 
01329     emit hideCursor();
01330     bool borderOutline = false;
01331     storeParagUndoRedoInfo( cursor, selectionId );
01332     if ( !textdoc->hasSelection( selectionId, true ) ) {
01333       cursor->parag()->setLeftBorder(leftBorder);
01334       cursor->parag()->setRightBorder(rightBorder);
01335       cursor->parag()->setBottomBorder(bottomBorder);
01336       cursor->parag()->setTopBorder(topBorder);
01337       setLastFormattedParag( cursor->parag() );
01338 
01339       if ( cursor->parag()->next() )
01340         cursor->parag()->next()->setChanged( true );
01341        if ( cursor->parag()->prev() )
01342         cursor->parag()->prev()->setChanged( true );
01343     }
01344     else
01345     {
01346         KoTextParag *start = textdoc->selectionStart( selectionId );
01347         KoTextParag *end = textdoc->selectionEnd( selectionId );
01348         setLastFormattedParag( start );
01349         KoBorder tmpBorder;
01350         tmpBorder.setPenWidth(0);
01351         for ( ; start && start != end->next() ; start = start->next() )
01352           {
01353             start->setLeftBorder(leftBorder);
01354             start->setRightBorder(rightBorder);
01355             //remove border
01356             start->setTopBorder(tmpBorder);
01357             start->setBottomBorder(tmpBorder);
01358           }
01359         end->setBottomBorder(bottomBorder);
01360         textdoc->selectionStart( selectionId )->setTopBorder(topBorder);
01361         borderOutline = true;
01362 
01363         if ( start && start->prev() )
01364             start->prev()->setChanged( true );
01365         if ( end && end->next() )
01366             end->next()->setChanged( true );
01367     }
01368     formatMore( 2 );
01369     emit repaintChanged( this );
01370     undoRedoInfo.newParagLayout.leftBorder=leftBorder;
01371     undoRedoInfo.newParagLayout.rightBorder=rightBorder;
01372     undoRedoInfo.newParagLayout.topBorder=topBorder;
01373     undoRedoInfo.newParagLayout.bottomBorder=bottomBorder;
01374 
01375     KoTextParagCommand *cmd = new KoTextParagCommand(
01376         textdoc, undoRedoInfo.id, undoRedoInfo.eid,
01377         undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
01378         KoParagLayout::Borders, (Q3StyleSheetItem::Margin)-1, borderOutline);
01379     textdoc->addCommand( cmd );
01380 
01381     undoRedoInfo.clear();
01382     emit showCursor();
01383     emit updateUI( true );
01384     return new KoTextCommand( this, /*cmd, */i18n("Change Borders") );
01385 }
01386 
01387 KCommand * KoTextObject::setJoinBordersCommand( KoTextCursor * cursor, bool join, KoTextDocument::SelectionId selectionId  )
01388 {
01389   if ( protectContent() )
01390         return 0L;
01391   if ( !textdoc->hasSelection( selectionId, true ) &&
01392        cursor && cursor->parag()->joinBorder() == join )
01393         return 0L; // No change needed.
01394 
01395     emit hideCursor();
01396      bool borderOutline = false;
01397      storeParagUndoRedoInfo( cursor, KoTextDocument::Standard );
01398     if ( !textdoc->hasSelection( selectionId, true ) )
01399     {
01400       cursor->parag()->setJoinBorder( join );
01401       setLastFormattedParag( cursor->parag() );
01402 
01403       if ( cursor->parag()->next() )
01404         cursor->parag()->next()->setChanged( true );
01405       if ( cursor->parag()->prev() )
01406         cursor->parag()->prev()->setChanged( true );
01407     }
01408     else
01409     {
01410         KoTextParag *start = textdoc->selectionStart( selectionId );
01411         KoTextParag *end = textdoc->selectionEnd( selectionId );
01412         setLastFormattedParag( start );
01413         for ( ; start && start != end->next() ; start = start->next() )
01414         {
01415             start->setJoinBorder( true );
01416         }
01417         end->setJoinBorder ( true );
01418         borderOutline = true;
01419 
01420         if ( start && start->prev() )
01421             start->prev()->setChanged( true );
01422         if ( end && end->next() )
01423             end->next()->setChanged( true );
01424     }
01425     formatMore( 2 );
01426 
01427     emit repaintChanged( this );
01428     undoRedoInfo.newParagLayout.joinBorder=join;
01429 
01430     KoTextParagCommand *cmd = new KoTextParagCommand(
01431         textdoc, undoRedoInfo.id, undoRedoInfo.eid,
01432         undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
01433         KoParagLayout::Borders, (Q3StyleSheetItem::Margin)-1, borderOutline);
01434     textdoc->addCommand( cmd );
01435 
01436     undoRedoInfo.clear();
01437     emit ensureCursorVisible();
01438     emit showCursor();
01439     emit updateUI( true );
01440     return new KoTextCommand( this, /*cmd, */i18n("Change Join Borders") );
01441 }
01442 
01443 
01444 KCommand * KoTextObject::setTabListCommand( KoTextCursor * cursor, const KoTabulatorList &tabList, KoTextDocument::SelectionId selectionId  )
01445 {
01446     if ( protectContent() )
01447         return 0L;
01448     if ( !textdoc->hasSelection( selectionId, true ) && cursor &&
01449          cursor->parag()->tabList() == tabList )
01450         return 0L; // No change needed.
01451 
01452     emit hideCursor();
01453     storeParagUndoRedoInfo( cursor, selectionId );
01454 
01455     if ( !textdoc->hasSelection( selectionId, true ) && cursor ) {
01456         cursor->parag()->setTabList( tabList );
01457         setLastFormattedParag( cursor->parag() );
01458     }
01459     else
01460     {
01461         KoTextParag *start = textdoc->selectionStart( selectionId );
01462         KoTextParag *end = textdoc->selectionEnd( selectionId );
01463         setLastFormattedParag( start );
01464         for ( ; start && start != end->next() ; start = start->next() )
01465             start->setTabList( tabList );
01466     }
01467 
01468     formatMore( 2 );
01469     emit repaintChanged( this );
01470     undoRedoInfo.newParagLayout.setTabList( tabList );
01471     KoTextParagCommand *cmd = new KoTextParagCommand(
01472         textdoc, undoRedoInfo.id, undoRedoInfo.eid,
01473         undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
01474         KoParagLayout::Tabulator);
01475     textdoc->addCommand( cmd );
01476     undoRedoInfo.clear();
01477     emit showCursor();
01478     emit updateUI( true );
01479     return new KoTextCommand( this, /*cmd, */i18n("Change Tabulator") );
01480 }
01481 
01482 KCommand * KoTextObject::setParagDirectionCommand( KoTextCursor * cursor, QChar::Direction d, KoTextDocument::SelectionId selectionId )
01483 {
01484     if ( protectContent() )
01485         return 0L;
01486     if ( !textdoc->hasSelection( selectionId, true ) && cursor &&
01487          cursor->parag()->direction() == d )
01488         return 0L; // No change needed.
01489 
01490     emit hideCursor();
01491     storeParagUndoRedoInfo( cursor, selectionId );
01492 
01493     if ( !textdoc->hasSelection( selectionId, true ) && cursor ) {
01494         cursor->parag()->setDirection( d );
01495         setLastFormattedParag( cursor->parag() );
01496     }
01497     else
01498     {
01499         KoTextParag *start = textdoc->selectionStart( selectionId );
01500         KoTextParag *end = textdoc->selectionEnd( selectionId );
01501         setLastFormattedParag( start );
01502         for ( ; start && start != end->next() ; start = start->next() )
01503             start->setDirection( d );
01504     }
01505 
01506     formatMore( 2 );
01507     emit repaintChanged( this );
01509 #if 0
01510     undoRedoInfo.newParagLayout.direction = d;
01511     KoTextParagCommand *cmd = new KoTextParagCommand(
01512         textdoc, undoRedoInfo.id, undoRedoInfo.eid,
01513         undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout,
01514         KoParagLayout::Shadow);
01515     textdoc->addCommand( cmd );
01516 #endif
01517     undoRedoInfo.clear();
01518     emit showCursor();
01519     emit updateUI( true );
01520 #if 0
01521     return new KoTextCommand( this, /*cmd, */i18n("Change Shadow") );
01522 #else
01523     return 0L;
01524 #endif
01525 }
01526 
01527 void KoTextObject::removeSelectedText( KoTextCursor * cursor, KoTextDocument::SelectionId selectionId, const QString & cmdName, bool createUndoRedo )
01528 {
01529     if ( protectContent() )
01530         return ;
01531     emit hideCursor();
01532     if( createUndoRedo)
01533     {
01534         checkUndoRedoInfo( cursor, UndoRedoInfo::RemoveSelected );
01535         if ( !undoRedoInfo.valid() ) {
01536             textdoc->selectionStart( selectionId, undoRedoInfo.id, undoRedoInfo.index );
01537             undoRedoInfo.text = QString::null;
01538             newPlaceHolderCommand( cmdName.isNull() ? i18n("Remove Selected Text") : cmdName );
01539         }
01540     }
01541     KoTextCursor c1 = textdoc->selectionStartCursor( selectionId );
01542     KoTextCursor c2 = textdoc->selectionEndCursor( selectionId );
01543     readFormats( c1, c2, true, true );
01544     //kDebug(32500) << "KoTextObject::removeSelectedText text=" << undoRedoInfo.text.toString() << endl;
01545 
01546     textdoc->removeSelectedText( selectionId, cursor );
01547 
01548     setLastFormattedParag( cursor->parag() );
01549     formatMore( 2 );
01550     emit repaintChanged( this );
01551     emit ensureCursorVisible();
01552     emit updateUI( true );
01553     emit showCursor();
01554     if(selectionId==KoTextDocument::Standard || selectionId==KoTextDocument::InputMethodPreedit)
01555         selectionChangedNotify();
01556     if ( createUndoRedo)
01557         undoRedoInfo.clear();
01558 }
01559 
01560 KCommand * KoTextObject::removeSelectedTextCommand( KoTextCursor * cursor, KoTextDocument::SelectionId selectionId, bool repaint )
01561 {
01562     if ( protectContent() )
01563         return 0L;
01564     if ( !textdoc->hasSelection( selectionId, true ) )
01565         return 0L;
01566 
01567     undoRedoInfo.clear();
01568     textdoc->selectionStart( selectionId, undoRedoInfo.id, undoRedoInfo.index );
01569     Q_ASSERT( undoRedoInfo.id >= 0 );
01570 
01571     KoTextCursor c1 = textdoc->selectionStartCursor( selectionId );
01572     KoTextCursor c2 = textdoc->selectionEndCursor( selectionId );
01573     readFormats( c1, c2, true, true );
01574 
01575     textdoc->removeSelectedText( selectionId, cursor );
01576 
01577     KMacroCommand *macroCmd = new KMacroCommand( i18n("Remove Selected Text") );
01578 
01579     KoTextDocCommand *cmd = deleteTextCommand( textdoc, undoRedoInfo.id, undoRedoInfo.index,
01580                                                  undoRedoInfo.text.rawData(),
01581                                                  undoRedoInfo.customItemsMap,
01582                                                  undoRedoInfo.oldParagLayouts );
01583     textdoc->addCommand(cmd);
01584     macroCmd->addCommand(new KoTextCommand( this, /*cmd, */QString::null ));
01585 
01586     if(!undoRedoInfo.customItemsMap.isEmpty())
01587         undoRedoInfo.customItemsMap.deleteAll( macroCmd );
01588 
01589     undoRedoInfo.type = UndoRedoInfo::Invalid; // we don't want clear() to create a command
01590     undoRedoInfo.clear();
01591     if ( repaint )
01592         selectionChangedNotify();
01593     return macroCmd;
01594 }
01595 
01596 KCommand* KoTextObject::replaceSelectionCommand( KoTextCursor * cursor, const QString & replacement,
01597                                                  const QString & cmdName,
01598                                                  KoTextDocument::SelectionId selectionId,
01599                                                  int insertFlags,
01600                                                  CustomItemsMap customItemsMap )
01601 {
01602     if ( protectContent() )
01603         return 0L;
01604     Q_ASSERT( ( insertFlags & DoNotRemoveSelected ) == 0 ); // nonsensical
01605     const bool repaint = ( insertFlags & DoNotRepaint ) == 0; // DoNotRepaint is set during search/replace
01606     if ( repaint )
01607         emit hideCursor();
01608     // This could be improved to use a macro command only when there's a selection to remove.
01609     KMacroCommand * macroCmd = new KMacroCommand( cmdName );
01610 
01611     // Remember formatting
01612     KoTextCursor c1 = textdoc->selectionStartCursor( selectionId );
01613     KoTextFormat * format = c1.parag()->at( c1.index() )->format();
01614     format->addRef();
01615 
01616     // Remove selected text, if any
01617     KCommand* removeSelCmd = removeSelectedTextCommand( cursor, selectionId, repaint );
01618     if ( removeSelCmd )
01619         macroCmd->addCommand( removeSelCmd );
01620 
01621     // Insert replacement
01622     insert( cursor, format,
01623             replacement, QString::null /* no place holder command */,
01624             selectionId, insertFlags | DoNotRemoveSelected, customItemsMap );
01625 
01626     KoTextDocCommand * cmd = new KoTextInsertCommand( textdoc, undoRedoInfo.id, undoRedoInfo.index,
01627                                                       undoRedoInfo.text.rawData(),
01628                                                       CustomItemsMap(), undoRedoInfo.oldParagLayouts );
01629     textdoc->addCommand( cmd );
01630     macroCmd->addCommand( new KoTextCommand( this, /*cmd, */QString::null ) );
01631 
01632     undoRedoInfo.type = UndoRedoInfo::Invalid; // we don't want clear() to create a command
01633     undoRedoInfo.clear();
01634 
01635     format->removeRef();
01636 
01637     setLastFormattedParag( c1.parag() );
01638     if ( repaint )
01639     {
01640         formatMore( 2 );
01641         emit repaintChanged( this );
01642         emit ensureCursorVisible();
01643         emit updateUI( true );
01644         emit showCursor();
01645         if(selectionId==KoTextDocument::Standard)
01646             selectionChangedNotify();
01647     }
01648     return macroCmd;
01649 }
01650 
01651 KCommand * KoTextObject::insertParagraphCommand( KoTextCursor *cursor )
01652 {
01653     if ( protectContent() )
01654         return 0L;
01655     return replaceSelectionCommand( cursor, "\n", QString::null, KoTextDocument::Standard, CheckNewLine );
01656 }
01657 
01658 void KoTextObject::highlightPortion( KoTextParag * parag, int index, int length, bool repaint )
01659 {
01660     if ( !m_highlightSelectionAdded )
01661     {
01662         textdoc->addSelection( KoTextDocument::HighlightSelection );
01663         textdoc->setSelectionColor( KoTextDocument::HighlightSelection,
01664                                     QApplication::palette().color( QPalette::Active, QColorGroup::Dark ) );
01665         textdoc->setInvertSelectionText( KoTextDocument::HighlightSelection, true );
01666         m_highlightSelectionAdded = true;
01667     }
01668 
01669     removeHighlight(repaint); // remove previous highlighted selection
01670     KoTextCursor cursor( textdoc );
01671     cursor.setParag( parag );
01672     cursor.setIndex( index );
01673     textdoc->setSelectionStart( KoTextDocument::HighlightSelection, &cursor );
01674     cursor.setIndex( index + length );
01675     textdoc->setSelectionEnd( KoTextDocument::HighlightSelection, &cursor );
01676     if ( repaint ) {
01677         parag->setChanged( true );
01678         emit repaintChanged( this );
01679     }
01680 }
01681 
01682 void KoTextObject::removeHighlight(bool repaint)
01683 {
01684     if ( textdoc->hasSelection( KoTextDocument::HighlightSelection, true ) )
01685     {
01686         KoTextParag * oldParag = textdoc->selectionStart( KoTextDocument::HighlightSelection );
01687         oldParag->setChanged( true );
01688         textdoc->removeSelection( KoTextDocument::HighlightSelection );
01689     }
01690     if ( repaint )
01691         emit repaintChanged( this );
01692 }
01693 
01694 void KoTextObject::selectAll( bool select )
01695 {
01696     if ( !select )
01697         textdoc->removeSelection( KoTextDocument::Standard );
01698     else
01699         textdoc->selectAll( KoTextDocument::Standard );
01700     selectionChangedNotify();
01701 }
01702 
01703 void KoTextObject::selectionChangedNotify( bool enableActions /* = true */)
01704 {
01705     emit repaintChanged( this );
01706     if ( enableActions )
01707         emit selectionChanged( hasSelection() );
01708 }
01709 
01710 void KoTextObject::setViewArea( QWidget* w, int maxY )
01711 {
01712     m_mapViewAreas.insert( w, maxY );
01713 }
01714 
01715 void KoTextObject::setLastFormattedParag( KoTextParag *parag )
01716 {
01717     //kDebug() << k_funcinfo << parag << " (" << ( parag ? QString::number(parag->paragId()) : QString("(null)") ) << ")" << endl;
01718     if ( !m_lastFormatted || !parag || m_lastFormatted->paragId() >= parag->paragId() ) {
01719         m_lastFormatted = parag;
01720     }
01721 }
01722 
01723 void KoTextObject::ensureFormatted( KoTextParag * parag, bool emitAfterFormatting /* = true */ )
01724 {
01725     if ( !textdoc->lastParag() )
01726         return; // safety test
01727     //kDebug(32500) << name() << " ensureFormatted " << parag->paragId() << endl;
01728     if ( !parag->isValid() && m_lastFormatted == 0 )
01729         m_lastFormatted = parag; // bootstrap
01730 
01731     while ( !parag->isValid() )
01732     {
01733         if ( !m_lastFormatted ) {
01734             kWarning() << "ensureFormatted for parag " << parag << " " << parag->paragId() << " still not formatted, but m_lastFormatted==0" << endl;
01735             return;
01736         }
01737         // The paragid diff is "a good guess". The >=1 is a safety measure ;)
01738         bool ret = formatMore( qMax( 1, parag->paragId() - m_lastFormatted->paragId() ), emitAfterFormatting );
01739         if ( !ret ) { // aborted
01740             //kDebug(32500) << "ensureFormatted aborted!" << endl;
01741             break;
01742         }
01743     }
01744     //kDebug(32500) << name() << " ensureFormatted " << parag->paragId() << " done" << endl;
01745 }
01746 
01747 bool KoTextObject::formatMore( int count /* = 10 */, bool emitAfterFormatting /* = true */ )
01748 {
01749     if ( ( !m_lastFormatted && d->afterFormattingEmitted )
01750          || !m_visible || m_availableHeight == -1 )
01751         return false;
01752 
01753     if ( !textdoc->lastParag() )
01754         return false; // safety test
01755 
01756     if ( d->abortFormatting ) {
01757         d->abortFormatting = false;
01758         return false;
01759     }
01760 
01761     if ( count == 0 )
01762     {
01763         formatTimer->setSingleShot( true );
01764         formatTimer->start( interval );
01765         return true;
01766     }
01767 
01768     int bottom = 0;
01769     if ( m_lastFormatted )
01770     {
01771         d->afterFormattingEmitted = false;
01772 
01773         int viewsBottom = 0;
01774         QMap<QWidget *, int>::const_iterator mapIt = m_mapViewAreas.begin();
01775         for ( ; mapIt != m_mapViewAreas.end() ; ++mapIt )
01776             viewsBottom = qMax( viewsBottom, mapIt.value() );
01777 
01778 #ifdef DEBUG_FORMAT_MORE
01779         kDebug(32500) << "formatMore " << name()
01780                        << " lastFormatted id=" << m_lastFormatted->paragId()
01781                        << " lastFormatted's top=" << m_lastFormatted->rect().top()
01782                        << " lastFormatted's height=" << m_lastFormatted->rect().height()
01783                        << " count=" << count << " viewsBottom=" << viewsBottom
01784                        << " availableHeight=" << m_availableHeight << endl;
01785 #endif
01786         if ( m_lastFormatted->prev() == 0 )
01787         {
01788             emit formattingFirstParag();
01789 #ifdef TIMING_FORMAT
01790             kDebug(32500) << "formatMore " << name() << ". First parag -> starting timer" << endl;
01791             m_time.start();
01792 #endif
01793         }
01794 
01795         // Stop if we have formatted everything or if we need more space
01796         // Otherwise, stop formatting after "to" paragraphs,
01797         // but make sure we format everything the views need
01798         int i;
01799         for ( i = 0;
01800               m_lastFormatted && bottom + m_lastFormatted->rect().height() <= m_availableHeight &&
01801                   ( i < count || bottom <= viewsBottom ) ; ++i )
01802         {
01803             KoTextParag* parag = m_lastFormatted;
01804 #ifdef DEBUG_FORMAT_MORE
01805             kDebug(32500) << "formatMore formatting " << parag << " id=" << parag->paragId() << endl;
01806 #endif
01807             assert( parag->string() ); // i.e. not deleted
01808             parag->format();
01809             bottom = parag->rect().top() + parag->rect().height();
01810 #if 0 //def DEBUG_FORMAT_MORE
01811             kDebug(32500) << "formatMore(inside) top=" << parag->rect().top()
01812                       << " height=" << parag->rect().height()
01813                       << " bottom=" << bottom << " m_lastFormatted(next parag) = " << m_lastFormatted->next() << endl;
01814 #endif
01815 
01816             // Check for Head 1 (i.e. section) titles, and emit them - for the Section variable
01817             if ( parag->counter() && parag->counter()->numbering() == KoParagCounter::NUM_CHAPTER
01818                  && parag->counter()->depth() == 0 )
01819                 emit chapterParagraphFormatted( parag );
01820 
01821             if ( d->abortFormatting ) {
01822 #ifdef DEBUG_FORMAT_MORE
01823                 kDebug(32500) << "formatMore formatting aborted. " << endl;
01824 #endif
01825                 d->abortFormatting = false;
01826                 return false;
01827             }
01828 
01829             if ( parag != m_lastFormatted )
01830                 kWarning() << "Some code changed m_lastFormatted during formatting! Was " << parag->paragId() << ", is now " << m_lastFormatted->paragId() << endl;
01831 #if 0 // This happens now that formatting can 'abort' (e.g. due to page not yet created)
01832             else if (!parag->isValid())
01833                 kWarning() << "PARAGRAPH " << parag->paragId() << " STILL INVALID AFTER FORMATTING" << endl;
01834 #endif
01835             m_lastFormatted = parag->next();
01836         }
01837     }
01838     else // formatting was done previously, but not emit afterFormatting
01839     {
01840         QRect rect = textdoc->lastParag()->rect();
01841         bottom = rect.top() + rect.height();
01842     }
01843 #ifdef DEBUG_FORMAT_MORE
01844     QString id;
01845     if ( m_lastFormatted ) id = QString(" (%1)").arg(m_lastFormatted->paragId());
01846     kDebug(32500) << "formatMore finished formatting. "
01847                    << " bottom=" << bottom
01848                    << " m_lastFormatted=" << m_lastFormatted << id
01849                    << endl;
01850 #endif
01851 
01852     if ( emitAfterFormatting )
01853     {
01854         d->afterFormattingEmitted = true;
01855         bool needMoreSpace = false;
01856         // Check if we need more space
01857         if ( ( bottom > m_availableHeight ) ||   // this parag is already off page
01858              ( m_lastFormatted && bottom + m_lastFormatted->rect().height() > m_availableHeight ) ) // or next parag will be off page
01859             needMoreSpace = true;
01860         // default value of 'abort' depends on need more space
01861         bool abort = needMoreSpace;
01862         emit afterFormatting( bottom, m_lastFormatted, &abort );
01863         if ( abort )
01864             return false;
01865         else if ( needMoreSpace && m_lastFormatted ) // we got more space, keep formatting then
01866             return formatMore( 2 );
01867     }
01868 
01869     // Now let's see when we'll need to get back here.
01870     if ( m_lastFormatted )
01871     {
01872         formatTimer->setSingleShot( true );
01873         formatTimer->start( interval );
01874 #ifdef DEBUG_FORMAT_MORE
01875         kDebug(32500) << name() << " formatMore: will have to format more. formatTimer->start with interval=" << interval << endl;
01876 #endif
01877     }
01878     else
01879     {
01880         interval = qMax( 0, interval );
01881 #ifdef DEBUG_FORMAT_MORE
01882         kDebug(32500) << name() << " formatMore: all formatted interval=" << interval << endl;
01883 #endif
01884 #ifdef TIMING_FORMAT
01885         //if ( frameSetInfo() == FI_BODY )
01886         kDebug(32500) << "formatMore: " << name() << " all formatted. Took "
01887                        << (double)(m_time.elapsed()) / 1000 << " seconds." << endl;
01888 #endif
01889     }
01890     return true;
01891 }
01892 
01893 void KoTextObject::abortFormatting()
01894 {
01895     d->abortFormatting = true;
01896 }
01897 
01898 void KoTextObject::doChangeInterval()
01899 {
01900     //kDebug(32500) << "KoTextObject::doChangeInterval back to interval=0" << endl;
01901     interval = 0;
01902 }
01903 
01904 void KoTextObject::typingStarted()
01905 {
01906     //kDebug(32500) << "KoTextObject::typingStarted" << endl;
01907     startTimer->stop();
01908     interval = 10;
01909 }
01910 
01911 void KoTextObject::typingDone()
01912 {
01913     startTimer->setSingleShot( true );
01914     startTimer->start( 100 );
01915 }
01916 
01917 
01918 // helper for changeCaseOfText
01919 KCommand *KoTextObject::changeCaseOfTextParag( int cursorPosStart, int cursorPosEnd,
01920                                                KoChangeCaseDia::TypeOfCase _type,
01921                                                KoTextCursor *cursor, KoTextParag *parag )
01922 {
01923     if ( protectContent() )
01924         return 0L;
01925 
01926     KMacroCommand * macroCmd = new KMacroCommand( i18n("Change Case") );
01927     KoTextFormat *curFormat = parag->paragraphFormat();
01928     const QString text = parag->string()->toString().mid( cursorPosStart, cursorPosEnd - cursorPosStart );
01929     int posStart = cursorPosStart;
01930     int posEnd = cursorPosStart;
01931     KoTextCursor c1( textdoc );
01932     KoTextCursor c2( textdoc );
01933     //kDebug() << k_funcinfo << "from " << cursorPosStart << " to " << cursorPosEnd << " (excluded). Parag=" << parag << " length=" << parag->length() << endl;
01934     for ( int i = cursorPosStart; i < cursorPosEnd; ++i )
01935     {
01936         KoTextStringChar & ch = *(parag->at(i));
01937         KoTextFormat * newFormat = ch.format();
01938         if( ch.isCustom() )
01939         {
01940             posEnd = i;
01941             c1.setParag( parag );
01942             c1.setIndex( posStart );
01943             c2.setParag( parag );
01944             c2.setIndex( posEnd );
01945             //kDebug() << k_funcinfo << "found custom at " << i << " : doing from " << posStart << " to " << posEnd << endl;
01946 
01947             const QString repl = text.mid( posStart, posEnd - posStart );
01948             textdoc->setSelectionStart( KoTextDocument::Temp, &c1 );
01949             textdoc->setSelectionEnd( KoTextDocument::Temp, &c2 );
01950             macroCmd->addCommand(replaceSelectionCommand(
01951                                      cursor, textChangedCase(repl,_type),
01952                                      QString::null, KoTextDocument::Temp));
01953             do
01954             {
01955                 ++i;
01956             }
01957             while( parag->at(i)->isCustom() && i != cursorPosEnd);
01958             posStart=i;
01959             posEnd=i;
01960         }
01961         else
01962         {
01963             if ( newFormat != curFormat )
01964             {
01965                 posEnd=i;
01966                 c1.setParag( parag );
01967                 c1.setIndex( posStart );
01968                 c2.setParag( parag );
01969                 c2.setIndex( posEnd );
01970                 //kDebug() << k_funcinfo << "found new format at " << i << " : doing from " << posStart << " to " << posEnd << endl;
01971 
01972                 const QString repl = text.mid( posStart, posEnd - posStart );
01973                 textdoc->setSelectionStart( KoTextDocument::Temp, &c1 );
01974                 textdoc->setSelectionEnd( KoTextDocument::Temp, &c2 );
01975                 macroCmd->addCommand(replaceSelectionCommand(
01976                                          cursor, textChangedCase(repl,_type),
01977                                          QString::null, KoTextDocument::Temp));
01978                 posStart=i;
01979                 posEnd=i;
01980                 curFormat = newFormat;
01981             }
01982         }
01983     }
01984     if ( posStart != cursorPosEnd )
01985     {
01986         //kDebug() << k_funcinfo << "finishing: doing from " << posStart << " to " << cursorPosEnd << endl;
01987         c1.setParag( parag );
01988         c1.setIndex( posStart );
01989         c2.setParag( parag );
01990         c2.setIndex( cursorPosEnd );
01991 
01992         textdoc->setSelectionStart( KoTextDocument::Temp, &c1 );
01993         textdoc->setSelectionEnd( KoTextDocument::Temp, &c2 );
01994         const QString repl = text.mid( posStart, cursorPosEnd - posStart );
01995         macroCmd->addCommand(replaceSelectionCommand(
01996                                  cursor, textChangedCase(repl,_type),
01997                                  QString::null, KoTextDocument::Temp));
01998     }
01999     return macroCmd;
02000 
02001 }
02002 
02003 KCommand *KoTextObject::changeCaseOfText(KoTextCursor *cursor,KoChangeCaseDia::TypeOfCase _type)
02004 {
02005     if ( protectContent() )
02006         return 0L;
02007     KMacroCommand * macroCmd = new KMacroCommand( i18n("Change Case") );
02008 
02009     KoTextCursor start = textdoc->selectionStartCursor( KoTextDocument::Standard );
02010     KoTextCursor end = textdoc->selectionEndCursor( KoTextDocument::Standard );
02011     emit hideCursor();
02012 
02013     if ( start.parag() == end.parag() )
02014     {
02015         int endIndex = qMin( start.parag()->length() - 1, end.index() );
02016         macroCmd->addCommand( changeCaseOfTextParag( start.index(), endIndex, _type,
02017                                                      cursor, start.parag() ) );
02018     }
02019     else
02020     {
02021         macroCmd->addCommand( changeCaseOfTextParag( start.index(), start.parag()->length() - 1, _type,
02022                                                      cursor, start.parag() ) );
02023         KoTextParag *p = start.parag()->next();
02024         while ( p && p != end.parag() )
02025         {
02026             macroCmd->addCommand( changeCaseOfTextParag(0, p->length() - 1, _type, cursor, p ) );
02027             p = p->next();
02028         }
02029         if ( p )
02030         {
02031             int endIndex = qMin( p->length() - 1, end.index() );
02032             macroCmd->addCommand( changeCaseOfTextParag(0, endIndex, _type, cursor, end.parag() ));
02033         }
02034     }
02035     formatMore( 2 );
02036     emit repaintChanged( this );
02037     emit ensureCursorVisible();
02038     emit updateUI( true );
02039     emit showCursor();
02040     return macroCmd;
02041 }
02042 
02043 QString KoTextObject::textChangedCase(const QString& _text,KoChangeCaseDia::TypeOfCase _type)
02044 {
02045     QString text(_text);
02046     switch(_type)
02047     {
02048         case KoChangeCaseDia::UpperCase:
02049             text=text.toUpper();
02050             break;
02051         case KoChangeCaseDia::LowerCase:
02052             text=text.toLower();
02053             break;
02054         case KoChangeCaseDia::TitleCase:
02055             for(int i=0;i<text.length();i++)
02056             {
02057                 if(text.at(i)!=' ')
02058                 {
02059                     QChar prev = text.at(qMax(i-1,0));
02060                     if(i==0 || prev  == ' ' || prev == '\n' || prev == '\t')
02061                         text=text.replace(i, 1, text.at(i).toUpper() );
02062                     else
02063                         text=text.replace(i, 1, text.at(i).toLower() );
02064                 }
02065             }
02066             break;
02067         case KoChangeCaseDia::ToggleCase:
02068             for( int i=0; i<text.length(); i++ )
02069             {
02070                 QString repl=QString(text.at(i));
02071                 if( text.at(i) != text.at(i).toUpper() )
02072                     repl = repl.toUpper();
02073                 else if( text.at(i).toLower() != text.at(i) )
02074                     repl = repl.toLower();
02075                 text=text.replace(i, 1, repl );
02076             }
02077             break;
02078         case KoChangeCaseDia::SentenceCase:
02079             for(int i=0;i<text.length();i++)
02080             {
02081                 if(text.at(i)!=' ')
02082                 {
02083                     QChar prev = text.at(qMax(i-1,0));
02084                     if(i==0 || prev == '\n' ||prev.isPunct())
02085                         text = text.replace(i, 1, text.at(i).toUpper() );
02086                 }
02087             }
02088             break;
02089         default:
02090             kDebug(32500)<<"Error in changeCaseOfText !\n";
02091             break;
02092 
02093     }
02094     return text;
02095 }
02096 
02097 // Warning, this doesn't ref the format!
02098 KoTextFormat * KoTextObject::currentFormat() const
02099 {
02100     // We use the formatting of the very first character
02101     // Should we use a style instead, maybe ?
02102     KoTextStringChar *ch = textdoc->firstParag()->at( 0 );
02103     return ch->format();
02104 }
02105 
02106 const KoParagLayout * KoTextObject::currentParagLayoutFormat() const
02107 {
02108     KoTextParag * parag = textdoc->firstParag();
02109     return &(parag->paragLayout());
02110 }
02111 
02112 bool KoTextObject::rtl() const
02113 {
02114     return textdoc->firstParag()->string()->isRightToLeft();
02115 }
02116 
02117 void KoTextObject::loadOasisContent( const QDomElement &bodyElem, KoOasisContext& context, KoStyleCollection * styleColl )
02118 {
02119     textDocument()->clear(false); // Get rid of dummy paragraph (and more if any)
02120     setLastFormattedParag( 0L ); // no more parags, avoid UMR in next setLastFormattedParag call
02121 
02122     KoTextParag *lastParagraph = textDocument()->loadOasisText( bodyElem, context, 0, styleColl, 0 );
02123 
02124     if ( !lastParagraph )                // We created no paragraph
02125     {
02126         // Create an empty one, then. See KoTextDocument ctor.
02127         textDocument()->clear( true );
02128         textDocument()->firstParag()->setStyle( styleColl->findStyle( "Standard" ) );
02129     }
02130     else
02131         textDocument()->setLastParag( lastParagraph );
02132 
02133     setLastFormattedParag( textDocument()->firstParag() );
02134 }
02135 
02136 KoTextCursor KoTextObject::pasteOasisText( const QDomElement &bodyElem, KoOasisContext& context,
02137                                            KoTextCursor& cursor, KoStyleCollection * styleColl )
02138 {
02139     KoTextCursor resultCursor( cursor );
02140     KoTextParag* lastParagraph = cursor.parag();
02141     bool removeNewline = false;
02142     uint pos = cursor.index();
02143     if ( pos == 0 && lastParagraph->length() <= 1 ) {
02144         // Pasting on an empty paragraph -> respect <text:h> in selected text etc.
02145         lastParagraph = lastParagraph->prev();
02146         lastParagraph = textDocument()->loadOasisText( bodyElem, context, lastParagraph, styleColl, cursor.parag() );
02147         if ( lastParagraph ) {
02148             resultCursor.setParag( lastParagraph );
02149             resultCursor.setIndex( lastParagraph->length() - 1 );
02150         }
02151         removeNewline = true;
02152     } else {
02153         // Pasting inside a non-empty paragraph -> insert/append text to it.
02154         // This loop looks for the *FIRST* paragraph only.
02155         for ( QDomNode text (bodyElem.firstChild()); !text.isNull(); text = text.nextSibling() )
02156         {
02157             QDomElement tag = text.toElement();
02158             if ( tag.isNull() ) continue;
02159             // The first tag could be a text:p, text:h, text:numbered-paragraph, but also
02160             // a frame (anchored to page), a TOC, etc. For those, don't try to concat-with-existing-paragraph.
02161             // For text:numbered-paragraph, find the text:p or text:h inside it.
02162             QDomElement tagToLoad = tag;
02163             if ( tag.localName() == "numbered-paragraph" ) {
02164                 QDomElement npchild;
02165                 forEachElement( npchild, tag )
02166                 {
02167                     if ( npchild.localName() == "p" || npchild.localName() == "h" ) {
02168                         tagToLoad = npchild;
02169                         break;
02170                     }
02171                 }
02172             }
02173 
02174             if ( tagToLoad.localName() == "p" || tagToLoad.localName() == "h" ) {
02175                 context.styleStack().save();
02176                 context.fillStyleStack( tagToLoad, KoXmlNS::text, "style-name", "paragraph" );
02177                 lastParagraph->loadOasisSpan( tagToLoad, context, pos );
02178                 context.styleStack().restore();
02179 
02180                 lastParagraph->setChanged( true );
02181                 lastParagraph->invalidate( 0 );
02182 
02183                 // Now split this parag, to make room for the next paragraphs
02184                 resultCursor.setParag( lastParagraph );
02185                 resultCursor.setIndex( pos );
02186                 resultCursor.splitAndInsertEmptyParag( false, true );
02187                 removeNewline = true;
02188 
02189                 // Done with first parag, remove it and exit loop
02190                 const_cast<QDomElement &>( bodyElem ).removeChild( tag ); // somewhat hackish
02191             }
02192             break;
02193         }
02194         resultCursor.setParag( lastParagraph );
02195         resultCursor.setIndex( pos );
02196         // Load the rest the usual way.
02197         lastParagraph = textDocument()->loadOasisText( bodyElem, context, lastParagraph, styleColl, lastParagraph->next() );
02198         if ( lastParagraph != resultCursor.parag() ) // we loaded more paragraphs
02199         {
02200             removeNewline = true;
02201             resultCursor.setParag( lastParagraph );
02202             resultCursor.setIndex( lastParagraph->length() - 1 );
02203         }
02204     }
02205     KoTextParag* p = resultCursor.parag();
02206     if ( p ) p = p->next();
02207     // Remove the additional newline that loadOasisText inserted
02208     if ( removeNewline && resultCursor.remove() ) {
02209         if ( m_lastFormatted == p ) { // has been deleted
02210             m_lastFormatted = resultCursor.parag();
02211         }
02212     }
02213     return resultCursor;
02214 }
02215 
02216 void KoTextObject::saveOasisContent( KoXmlWriter& writer, KoSavingContext& context ) const
02217 {
02218     textDocument()->saveOasisContent( writer, context );
02219 }
02220 
02221 KCommand *KoTextObject::setParagLayoutFormatCommand( KoParagLayout *newLayout,int flags,int marginIndex)
02222 {
02223     if ( protectContent() )
02224         return 0L;
02225     textdoc->selectAll( KoTextDocument::Temp );
02226     KoTextCursor *cursor = new KoTextCursor( textdoc );
02227     KCommand* cmd = setParagLayoutCommand( cursor, *newLayout, KoTextDocument::Temp,
02228                                            flags, marginIndex, true /*createUndoRedo*/ );
02229     textdoc->removeSelection( KoTextDocument::Temp );
02230     delete cursor;
02231     return cmd;
02232 }
02233 
02234 void KoTextObject::setFormat( KoTextFormat * newFormat, int flags, bool zoomFont )
02235 {
02236     if ( protectContent() )
02237         return ;
02238     // This version of setFormat works on the whole textobject - we use the Temp selection for that
02239     textdoc->selectAll( KoTextDocument::Temp );
02240     KCommand *cmd = setFormatCommand( 0L, 0L, newFormat,
02241                                       flags, zoomFont, KoTextDocument::Temp );
02242     textdoc->removeSelection( KoTextDocument::Temp );
02243     if (cmd)
02244         emit newCommand( cmd );
02245 
02246     KoTextFormat format = *currentFormat();
02247     //format.setPointSize( docFontSize( currentFormat() ) ); // "unzoom" the font size
02248     emit showFormatObject(format);
02249 }
02250 
02251 KCommand *KoTextObject::setChangeCaseOfTextCommand(KoChangeCaseDia::TypeOfCase _type)
02252 {
02253     if ( protectContent() )
02254         return 0L;
02255     textdoc->selectAll( KoTextDocument::Standard );
02256     KoTextCursor *cursor = new KoTextCursor( textdoc );
02257     KCommand* cmd = changeCaseOfText(cursor, _type);
02258     textdoc->removeSelection( KoTextDocument::Standard );
02259     delete cursor;
02260     return cmd;
02261 }
02262 
02263 void KoTextObject::setNeedSpellCheck(bool b)
02264 {
02265     m_needsSpellCheck = b;
02266     for (KoTextParag * parag = textdoc->firstParag(); parag ; parag = parag->next())
02267         parag->string()->setNeedsSpellCheck( b );
02268 }
02269 
02270 bool KoTextObject::statistics( QProgressDialog *progress, ulong & charsWithSpace, ulong & charsWithoutSpace, ulong & words, ulong & sentences, ulong & syllables, ulong & lines, bool selected )
02271 {
02272     // parts of words for better counting of syllables:
02273     // (only use reg exp if necessary -> speed up)
02274 
02275     QStringList subs_syl;
02276     subs_syl << "cial" << "tia" << "cius" << "cious" << "giu" << "ion" << "iou";
02277     QStringList subs_syl_regexp;
02278     subs_syl_regexp << "sia$" << "ely$";
02279 
02280     QStringList add_syl;
02281     add_syl << "ia" << "riet" << "dien" << "iu" << "io" << "ii";
02282     QStringList add_syl_regexp;
02283     add_syl_regexp << "[aeiouym]bl$" << "[aeiou]{3}" << "^mc" << "ism$"
02284         << "[^l]lien" << "^coa[dglx]." << "[^gq]ua[^auieo]" << "dnt$";
02285 
02286     QString s;
02287     KoTextParag * parag = textdoc->firstParag();
02288     for ( ; parag ; parag = parag->next() )
02289     {
02290         if (  progress )
02291         {
02292             progress->setValue(progress->value()+1);
02293             // MA: resizing if KWStatisticsDialog does not work correct with this enabled, don't know why
02294             kapp->processEvents();
02295             if ( progress->wasCanceled() )
02296                 return false;
02297         }
02298         // start of a table
02299 /*        if ( parag->at(0)->isCustom())
02300         {
02301             KoLinkVariable *var=dynamic_cast<KoLinkVariable *>(parag->at(0)->customItem());
02302             if(!var)
02303                 continue;
02304                 }*/
02305         bool hasTrailingSpace = true;
02306         if ( !selected ) {
02307             s = parag->string()->toString();
02308             lines += parag->lines();
02309         } else {
02310             if ( parag->hasSelection( KoTextDocument::Standard ) ) {
02311                 hasTrailingSpace = false;
02312                 s = parag->string()->toString();
02313                 if ( !( parag->fullSelected( KoTextDocument::Standard ) ) ) {
02314                     s = s.mid( parag->selectionStart( KoTextDocument::Standard ), parag->selectionEnd( KoTextDocument::Standard ) - parag->selectionStart( KoTextDocument::Standard ) );
02315                     lines+=numberOfparagraphLineSelected(parag);
02316                 }
02317                 else
02318                     lines += parag->lines();
02319             } else {
02320                 continue;
02321             }
02322         }
02323 
02324         // Character count
02325         for ( int i = 0 ; i < s.length() - ( hasTrailingSpace ? 1 : 0 ) ; ++i )
02326         {
02327             QChar ch = s[i];
02328             ++charsWithSpace;
02329             if ( !ch.isSpace() )
02330                 ++charsWithoutSpace;
02331         }
02332 
02333         // Syllable and Word count
02334         // Algorithm mostly taken from Greg Fast's Lingua::EN::Syllable module for Perl.
02335         // This guesses correct for 70-90% of English words, but the overall value
02336         // is quite good, as some words get a number that's too high and others get
02337         // one that's too low.
02338         // IMPORTANT: please test any changes against demos/statistics.kwd
02339         QRegExp re("\\s+");
02340         QStringList wordlist = s.split( re );
02341         words += wordlist.count();
02342         re.setCaseSensitivity( Qt::CaseInsensitive );
02343         foreach( QString word, wordlist )
02344         {
02345             re.setPattern("[!?.,:_\"-]");    // clean word from punctuation
02346             word.remove(re);
02347             if ( word.length() <= 3 ) {  // extension to the original algorithm
02348                 syllables++;
02349                 continue;
02350             }
02351             re.setPattern("e$");
02352             word.remove(re);
02353             re.setPattern("[^aeiouy]+");
02354             QStringList syls = word.split( re );
02355             int word_syllables = 0;
02356             foreach( QString tmp, subs_syl )
02357             {
02358                 if( word.contains( tmp, Qt::CaseInsensitive) )
02359                     word_syllables--;
02360             }
02361             foreach( QString tmp, subs_syl_regexp )
02362             {
02363                 re.setPattern( tmp );
02364                 if( word.contains( re ) )
02365                     word_syllables--;
02366             }
02367             foreach( QString tmp, add_syl )
02368             {
02369                 if( word.contains( tmp, Qt::CaseInsensitive ) )
02370                     word_syllables++;
02371             }
02372             foreach( QString tmp, add_syl_regexp )
02373             {
02374                 re.setPattern( tmp );
02375                 if( word.contains( re ) )
02376                     word_syllables++;
02377             }
02378             word_syllables += syls.count();
02379             if ( word_syllables == 0 )
02380                 word_syllables = 1;
02381             syllables += word_syllables;
02382         }
02383         re.setCaseSensitivity( Qt::CaseSensitive );
02384 
02385         // Sentence count
02386         // Clean up for better result, destroys the original text but we only want to count
02387         s = s.trimmed();
02388         QChar lastchar = s.at(s.length());
02389         if( ! s.isEmpty() && ! KoAutoFormat::isMark( lastchar ) ) {  // e.g. for headlines
02390             s = s + '.';
02391         }
02392         re.setPattern("[.?!]+");         // count "..." as only one "."
02393         s.replace(re, ".");
02394         re.setPattern("\\d\\.\\d");      // don't count floating point numbers as sentences
02395         s.replace(re, "0,0");
02396         re.setPattern("[A-Z]\\.+");      // don't count "U.S.A." as three sentences
02397         s.replace(re, "*");
02398         for ( int i = 0 ; i < s.length() ; ++i )
02399         {
02400             QChar ch = s[i];
02401             if ( KoAutoFormat::isMark( ch ) )
02402                 ++sentences;
02403         }
02404     }
02405     return true;
02406 }
02407 
02408 int KoTextObject::numberOfparagraphLineSelected( KoTextParag *parag)
02409 {
02410     int indexOfLineStart;
02411     int lineStart;
02412     int lineEnd;
02413     KoTextCursor c1 = textdoc->selectionStartCursor( KoTextDocument::Standard );
02414     KoTextCursor c2 = textdoc->selectionEndCursor( KoTextDocument::Standard );
02415     parag->lineStartOfChar( c1.index(), &indexOfLineStart, &lineStart );
02416 
02417     parag->lineStartOfChar( c2.index(), &indexOfLineStart, &lineEnd );
02418     return (lineEnd - lineStart+1);
02419 }
02420 
02421 KoVariable* KoTextObject::variableAtPoint( const QPoint& iPoint ) const
02422 {
02423     KoTextCursor cursor( textDocument() );
02424     int variablePosition = -1;
02425     cursor.place( iPoint, textDocument()->firstParag(), false, &variablePosition );
02426     if ( variablePosition == -1 )
02427         return 0;
02428     return variableAtPosition( cursor.parag(), variablePosition );
02429 }
02430 
02431 KoVariable* KoTextObject::variableAtPosition( KoTextParag* parag, int index ) const
02432 {
02433     KoTextStringChar * ch = parag->at( index );
02434     if ( ch->isCustom() )
02435         return dynamic_cast<KoVariable *>( ch->customItem() );
02436     return 0;
02437 }
02438 
02439 QString KoTextObject::acceptSelectionMimeType()
02440 {
02441     return QString::fromLatin1( "application/vnd.oasis.opendocument." );
02442 }
02443 
02444 QString KoTextObject::providesOasis( const QMimeData* mime )
02445 {
02446     const QString acceptMimeType = acceptSelectionMimeType();
02447     const QStringList formats = mime->formats();
02448     foreach( const QString format, formats )
02449     {
02450         if ( format.startsWith( acceptMimeType ) )
02451         {
02452             return format;
02453         }
02454     }
02455     return QString();
02456 }
02457 
02458 #ifndef NDEBUG
02459 void KoTextObject::printRTDebug(int info)
02460 {
02461     KoTextParag* lastParag = 0;
02462     for (KoTextParag * parag = textdoc->firstParag(); parag ; parag = parag->next())
02463     {
02464         assert( parag->prev() == lastParag );
02465         parag->printRTDebug( info );
02466         lastParag = parag;
02467     }
02468     if ( info == 1 )
02469         textdoc->formatCollection()->debug();
02470 }
02471 #endif
02472 
02474 
02475 KCommand *KoTextFormatInterface::setBoldCommand(bool on)
02476 {
02477     KoTextFormat format( *currentFormat() );
02478     format.setBold( on );
02479     return setFormatCommand( &format, KoTextFormat::Bold );
02480 }
02481 
02482 KCommand *KoTextFormatInterface::setItalicCommand( bool on)
02483 {
02484     KoTextFormat format( *currentFormat() );
02485     format.setItalic( on );
02486     return setFormatCommand( &format, KoTextFormat::Italic );
02487 }
02488 
02489 KCommand *KoTextFormatInterface::setUnderlineCommand( bool on )
02490 {
02491     KoTextFormat format( *currentFormat() );
02492     format.setUnderlineType( on ? KoTextFormat::U_SIMPLE : KoTextFormat::U_NONE);
02493     return setFormatCommand( &format, KoTextFormat::ExtendUnderLine );
02494 }
02495 
02496 KCommand *KoTextFormatInterface::setUnderlineColorCommand( const QColor &color )
02497 {
02498     KoTextFormat format( *currentFormat() );
02499     format.setTextUnderlineColor( color);
02500     return setFormatCommand( &format, KoTextFormat::ExtendUnderLine );
02501 }
02502 
02503 KCommand *KoTextFormatInterface::setDoubleUnderlineCommand( bool on )
02504 {
02505     KoTextFormat format( *currentFormat() );
02506     format.setUnderlineType( on ? KoTextFormat::U_DOUBLE : KoTextFormat::U_NONE);
02507     return setFormatCommand( &format, KoTextFormat::ExtendUnderLine );
02508 }
02509 
02510 KCommand *KoTextFormatInterface::setStrikeOutCommand( bool on )
02511 {
02512     KoTextFormat format( *currentFormat() );
02513     format.setStrikeOutType( on ? KoTextFormat::S_SIMPLE : KoTextFormat::S_NONE);
02514     return setFormatCommand( &format, KoTextFormat::StrikeOut );
02515 }
02516 
02517 KCommand *KoTextFormatInterface::setTextBackgroundColorCommand(const QColor & col)
02518 {
02519     KoTextFormat format( *currentFormat() );
02520     format.setTextBackgroundColor( col );
02521     return setFormatCommand( &format, KoTextFormat::TextBackgroundColor );
02522 }
02523 
02524 KCommand *KoTextFormatInterface::setPointSizeCommand( int s )
02525 {
02526     KoTextFormat format( *currentFormat() );
02527     format.setPointSize( s );
02528     return setFormatCommand( &format, KoTextFormat::Size, true /* zoom the font size */ );
02529 }
02530 
02531 KCommand *KoTextFormatInterface::setFamilyCommand(const QString &font)
02532 {
02533     KoTextFormat format( *currentFormat() );
02534     format.setFamily( font );
02535     return setFormatCommand( &format, KoTextFormat::Family );
02536 }
02537 
02538 QColor KoTextFormatInterface::textBackgroundColor() const
02539 {
02540     return currentFormat()->textBackgroundColor();
02541 }
02542 
02543 QColor KoTextFormatInterface::textUnderlineColor()const
02544 {
02545     return currentFormat()->textUnderlineColor();
02546 }
02547 
02548 QColor KoTextFormatInterface::textColor() const
02549 {
02550     return currentFormat()->color();
02551 }
02552 
02553 bool KoTextFormatInterface::textUnderline()const
02554 {
02555     return currentFormat()->underline();
02556 }
02557 
02558 bool KoTextFormatInterface::textDoubleUnderline()const
02559 {
02560     return currentFormat()->doubleUnderline();
02561 }
02562 
02563 bool KoTextFormatInterface::textBold()const
02564 {
02565     return currentFormat()->font().bold();
02566 }
02567 
02568 bool KoTextFormatInterface::textStrikeOut()const
02569 {
02570     return currentFormat()->font().strikeOut();
02571 }
02572 
02573 bool KoTextFormatInterface::textItalic() const
02574 {
02575     return currentFormat()->font().italic();
02576 }
02577 
02578 bool KoTextFormatInterface::textSubScript() const
02579 {
02580     return (currentFormat()->vAlign()==KoTextFormat::AlignSubScript);
02581 }
02582 
02583 bool KoTextFormatInterface::textSuperScript() const
02584 {
02585     return (currentFormat()->vAlign()==KoTextFormat::AlignSuperScript);
02586 }
02587 
02588 double KoTextFormatInterface::shadowDistanceX() const
02589 {
02590     return currentFormat()->shadowDistanceX();
02591 }
02592 
02593 double KoTextFormatInterface::shadowDistanceY() const
02594 {
02595     return currentFormat()->shadowDistanceY();
02596 }
02597 
02598 QColor KoTextFormatInterface::shadowColor() const
02599 {
02600     return currentFormat()->shadowColor();
02601 }
02602 
02603 KoTextFormat::AttributeStyle KoTextFormatInterface::fontAttribute() const
02604 {
02605     return currentFormat()->attributeFont();
02606 }
02607 
02608 double KoTextFormatInterface::relativeTextSize() const
02609 {
02610     return currentFormat()->relativeTextSize();
02611 }
02612 
02613 int KoTextFormatInterface::offsetFromBaseLine()const
02614 {
02615     return currentFormat()->offsetFromBaseLine();
02616 }
02617 
02618 bool KoTextFormatInterface::wordByWord()const
02619 {
02620     return currentFormat()->wordByWord();
02621 }
02622 
02623 bool KoTextFormatInterface::hyphenation()const
02624 {
02625     return currentFormat()->hyphenation();
02626 }
02627 
02628 KoTextFormat::UnderlineType KoTextFormatInterface::underlineType()const
02629 {
02630     return currentFormat()->underlineType();
02631 }
02632 
02633 KoTextFormat::StrikeOutType KoTextFormatInterface::strikeOutType()const
02634 {
02635     return currentFormat()->strikeOutType();
02636 }
02637 
02638 KoTextFormat::UnderlineStyle KoTextFormatInterface::underlineStyle()const
02639 {
02640     return currentFormat()->underlineStyle();
02641 }
02642 
02643 KoTextFormat::StrikeOutStyle KoTextFormatInterface::strikeOutStyle()const
02644 {
02645     return currentFormat()->strikeOutStyle();
02646 }
02647 
02648 QFont KoTextFormatInterface::textFont() const
02649 {
02650     QFont fn( currentFormat()->font() );
02651     // "unzoom" the font size
02652     //fn.setPointSize( static_cast<int>( KoTextZoomHandler::layoutUnitPtToPt( fn.pointSize() ) ) );
02653     return fn;
02654 }
02655 
02656 QString KoTextFormatInterface::textFontFamily()const
02657 {
02658     return currentFormat()->font().family();
02659 }
02660 
02661 QString KoTextFormatInterface::language() const
02662 {
02663     return currentFormat()->language();
02664 }
02665 
02666 KCommand *KoTextFormatInterface::setTextColorCommand(const QColor &color)
02667 {
02668     KoTextFormat format( *currentFormat() );
02669     format.setColor( color );
02670     return setFormatCommand( &format, KoTextFormat::Color );
02671 }
02672 
02673 KCommand *KoTextFormatInterface::setTextSubScriptCommand(bool on)
02674 {
02675     KoTextFormat format( *currentFormat() );
02676     if(!on)
02677         format.setVAlign(KoTextFormat::AlignNormal);
02678     else
02679         format.setVAlign(KoTextFormat::AlignSubScript);
02680     return setFormatCommand( &format, KoTextFormat::VAlign );
02681 }
02682 
02683 KCommand *KoTextFormatInterface::setTextSuperScriptCommand(bool on)
02684 {
02685     KoTextFormat format( *currentFormat() );
02686     if(!on)
02687         format.setVAlign(KoTextFormat::AlignNormal);
02688     else
02689         format.setVAlign(KoTextFormat::AlignSuperScript);
02690     return setFormatCommand( &format, KoTextFormat::VAlign );
02691 }
02692 
02693 KCommand *KoTextFormatInterface::setDefaultFormatCommand()
02694 {
02695     KoTextFormatCollection * coll = currentFormat()->parent();
02696     Q_ASSERT(coll);
02697     if(coll)
02698     {
02699         KoTextFormat * format = coll->defaultFormat();
02700         return setFormatCommand( format, KoTextFormat::Format );
02701     } else {
02702         kDebug() << "useless call to setDefaultFormatCommand at: " << kBacktrace() << endl;
02703     }
02704     return 0;
02705 }
02706 
02707 KCommand *KoTextFormatInterface::setAlignCommand(int align)
02708 {
02709     KoParagLayout format( *currentParagLayoutFormat() );
02710     format.alignment=align;
02711     return setParagLayoutFormatCommand(&format,KoParagLayout::Alignment);
02712 }
02713 
02714 KCommand *KoTextFormatInterface::setHyphenationCommand( bool _b )
02715 {
02716     KoTextFormat format( *currentFormat() );
02717     format.setHyphenation( _b );
02718     return setFormatCommand( &format, KoTextFormat::Hyphenation);
02719 }
02720 
02721 
02722 KCommand *KoTextFormatInterface::setShadowTextCommand( double shadowDistanceX, double shadowDistanceY, const QColor& shadowColor )
02723 {
02724     KoTextFormat format( *currentFormat() );
02725     format.setShadow( shadowDistanceX, shadowDistanceY, shadowColor );
02726     return setFormatCommand( &format, KoTextFormat::ShadowText );
02727 }
02728 
02729 KCommand *KoTextFormatInterface::setFontAttributeCommand( KoTextFormat::AttributeStyle _att)
02730 {
02731     KoTextFormat format( *currentFormat() );
02732     format.setAttributeFont( _att );
02733     return setFormatCommand( &format, KoTextFormat::Attribute );
02734 }
02735 
02736 KCommand *KoTextFormatInterface::setRelativeTextSizeCommand( double _size )
02737 {
02738     KoTextFormat format( *currentFormat() );
02739     format.setRelativeTextSize( _size );
02740     return setFormatCommand( &format, KoTextFormat::VAlign );
02741 }
02742 
02743 KCommand *KoTextFormatInterface::setOffsetFromBaseLineCommand( int _offset )
02744 {
02745     KoTextFormat format( *currentFormat() );
02746     format.setOffsetFromBaseLine( _offset );
02747     return setFormatCommand( &format, KoTextFormat::OffsetFromBaseLine );
02748 }
02749 
02750 KCommand *KoTextFormatInterface::setWordByWordCommand( bool _b )
02751 {
02752     KoTextFormat format( *currentFormat() );
02753     format.setWordByWord( _b );
02754     return setFormatCommand( &format, KoTextFormat::WordByWord );
02755 }
02756 
02757 #if 0
02758 void KoTextFormatInterface::setAlign(int align)
02759 {
02760     KCommand *cmd = setAlignCommand( align );
02761     emitNewCommand( cmd );
02762 }
02763 
02764 void KoTextFormatInterface::setMargin(Q3StyleSheetItem::Margin m, double margin)
02765 {
02766     KCommand *cmd = setMarginCommand( m, margin );
02767     emitNewCommand( cmd );
02768 }
02769 
02770 void KoTextFormatInterface::setTabList(const KoTabulatorList & tabList )
02771 {
02772     KCommand *cmd = setTabListCommand( tabList );
02773     emitNewCommand( cmd );
02774 }
02775 
02776 void KoTextFormatInterface::setCounter(const KoParagCounter & counter )
02777 {
02778     KCommand *cmd = setCounterCommand( counter );
02779     emitNewCommand( cmd );
02780 }
02781 
02782 void KoTextFormatInterface::setParagLayoutFormat( KoParagLayout *newLayout, int flags, int marginIndex)
02783 {
02784     KCommand *cmd = setParagLayoutFormatCommand(newLayout, flags, marginIndex);
02785     emitNewCommand( cmd );
02786 }
02787 #endif
02788 
02789 KCommand *KoTextFormatInterface::setMarginCommand(Q3StyleSheetItem::Margin m, double margin)
02790 {
02791     KoParagLayout format( *currentParagLayoutFormat() );
02792     format.margins[m]=margin;
02793     return setParagLayoutFormatCommand(&format,KoParagLayout::Margins,(int)m);
02794 }
02795 
02796 KCommand *KoTextFormatInterface::setTabListCommand(const KoTabulatorList & tabList )
02797  {
02798     KoParagLayout format( *currentParagLayoutFormat() );
02799     format.setTabList(tabList);
02800     return setParagLayoutFormatCommand(&format,KoParagLayout::Tabulator);
02801 }
02802 
02803 KCommand *KoTextFormatInterface::setCounterCommand(const KoParagCounter & counter )
02804 {
02805     KoParagLayout format( *currentParagLayoutFormat() );
02806     if(!format.counter)
02807         format.counter = new KoParagCounter;
02808     *format.counter = counter;
02809     return setParagLayoutFormatCommand(&format,KoParagLayout::BulletNumber);
02810 }
02811 
02812 KCommand *KoTextFormatInterface::setLanguageCommand(const QString &_lang)
02813 {
02814     KoTextFormat format( *currentFormat() );
02815     format.setLanguage(_lang);
02816     return setFormatCommand( &format, KoTextFormat::Language );
02817 }
02818 
02819 KoTextDocCommand *KoTextFormatInterface::deleteTextCommand( KoTextDocument *textdoc, int id, int index, const Q3MemArray<KoTextStringChar> & str, const CustomItemsMap & customItemsMap, const Q3ValueList<KoParagLayout> & oldParagLayouts )
02820 {
02821     return textdoc->deleteTextCommand( textdoc, id, index, str, customItemsMap, oldParagLayouts );
02822 }
02823 
02824 #include "KoTextObject.moc"

Généré le Wed Nov 22 23:41:10 2006 pour KPlato par  doxygen 1.5.1-p1