lib

KoTextObject.cpp

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