00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "KoTextDocument.h"
00021 #include "KoTextParag.h"
00022 #include "KoTextZoomHandler.h"
00023 #include "KoTextFormatter.h"
00024 #include "KoTextFormat.h"
00025 #include "KoParagCounter.h"
00026 #include "KoTextCommand.h"
00027 #include "KoOasisContext.h"
00028 #include "KoVariable.h"
00029 #include <KoXmlWriter.h>
00030 #include <KoXmlNS.h>
00031 #include <KoDom.h>
00032 #include <kdebug.h>
00033 #include <kdeversion.h>
00034 #include <QApplication>
00035
00036 #include <QPixmap>
00037 #include <Q3MemArray>
00038 #include <Q3PtrList>
00039 #include <Q3ValueList>
00040 #include <assert.h>
00041
00042
00043
00046
00047 KoTextDocument::KoTextDocument( KoTextZoomHandler *zoomHandler, KoTextFormatCollection *fc,
00048 KoTextFormatter *formatter, bool createInitialParag )
00049 : m_zoomHandler( zoomHandler ),
00050 m_bDestroying( false ),
00051 #ifdef QTEXTTABLE_AVAILABLE
00052 par( 0L ),
00053 tc( 0 ),
00054 #endif
00055 tArray( 0 ), tStopWidth( 0 )
00056 {
00057 fCollection = fc;
00058 init();
00059
00060 m_drawingFlags = 0;
00061 if ( !formatter )
00062 formatter = new KoTextFormatter;
00063 setFormatter( formatter );
00064
00065 setY( 0 );
00066 setLeftMargin( 0 );
00067 setRightMargin( 0 );
00068
00069
00070 if ( !createInitialParag )
00071 clear( false );
00072 }
00073
00074 void KoTextDocument::init()
00075 {
00076
00077 useFC = true;
00078 pFormatter = 0;
00079 fParag = 0;
00080 m_pageBreakEnabled = false;
00081
00082 align = Qt::AlignLeft;
00083 nSelections = 2;
00084
00085 underlLinks = true;
00086 backBrush = 0;
00087 buf_pixmap = 0;
00088
00089
00090
00091
00092
00093 withoutDoubleBuffer = false;
00094
00095 lParag = fParag = createParag( this, 0, 0 );
00096
00097
00098
00099
00100 cx = cy = 0;
00101
00102
00103 flow_ = new KoTextFlow;
00104
00105
00106 leftmargin = 0;
00107 rightmargin = 0;
00108
00109 selectionColors[ Standard ] = QApplication::palette().color( QPalette::Active, QColorGroup::Highlight );
00110 selectionText[ Standard ] = true;
00111 assert( Standard < nSelections );
00112 selectionText[ InputMethodPreedit ] = false;
00113 assert( InputMethodPreedit < nSelections );
00114 commandHistory = new KoTextDocCommandHistory( 100 );
00115 tStopWidth = formatCollection()->defaultFormat()->width( 'x' ) * 8;
00116 }
00117
00118 KoTextDocument::~KoTextDocument()
00119 {
00120
00121
00123 m_bDestroying = true;
00124 clear( false );
00126 delete commandHistory;
00127 delete flow_;
00128
00129 delete pFormatter;
00130 delete fCollection;
00131
00132 delete buf_pixmap;
00133 delete backBrush;
00134 if ( tArray )
00135 delete [] tArray;
00136 }
00137
00138 void KoTextDocument::clear( bool createEmptyParag )
00139 {
00140 if ( flow_ )
00141 flow_->clear();
00142 while ( fParag ) {
00143 KoTextParag *p = fParag->next();
00144 fParag->string()->clear();
00145 delete fParag;
00146 fParag = p;
00147 }
00148 fParag = lParag = 0;
00149 if ( createEmptyParag )
00150 fParag = lParag = createParag( this );
00151 selections.clear();
00152 customItems.clear();
00153 }
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 int KoTextDocument::height() const
00176 {
00177 int h = 0;
00178 if ( lParag )
00179 h = lParag->rect().top() + lParag->rect().height() + 1;
00180
00181
00182 return h;
00183 }
00184
00185
00186 KoTextParag *KoTextDocument::createParag( KoTextDocument *d, KoTextParag *pr, KoTextParag *nx, bool updateIds )
00187 {
00188 return new KoTextParag( d, pr, nx, updateIds );
00189 }
00190
00191 void KoTextDocument::setPlainText( const QString &text )
00192 {
00193 clear();
00194
00195
00196
00197
00198 int lastNl = 0;
00199 int nl = text.find( '\n' );
00200 if ( nl == -1 ) {
00201 lParag = createParag( this, lParag, 0 );
00202 if ( !fParag )
00203 fParag = lParag;
00204 QString s = text;
00205 if ( !s.isEmpty() ) {
00206 if ( s[ (int)s.length() - 1 ] == '\r' )
00207 s.remove( s.length() - 1, 1 );
00208 lParag->append( s );
00209 }
00210 } else {
00211 for (;;) {
00212 lParag = createParag( this, lParag, 0 );
00213 if ( !fParag )
00214 fParag = lParag;
00215 QString s = text.mid( lastNl, nl - lastNl );
00216 if ( !s.isEmpty() ) {
00217 if ( s[ (int)s.length() - 1 ] == '\r' )
00218 s.remove( s.length() - 1, 1 );
00219 lParag->append( s );
00220 }
00221 if ( nl == 0xffffff )
00222 break;
00223 lastNl = nl + 1;
00224 nl = text.find( '\n', nl + 1 );
00225 if ( nl == -1 )
00226 nl = 0xffffff;
00227 }
00228 }
00229 if ( !lParag )
00230 lParag = fParag = createParag( this, 0, 0 );
00231 }
00232
00233 void KoTextDocument::setText( const QString &text, const QString & )
00234 {
00235 selections.clear();
00236 setPlainText( text );
00237 }
00238
00239 QString KoTextDocument::plainText() const
00240 {
00241 QString buffer;
00242 QString s;
00243 KoTextParag *p = fParag;
00244 while ( p ) {
00245 s = p->string()->toString();
00246 s.remove( s.length() - 1, 1 );
00247 if ( p->next() )
00248 s += '\n';
00249 buffer += s;
00250 p = p->next();
00251 }
00252 return buffer;
00253 }
00254
00255 void KoTextDocument::invalidate()
00256 {
00257 KoTextParag *s = fParag;
00258 while ( s ) {
00259 s->invalidate( 0 );
00260 s = s->next();
00261 }
00262 }
00263
00264 void KoTextDocument::informParagraphDeleted( KoTextParag* parag )
00265 {
00266 QMap<int, KoTextDocumentSelection>::Iterator it = selections.begin();
00267 for ( ; it != selections.end(); ++it )
00268 {
00269 if ( (*it).startCursor.parag() == parag ) {
00270 if ( parag->prev() ) {
00271 KoTextParag* prevP = parag->prev();
00272 (*it).startCursor.setParag( prevP );
00273 (*it).startCursor.setIndex( prevP->length()-1 );
00274 } else
00275 (*it).startCursor.setParag( parag->next() );
00276 }
00277 if ( (*it).endCursor.parag() == parag ) {
00278 if ( parag->prev() ) {
00279 KoTextParag* prevP = parag->prev();
00280 (*it).endCursor.setParag( prevP );
00281 (*it).endCursor.setIndex( prevP->length()-1 );
00282 } else
00283 (*it).endCursor.setParag( parag->next() );
00284 }
00285 }
00286 emit paragraphDeleted( parag );
00287 }
00288
00289 void KoTextDocument::selectionStart( int id, int ¶gId, int &index )
00290 {
00291 QMap<int, KoTextDocumentSelection>::Iterator it = selections.find( id );
00292 if ( it == selections.end() )
00293 return;
00294 KoTextDocumentSelection &sel = *it;
00295 paragId = !sel.swapped ? sel.startCursor.parag()->paragId() : sel.endCursor.parag()->paragId();
00296 index = !sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
00297 }
00298
00299 KoTextCursor KoTextDocument::selectionStartCursor( int id)
00300 {
00301 QMap<int, KoTextDocumentSelection>::Iterator it = selections.find( id );
00302 if ( it == selections.end() )
00303 return KoTextCursor( this );
00304 KoTextDocumentSelection &sel = *it;
00305 if ( sel.swapped )
00306 return sel.endCursor;
00307 return sel.startCursor;
00308 }
00309
00310 KoTextCursor KoTextDocument::selectionEndCursor( int id)
00311 {
00312 QMap<int, KoTextDocumentSelection>::Iterator it = selections.find( id );
00313 if ( it == selections.end() )
00314 return KoTextCursor( this );
00315 KoTextDocumentSelection &sel = *it;
00316 if ( !sel.swapped )
00317 return sel.endCursor;
00318 return sel.startCursor;
00319 }
00320
00321 void KoTextDocument::selectionEnd( int id, int ¶gId, int &index )
00322 {
00323 QMap<int, KoTextDocumentSelection>::Iterator it = selections.find( id );
00324 if ( it == selections.end() )
00325 return;
00326 KoTextDocumentSelection &sel = *it;
00327 paragId = sel.swapped ? sel.startCursor.parag()->paragId() : sel.endCursor.parag()->paragId();
00328 index = sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
00329 }
00330
00331 bool KoTextDocument::isSelectionSwapped( int id )
00332 {
00333 QMap<int, KoTextDocumentSelection>::Iterator it = selections.find( id );
00334 if ( it == selections.end() )
00335 return false;
00336 KoTextDocumentSelection &sel = *it;
00337 return sel.swapped;
00338 }
00339
00340 KoTextParag *KoTextDocument::selectionStart( int id )
00341 {
00342 QMap<int, KoTextDocumentSelection>::Iterator it = selections.find( id );
00343 if ( it == selections.end() )
00344 return 0;
00345 KoTextDocumentSelection &sel = *it;
00346 if ( sel.startCursor.parag()->paragId() < sel.endCursor.parag()->paragId() )
00347 return sel.startCursor.parag();
00348 return sel.endCursor.parag();
00349 }
00350
00351 KoTextParag *KoTextDocument::selectionEnd( int id )
00352 {
00353 QMap<int, KoTextDocumentSelection>::Iterator it = selections.find( id );
00354 if ( it == selections.end() )
00355 return 0;
00356 KoTextDocumentSelection &sel = *it;
00357 if ( sel.startCursor.parag()->paragId() > sel.endCursor.parag()->paragId() )
00358 return sel.startCursor.parag();
00359 return sel.endCursor.parag();
00360 }
00361
00362 void KoTextDocument::addSelection( int id )
00363 {
00364 nSelections = qMax( nSelections, id + 1 );
00365 }
00366
00367 static void setSelectionEndHelper( int id, KoTextDocumentSelection &sel, KoTextCursor &start, KoTextCursor &end )
00368 {
00369 KoTextCursor c1 = start;
00370 KoTextCursor c2 = end;
00371 if ( sel.swapped ) {
00372 c1 = end;
00373 c2 = start;
00374 }
00375
00376 c1.parag()->removeSelection( id );
00377 c2.parag()->removeSelection( id );
00378 if ( c1.parag() != c2.parag() ) {
00379 c1.parag()->setSelection( id, c1.index(), c1.parag()->length() - 1 );
00380 c2.parag()->setSelection( id, 0, c2.index() );
00381 } else {
00382 c1.parag()->setSelection( id, qMin( c1.index(), c2.index() ), qMax( c1.index(), c2.index() ) );
00383 }
00384
00385 sel.startCursor = start;
00386 sel.endCursor = end;
00387 if ( sel.startCursor.parag() == sel.endCursor.parag() )
00388 sel.swapped = sel.startCursor.index() > sel.endCursor.index();
00389 }
00390
00391 bool KoTextDocument::setSelectionEnd( int id, KoTextCursor *cursor )
00392 {
00393 QMap<int, KoTextDocumentSelection>::Iterator it = selections.find( id );
00394 if ( it == selections.end() )
00395 return false;
00396 KoTextDocumentSelection &sel = *it;
00397
00398 KoTextCursor start = sel.startCursor;
00399 KoTextCursor end = *cursor;
00400
00401 if ( start == end ) {
00402 removeSelection( id );
00403 setSelectionStart( id, cursor );
00404 return true;
00405 }
00406
00407 if ( sel.endCursor.parag() == end.parag() ) {
00408 setSelectionEndHelper( id, sel, start, end );
00409 return true;
00410 }
00411
00412 bool inSelection = false;
00413 KoTextCursor c( this );
00414 KoTextCursor tmp = sel.startCursor;
00415 if ( sel.swapped )
00416 tmp = sel.endCursor;
00417 KoTextCursor tmp2 = *cursor;
00418 c.setParag( tmp.parag()->paragId() < tmp2.parag()->paragId() ? tmp.parag() : tmp2.parag() );
00419 KoTextCursor old;
00420 bool hadStart = false;
00421 bool hadEnd = false;
00422 bool hadStartParag = false;
00423 bool hadEndParag = false;
00424 bool hadOldStart = false;
00425 bool hadOldEnd = false;
00426 bool leftSelection = false;
00427 sel.swapped = false;
00428 for ( ;; ) {
00429 if ( c == start )
00430 hadStart = true;
00431 if ( c == end )
00432 hadEnd = true;
00433 if ( c.parag() == start.parag() )
00434 hadStartParag = true;
00435 if ( c.parag() == end.parag() )
00436 hadEndParag = true;
00437 if ( c == sel.startCursor )
00438 hadOldStart = true;
00439 if ( c == sel.endCursor )
00440 hadOldEnd = true;
00441
00442 if ( !sel.swapped &&
00443 ( hadEnd && !hadStart ||
00444 hadEnd && hadStart && start.parag() == end.parag() && start.index() > end.index() ) )
00445 sel.swapped = true;
00446
00447 if ( c == end && hadStartParag ||
00448 c == start && hadEndParag ) {
00449 KoTextCursor tmp = c;
00450 if ( tmp.parag() != c.parag() ) {
00451 int sstart = tmp.parag()->selectionStart( id );
00452 tmp.parag()->removeSelection( id );
00453 tmp.parag()->setSelection( id, sstart, tmp.index() );
00454 }
00455 }
00456
00457 if ( inSelection &&
00458 ( c == end && hadStart || c == start && hadEnd ) )
00459 leftSelection = true;
00460 else if ( !leftSelection && !inSelection && ( hadStart || hadEnd ) )
00461 inSelection = true;
00462
00463 bool noSelectionAnymore = hadOldStart && hadOldEnd && leftSelection && !inSelection && !c.parag()->hasSelection( id ) && c.atParagEnd();
00464 c.parag()->removeSelection( id );
00465 if ( inSelection ) {
00466 if ( c.parag() == start.parag() && start.parag() == end.parag() ) {
00467 c.parag()->setSelection( id, qMin( start.index(), end.index() ), qMax( start.index(), end.index() ) );
00468 } else if ( c.parag() == start.parag() && !hadEndParag ) {
00469 c.parag()->setSelection( id, start.index(), c.parag()->length() - 1 );
00470 } else if ( c.parag() == end.parag() && !hadStartParag ) {
00471 c.parag()->setSelection( id, end.index(), c.parag()->length() - 1 );
00472 } else if ( c.parag() == end.parag() && hadEndParag ) {
00473 c.parag()->setSelection( id, 0, end.index() );
00474 } else if ( c.parag() == start.parag() && hadStartParag ) {
00475 c.parag()->setSelection( id, 0, start.index() );
00476 } else {
00477 c.parag()->setSelection( id, 0, c.parag()->length() - 1 );
00478 }
00479 }
00480
00481 if ( leftSelection )
00482 inSelection = false;
00483
00484 old = c;
00485 c.gotoNextLetter();
00486 if ( old == c || noSelectionAnymore )
00487 break;
00488 }
00489
00490 if ( !sel.swapped )
00491 sel.startCursor.parag()->setSelection( id, sel.startCursor.index(), sel.startCursor.parag()->length() - 1 );
00492
00493 sel.startCursor = start;
00494 sel.endCursor = end;
00495 if ( sel.startCursor.parag() == sel.endCursor.parag() )
00496 sel.swapped = sel.startCursor.index() > sel.endCursor.index();
00497
00498 setSelectionEndHelper( id, sel, start, end );
00499
00500 return true;
00501 }
00502
00503 void KoTextDocument::selectAll( int id )
00504 {
00505 removeSelection( id );
00506
00507 KoTextDocumentSelection sel;
00508 sel.swapped = false;
00509 KoTextCursor c( this );
00510
00511 c.setParag( fParag );
00512 c.setIndex( 0 );
00513 sel.startCursor = c;
00514
00515 c.setParag( lParag );
00516 c.setIndex( lParag->length() - 1 );
00517 sel.endCursor = c;
00518
00519 KoTextParag *p = fParag;
00520 while ( p ) {
00521 p->setSelection( id, 0, p->length() - 1 );
00522 #ifdef QTEXTTABLE_AVAILABLE
00523 for ( int i = 0; i < (int)p->length(); ++i ) {
00524 if ( p->at( i )->isCustom() && p->at( i )->customItem()->isNested() ) {
00525 KoTextTable *t = (KoTextTable*)p->at( i )->customItem();
00526 Q3PtrList<KoTextTableCell> tableCells = t->tableCells();
00527 for ( KoTextTableCell *c = tableCells.first(); c; c = tableCells.next() )
00528 c->richText()->selectAll( id );
00529 }
00530 }
00531 #endif
00532 p = p->next();
00533 }
00534
00535 selections.insert( id, sel );
00536 }
00537
00538 bool KoTextDocument::removeSelection( int id )
00539 {
00540 QMap<int, KoTextDocumentSelection>::Iterator it = selections.find( id );
00541 if ( it == selections.end() )
00542 return false;
00543
00544 KoTextDocumentSelection &sel = *it;
00545
00546 KoTextCursor c( this );
00547 KoTextCursor tmp = sel.startCursor;
00548 if ( sel.swapped )
00549 tmp = sel.endCursor;
00550 c.setParag( tmp.parag() );
00551 KoTextCursor old;
00552 bool hadStart = false;
00553 bool hadEnd = false;
00554 KoTextParag *lastParag = 0;
00555 bool leftSelection = false;
00556 bool inSelection = false;
00557 sel.swapped = false;
00558 for ( ;; ) {
00559 if ( !hadStart && c.parag() == sel.startCursor.parag() )
00560 hadStart = true;
00561 if ( !hadEnd && c.parag() == sel.endCursor.parag() )
00562 hadEnd = true;
00563
00564 if ( !leftSelection && !inSelection && ( c.parag() == sel.startCursor.parag() || c.parag() == sel.endCursor.parag() ) )
00565 inSelection = true;
00566
00567 if ( inSelection &&
00568 ( c == sel.endCursor && hadStart || c == sel.startCursor && hadEnd ) ) {
00569 leftSelection = true;
00570 inSelection = false;
00571 }
00572
00573 bool noSelectionAnymore = leftSelection && !inSelection && !c.parag()->hasSelection( id ) && c.atParagEnd();
00574
00575 if ( lastParag != c.parag() )
00576 c.parag()->removeSelection( id );
00577
00578 old = c;
00579 lastParag = c.parag();
00580 c.gotoNextLetter();
00581 if ( old == c || noSelectionAnymore )
00582 break;
00583 }
00584
00585 selections.remove( id );
00586 return true;
00587 }
00588
00589 QString KoTextDocument::selectedText( int id, bool withCustom ) const
00590 {
00591
00592 QMap<int, KoTextDocumentSelection>::ConstIterator it = selections.find( id );
00593 if ( it == selections.end() )
00594 return QString::null;
00595
00596 KoTextDocumentSelection sel = *it;
00597
00598
00599 KoTextCursor c1 = sel.startCursor;
00600 KoTextCursor c2 = sel.endCursor;
00601 if ( sel.swapped ) {
00602 c2 = sel.startCursor;
00603 c1 = sel.endCursor;
00604 }
00605
00606 if ( c1.parag() == c2.parag() ) {
00607 QString s;
00608 KoTextParag *p = c1.parag();
00609 int end = c2.index();
00610 if ( p->at( qMax( 0, end - 1 ) )->isCustom() )
00611 ++end;
00612 if ( !withCustom || !p->customItems() ) {
00613 s += p->string()->toString().mid( c1.index(), end - c1.index() );
00614 } else {
00615 for ( int i = c1.index(); i < end; ++i ) {
00616 if ( p->at( i )->isCustom() ) {
00617 #ifdef QTEXTTABLE_AVAILABLE
00618 if ( p->at( i )->customItem()->isNested() ) {
00619 s += '\n';
00620 KoTextTable *t = (KoTextTable*)p->at( i )->customItem();
00621 Q3PtrList<KoTextTableCell> cells = t->tableCells();
00622 for ( KoTextTableCell *c = cells.first(); c; c = cells.next() )
00623 s += c->richText()->plainText() + '\n';
00624 s += '\n';
00625 }
00626 #endif
00627 } else {
00628 s += p->at( i )->c;
00629 }
00630 s += '\n';
00631 }
00632 }
00633 return s;
00634 }
00635
00636 QString s;
00637 KoTextParag *p = c1.parag();
00638 int start = c1.index();
00639 while ( p ) {
00640 int end = p == c2.parag() ? c2.index() : p->length() - 1;
00641 if ( p == c2.parag() && p->at( qMax( 0, end - 1 ) )->isCustom() )
00642 ++end;
00643 if ( !withCustom || !p->customItems() ) {
00644 s += p->string()->toString().mid( start, end - start );
00645 if ( p != c2.parag() )
00646 s += '\n';
00647 } else {
00648 for ( int i = start; i < end; ++i ) {
00649 if ( p->at( i )->isCustom() ) {
00650 #ifdef QTEXTTABLE_AVAILABLE
00651 if ( p->at( i )->customItem()->isNested() ) {
00652 s += '\n';
00653 KoTextTable *t = (KoTextTable*)p->at( i )->customItem();
00654 Q3PtrList<KoTextTableCell> cells = t->tableCells();
00655 for ( KoTextTableCell *c = cells.first(); c; c = cells.next() )
00656 s += c->richText()->plainText() + '\n';
00657 s += '\n';
00658 }
00659 #endif
00660 } else {
00661 s += p->at( i )->c;
00662 }
00663 s += '\n';
00664 }
00665 }
00666 start = 0;
00667 if ( p == c2.parag() )
00668 break;
00669 p = p->next();
00670 }
00671 return s;
00672 }
00673
00674 QString KoTextDocument::copySelection( KoXmlWriter& writer, KoSavingContext& context, int selectionId )
00675 {
00676 KoTextCursor c1 = selectionStartCursor( selectionId );
00677 KoTextCursor c2 = selectionEndCursor( selectionId );
00678 QString text;
00679 if ( c1.parag() == c2.parag() )
00680 {
00681 text = c1.parag()->toString( c1.index(), c2.index() - c1.index() );
00682
00683 c1.parag()->saveOasis( writer, context, c1.index(), c2.index()-1, true );
00684 }
00685 else
00686 {
00687 text += c1.parag()->toString( c1.index() ) + '\n';
00688
00689 c1.parag()->saveOasis( writer, context, c1.index(), c1.parag()->length()-2, true );
00690 KoTextParag *p = c1.parag()->next();
00691 while ( p && p != c2.parag() ) {
00692 text += p->toString() + '\n';
00693 p->saveOasis( writer, context, 0, p->length()-2, true );
00694 p = p->next();
00695 }
00696 text += c2.parag()->toString( 0, c2.index() );
00697 c2.parag()->saveOasis( writer, context, 0, c2.index() - 1, true );
00698 }
00699 return text;
00700 }
00701
00702 void KoTextDocument::setFormat( int id, const KoTextFormat *f, int flags )
00703 {
00704 QMap<int, KoTextDocumentSelection>::ConstIterator it = selections.find( id );
00705 if ( it == selections.end() )
00706 return;
00707
00708 KoTextDocumentSelection sel = *it;
00709
00710 KoTextCursor c1 = sel.startCursor;
00711 KoTextCursor c2 = sel.endCursor;
00712 if ( sel.swapped ) {
00713 c2 = sel.startCursor;
00714 c1 = sel.endCursor;
00715 }
00716
00717 if ( c1.parag() == c2.parag() ) {
00718 c1.parag()->setFormat( c1.index(), c2.index() - c1.index(), f, true, flags );
00719 return;
00720 }
00721
00722 c1.parag()->setFormat( c1.index(), c1.parag()->length() - c1.index(), f, true, flags );
00723 KoTextParag *p = c1.parag()->next();
00724 while ( p && p != c2.parag() ) {
00725 p->setFormat( 0, p->length(), f, true, flags );
00726 p = p->next();
00727 }
00728 c2.parag()->setFormat( 0, c2.index(), f, true, flags );
00729 }
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741 void KoTextDocument::removeSelectedText( int id, KoTextCursor *cursor )
00742 {
00743 QMap<int, KoTextDocumentSelection>::Iterator it = selections.find( id );
00744 if ( it == selections.end() )
00745 return;
00746
00747 KoTextDocumentSelection sel = *it;
00748
00749 KoTextCursor c1 = sel.startCursor;
00750 KoTextCursor c2 = sel.endCursor;
00751 if ( sel.swapped ) {
00752 c2 = sel.startCursor;
00753 c1 = sel.endCursor;
00754 }
00755
00756 *cursor = c1;
00757 removeSelection( id );
00758
00759 if ( c1.parag() == c2.parag() ) {
00760 c1.parag()->remove( c1.index(), c2.index() - c1.index() );
00761 return;
00762 }
00763
00764
00765 bool valid = true;
00766 if ( c1.parag() == fParag && c1.index() == 0 &&
00767 c2.parag() == lParag && c2.index() == lParag->length() - 1 )
00768 valid = false;
00769
00770 bool didGoLeft = false;
00771 if ( c1.index() == 0 && c1.parag() != fParag ) {
00772 cursor->gotoPreviousLetter();
00773 if ( valid )
00774 didGoLeft = true;
00775 }
00776
00777 c1.parag()->remove( c1.index(), c1.parag()->length() - 1 - c1.index() );
00778 KoTextParag *p = c1.parag()->next();
00779 int dy = 0;
00780 KoTextParag *tmp;
00781 while ( p && p != c2.parag() ) {
00782 tmp = p->next();
00783 dy -= p->rect().height();
00784
00785 delete p;
00786 p = tmp;
00787 }
00788 c2.parag()->remove( 0, c2.index() );
00789 while ( p ) {
00790 p->move( dy );
00792 if ( p->paragLayout().counter )
00793 p->paragLayout().counter->invalidate();
00795 p->invalidate( 0 );
00796
00797 p = p->next();
00798 }
00799
00800 c1.parag()->join( c2.parag() );
00801
00802 if ( didGoLeft )
00803 cursor->gotoNextLetter();
00804 }
00805
00806 void KoTextDocument::addCommand( KoTextDocCommand *cmd )
00807 {
00808 commandHistory->addCommand( cmd );
00809 }
00810
00811 KoTextCursor *KoTextDocument::undo( KoTextCursor *c )
00812 {
00813 return commandHistory->undo( c );
00814 }
00815
00816 KoTextCursor *KoTextDocument::redo( KoTextCursor *c )
00817 {
00818 return commandHistory->redo( c );
00819 }
00820
00821 bool KoTextDocument::find( const QString &expr, bool cs, bool wo, bool forward,
00822 int *parag, int *index, KoTextCursor *cursor )
00823 {
00824 KoTextParag *p = forward ? fParag : lParag;
00825 if ( parag )
00826 p = paragAt( *parag );
00827 else if ( cursor )
00828 p = cursor->parag();
00829 bool first = true;
00830
00831 while ( p ) {
00832 QString s = p->string()->toString();
00833 s.remove( s.length() - 1, 1 );
00834 int start = forward ? 0 : s.length() - 1;
00835 if ( first && index )
00836 start = *index;
00837 else if ( first && cursor )
00838 start = cursor->index();
00839 if ( !forward && first ) {
00840 start -= expr.length() + 1;
00841 if ( start < 0 ) {
00842 first = false;
00843 p = p->prev();
00844 continue;
00845 }
00846 }
00847 first = false;
00848
00849 for ( ;; ) {
00850 int res = forward ? s.find( expr, start, cs ) : s.findRev( expr, start, cs );
00851 if ( res == -1 )
00852 break;
00853
00854 bool ok = true;
00855 if ( wo ) {
00856 int end = res + expr.length();
00857 if ( ( res == 0 || s[ res - 1 ].isSpace() || s[ res - 1 ].isPunct() ) &&
00858 ( end == (int)s.length() || s[ end ].isSpace() || s[ end ].isPunct() ) )
00859 ok = true;
00860 else
00861 ok = false;
00862 }
00863 if ( ok && cursor ) {
00864 cursor->setParag( p );
00865 cursor->setIndex( res );
00866 setSelectionStart( Standard, cursor );
00867 cursor->setIndex( res + expr.length() );
00868 setSelectionEnd( Standard, cursor );
00869 if ( parag )
00870 *parag = p->paragId();
00871 if ( index )
00872 *index = res;
00873 return true;
00874 }
00875 if ( forward ) {
00876 start = res + 1;
00877 } else {
00878 if ( res == 0 )
00879 break;
00880 start = res - 1;
00881 }
00882 }
00883 p = forward ? p->next() : p->prev();
00884 }
00885
00886 return false;
00887 }
00888
00889 bool KoTextDocument::inSelection( int selId, const QPoint &pos ) const
00890 {
00891 QMap<int, KoTextDocumentSelection>::ConstIterator it = selections.find( selId );
00892 if ( it == selections.end() )
00893 return false;
00894
00895 KoTextDocumentSelection sel = *it;
00896 KoTextParag *startParag = sel.startCursor.parag();
00897 KoTextParag *endParag = sel.endCursor.parag();
00898 if ( sel.startCursor.parag() == sel.endCursor.parag() &&
00899 sel.startCursor.parag()->selectionStart( selId ) == sel.endCursor.parag()->selectionEnd( selId ) )
00900 return false;
00901 if ( sel.endCursor.parag()->paragId() < sel.startCursor.parag()->paragId() ) {
00902 endParag = sel.startCursor.parag();
00903 startParag = sel.endCursor.parag();
00904 }
00905
00906 KoTextParag *p = startParag;
00907 while ( p ) {
00908 if ( p->rect().contains( pos ) ) {
00909 bool inSel = false;
00910 int selStart = p->selectionStart( selId );
00911 int selEnd = p->selectionEnd( selId );
00912 int y = 0;
00913 int h = 0;
00914 for ( int i = 0; i < p->length(); ++i ) {
00915 if ( i == selStart )
00916 inSel = true;
00917 if ( i == selEnd )
00918 break;
00919 if ( p->at( i )->lineStart ) {
00920 y = (*p->lineStarts.find( i ))->y;
00921 h = (*p->lineStarts.find( i ))->h;
00922 }
00923 if ( pos.y() - p->rect().y() >= y && pos.y() - p->rect().y() <= y + h ) {
00924 if ( inSel && pos.x() >= p->at( i )->x &&
00925 pos.x() <= p->at( i )->x + p->at( i )->width )
00926 return true;
00927 }
00928 }
00929 }
00930 if ( pos.y() < p->rect().y() )
00931 break;
00932 if ( p == endParag )
00933 break;
00934 p = p->next();
00935 }
00936
00937 return false;
00938 }
00939
00940 QPixmap *KoTextDocument::bufferPixmap( const QSize &s )
00941 {
00942 if ( !buf_pixmap ) {
00943 int w = QABS( s.width() );
00944 int h = QABS( s.height() );
00945 buf_pixmap = new QPixmap( w, h );
00946 } else {
00947 if ( buf_pixmap->width() < s.width() ||
00948 buf_pixmap->height() < s.height() ) {
00949 buf_pixmap->resize( qMax( s.width(), buf_pixmap->width() ),
00950 qMax( s.height(), buf_pixmap->height() ) );
00951 }
00952 }
00953
00954 return buf_pixmap;
00955 }
00956
00957 void KoTextDocument::registerCustomItem( KoTextCustomItem *i, KoTextParag *p )
00958 {
00959 if (!i)
00960 return;
00961
00962 if ( i->placement() != KoTextCustomItem::PlaceInline )
00963 flow_->registerFloatingItem( i );
00964 p->registerFloatingItem( i );
00965 i->setParagraph( p );
00966
00967 customItems.append( i );
00968 }
00969
00970 void KoTextDocument::unregisterCustomItem( KoTextCustomItem *i, KoTextParag *p )
00971 {
00972 flow_->unregisterFloatingItem( i );
00973 p->unregisterFloatingItem( i );
00974 i->setParagraph( 0 );
00975 customItems.removeRef( i );
00976 }
00977
00978 int KoTextDocument::length() const
00979 {
00980 int l = 0;
00981 KoTextParag *p = fParag;
00982 while ( p ) {
00983 l += p->length() - 1;
00984 p = p->next();
00985 }
00986 return l;
00987 }
00988
00989 bool KoTextDocument::visitSelection( int selectionId, KoParagVisitor* visitor, bool forward )
00990 {
00991 KoTextCursor c1 = selectionStartCursor( selectionId );
00992 KoTextCursor c2 = selectionEndCursor( selectionId );
00993 if ( c1 == c2 )
00994 return true;
00995 return visitFromTo( c1.parag(), c1.index(), c2.parag(), c2.index(), visitor, forward );
00996 }
00997
00998 bool KoTextDocument::hasSelection( int id, bool visible ) const
00999 {
01000 return ( selections.find( id ) != selections.end() &&
01001 ( !visible ||
01002 ( (KoTextDocument*)this )->selectionStartCursor( id ) !=
01003 ( (KoTextDocument*)this )->selectionEndCursor( id ) ) );
01004 }
01005
01006 void KoTextDocument::setSelectionStart( int id, KoTextCursor *cursor )
01007 {
01008 KoTextDocumentSelection sel;
01009 sel.startCursor = *cursor;
01010 sel.endCursor = *cursor;
01011 sel.swapped = false;
01012 selections[ id ] = sel;
01013 }
01014
01015 KoTextParag *KoTextDocument::paragAt( int i ) const
01016 {
01017 KoTextParag *s = fParag;
01018 while ( s ) {
01019 if ( s->paragId() == i )
01020 return s;
01021 s = s->next();
01022 }
01023 return 0;
01024 }
01025
01026 bool KoTextDocument::visitDocument( KoParagVisitor *visitor, bool forward )
01027 {
01028 return visitFromTo( firstParag(), 0, lastParag(), lastParag()->length()-1, visitor, forward );
01029 }
01030
01031 bool KoTextDocument::visitFromTo( KoTextParag *firstParag, int firstIndex, KoTextParag* lastParag, int lastIndex, KoParagVisitor* visitor, bool forw )
01032 {
01033 if ( firstParag == lastParag )
01034 {
01035 return visitor->visit( firstParag, firstIndex, lastIndex );
01036 }
01037 else
01038 {
01039 bool ret = true;
01040 if ( forw )
01041 {
01042
01043 ret = visitor->visit( firstParag, firstIndex, firstParag->length() - 1 );
01044 if (!ret) return false;
01045 }
01046 else
01047 {
01048 ret = visitor->visit( lastParag, 0, lastIndex );
01049 if (!ret) return false;
01050 }
01051
01052 KoTextParag* currentParag = forw ? firstParag->next() : lastParag->prev();
01053 KoTextParag * endParag = forw ? lastParag : firstParag;
01054 while ( currentParag && currentParag != endParag )
01055 {
01056 ret = visitor->visit( currentParag, 0, currentParag->length() - 1 );
01057 if (!ret) return false;
01058 currentParag = forw ? currentParag->next() : currentParag->prev();
01059 }
01060 Q_ASSERT( currentParag );
01061 Q_ASSERT( endParag == currentParag );
01062 if ( forw )
01063 ret = visitor->visit( lastParag, 0, lastIndex );
01064 else
01065 ret = visitor->visit( currentParag, firstIndex, currentParag->length() - 1 );
01066 return ret;
01067 }
01068 }
01069
01070 static bool is_printer( QPainter *p )
01071 {
01072 return p && p->device() && p->device()->devType() == QInternal::Printer;
01073 }
01074
01075 KoTextParag *KoTextDocument::drawWYSIWYG( QPainter *p, int cx, int cy, int cw, int ch, const QColorGroup &cg,
01076 KoTextZoomHandler* zoomHandler, bool onlyChanged,
01077 bool drawCursor, KoTextCursor *cursor,
01078 bool resetChanged, uint drawingFlags )
01079 {
01080 m_drawingFlags = drawingFlags;
01081
01082
01083
01084
01085 if ( is_printer( p ) || ( drawingFlags & TransparentBackground ) ) {
01086
01087
01088
01089
01090 QRect crect( cx, cy, cw, ch );
01091 drawWithoutDoubleBuffer( p, crect, cg, zoomHandler );
01092 return 0;
01093 }
01094
01095
01096 if ( !firstParag() )
01097 return 0;
01098
01099 KoTextParag *lastFormatted = 0;
01100 KoTextParag *parag = firstParag();
01101
01102 QPixmap *doubleBuffer = 0;
01103 QPainter painter;
01104
01105 QRect crect( cx, cy, cw, ch );
01106 Q_ASSERT( ch > 0 );
01107 #ifdef DEBUG_PAINTING
01108 kDebug(32500) << "\nKoTextDocument::drawWYSIWYG crect=" << crect << endl;
01109 #endif
01110
01111
01112 QRect pixelRect = parag->pixelRect( zoomHandler );
01113 if ( isPageBreakEnabled() && parag && cy <= pixelRect.y() && pixelRect.y() > 0 ) {
01114 QRect r( 0, 0,
01115 zoomHandler->layoutUnitToPixelX( parag->document()->x() + parag->document()->width() ),
01116 pixelRect.y() );
01117 r &= crect;
01118 if ( !r.isEmpty() ) {
01119 #ifdef DEBUG_PAINTING
01120 kDebug(32500) << " drawWYSIWYG: space above first parag: " << r << " (pixels)" << endl;
01121 #endif
01122 p->fillRect( r, cg.brush( QColorGroup::Base ) );
01123 }
01124 }
01125
01126 while ( parag ) {
01127 lastFormatted = parag;
01128 if ( !parag->isValid() )
01129 parag->format();
01130
01131 QRect ir = parag->pixelRect( zoomHandler );
01132 #ifdef DEBUG_PAINTING
01133 kDebug(32500) << " drawWYSIWYG: ir=" << ir << endl;
01134 #endif
01135 if ( isPageBreakEnabled() && parag->next() && ( drawingFlags & TransparentBackground ) == 0 )
01136 {
01137 int nexty = parag->next()->pixelRect(zoomHandler).y();
01138
01139
01140 if ( ir.y() + ir.height() < nexty ) {
01141 QRect r( 0, ir.y() + ir.height(),
01142 zoomHandler->layoutUnitToPixelX( parag->document()->x() + parag->document()->width() ),
01143 nexty - ( ir.y() + ir.height() ) );
01144 r &= crect;
01145 if ( !r.isEmpty() )
01146 {
01147 #ifdef DEBUG_PAINTING
01148 kDebug(32500) << " drawWYSIWYG: space between parag " << parag->paragId() << " and " << parag->next()->paragId() << " : " << r << " (pixels)" << endl;
01149 #endif
01150 p->fillRect( r, cg.brush( QColorGroup::Base ) );
01151 }
01152 }
01153 }
01154
01155 if ( !ir.intersects( crect ) ) {
01156
01157 ir.setWidth( zoomHandler->layoutUnitToPixelX( parag->document()->width() ) );
01158 if ( ir.intersects( crect ) && ( drawingFlags & TransparentBackground ) == 0 )
01159 p->fillRect( ir.intersect( crect ), cg.brush( QColorGroup::Base ) );
01160 if ( ir.y() > cy + ch ) {
01161 goto floating;
01162 }
01163 }
01164 else if ( parag->hasChanged() || !onlyChanged ) {
01165
01166
01167
01168 if ( !onlyChanged && parag->lineChanged() > 0 )
01169 parag->setChanged( false );
01170 drawParagWYSIWYG( p, parag, cx, cy, cw, ch, doubleBuffer, cg,
01171 zoomHandler, drawCursor, cursor, resetChanged, drawingFlags );
01172 }
01173 parag = parag->next();
01174 }
01175
01176 parag = lastParag();
01177
01178 floating:
01179 pixelRect = parag->pixelRect(zoomHandler);
01180 int docheight = zoomHandler->layoutUnitToPixelY( parag->document()->height() );
01181 if ( pixelRect.y() + pixelRect.height() < docheight ) {
01182 int docwidth = zoomHandler->layoutUnitToPixelX( parag->document()->width() );
01183 if ( ( drawingFlags & TransparentBackground ) == 0 ) {
01184 p->fillRect( 0, pixelRect.y() + pixelRect.height(),
01185 docwidth, docheight - ( pixelRect.y() + pixelRect.height() ),
01186 cg.brush( QColorGroup::Base ) );
01187 }
01188 if ( !flow()->isEmpty() ) {
01189 QRect cr( cx, cy, cw, ch );
01190 cr = cr.intersect( QRect( 0, pixelRect.y() + pixelRect.height(), docwidth,
01191 docheight - ( pixelRect.y() + pixelRect.height() ) ) );
01192 flow()->drawFloatingItems( p, cr.x(), cr.y(), cr.width(), cr.height(), cg, false );
01193 }
01194 }
01195
01196 if ( buf_pixmap && buf_pixmap->height() > 300 ) {
01197 delete buf_pixmap;
01198 buf_pixmap = 0;
01199 }
01200
01201 return lastFormatted;
01202 }
01203
01204
01205
01206 void KoTextDocument::drawWithoutDoubleBuffer( QPainter *p, const QRect &cr, const QColorGroup &cg,
01207 KoTextZoomHandler* zoomHandler, const QBrush *paper )
01208 {
01209 if ( !firstParag() )
01210 return;
01211
01212 Q_ASSERT( (m_drawingFlags & DrawSelections) == 0 );
01213 if (m_drawingFlags & DrawSelections)
01214 kDebug() << kBacktrace();
01215 if ( paper && ( m_drawingFlags & TransparentBackground ) == 0 ) {
01216 p->setBrushOrigin( -(int)p->translationX(), -(int)p->translationY() );
01217 p->fillRect( cr, *paper );
01218 }
01219
01220 KoTextParag *parag = firstParag();
01221 while ( parag ) {
01222 if ( !parag->isValid() )
01223 parag->format();
01224
01225 QRect pr( parag->pixelRect( zoomHandler ) );
01226 pr.setLeft( 0 );
01227 pr.setWidth( QWIDGETSIZE_MAX );
01228
01229 QRect crect_lu( parag->rect() );
01230
01231 if ( !cr.isNull() && !cr.intersects( pr ) ) {
01232 parag = parag->next();
01233 continue;
01234 }
01235
01236 p->translate( 0, pr.y() );
01237
01238
01239
01240 QBrush brush = cg.brush( QColorGroup::Base );;
01241 bool needBrush = brush.style() != Qt::NoBrush &&
01242 !(brush.style() == Qt::SolidPattern &&
01243 brush.color() == Qt::white &&
01244 is_printer(p));
01245 if ( needBrush && ( m_drawingFlags & TransparentBackground ) == 0 )
01246 p->fillRect( QRect( 0, 0, pr.width(), pr.height() ), brush );
01247
01248
01249 parag->paint( *p, cg, 0, false,
01250 crect_lu.x(), crect_lu.y(),
01251 crect_lu.width(), crect_lu.height() );
01252 p->translate( 0, -pr.y() );
01253
01254 parag = parag->next();
01255 }
01256 }
01257
01258
01259
01260 void KoTextDocument::drawParagWYSIWYG( QPainter *p, KoTextParag *parag, int cx, int cy, int cw, int ch,
01261 QPixmap *&doubleBuffer, const QColorGroup &cg,
01262 KoTextZoomHandler* zoomHandler, bool drawCursor,
01263 KoTextCursor *cursor, bool resetChanged, uint drawingFlags )
01264 {
01265 if ( cw <= 0 || ch <= 0 ) { Q_ASSERT( cw > 0 ); Q_ASSERT( ch > 0 ); return; }
01266 #ifdef DEBUG_PAINTING
01267 kDebug(32500) << "KoTextDocument::drawParagWYSIWYG " << (void*)parag << " id:" << parag->paragId() << endl;
01268 #endif
01269 m_drawingFlags = drawingFlags;
01270 QPainter *painter = 0;
01271
01272 QRect rect = parag->pixelRect( zoomHandler );
01273
01274 int offsetY = 0;
01275
01276 if ( parag->lineChanged() > -1 )
01277 {
01278 offsetY = zoomHandler->layoutUnitToPixelY( parag->lineY( parag->lineChanged() ) - parag->topMargin() );
01279 #ifdef DEBUG_PAINTING
01280 kDebug(32500) << " Repainting from lineChanged=" << parag->lineChanged() << " -> adding " << offsetY << " to rect" << endl;
01281 #endif
01282
01283 rect.rTop() += offsetY;
01284 }
01285
01286 QRect crect( cx, cy, cw, ch );
01287 QRect ir( rect );
01288
01289 QBrush brush = cg.brush( QColorGroup::Base );
01290
01291
01292
01293 bool needBrush = brush.style() != Qt::NoBrush &&
01294 ( drawingFlags & TransparentBackground ) == 0 &&
01295 !(brush.style() == Qt::SolidPattern &&
01296 brush.color() == Qt::white &&
01297 is_printer(p));
01298
01299 bool useDoubleBuffer = !parag->document()->parent();
01300 if ( is_printer(p) )
01301 useDoubleBuffer = false;
01302
01303
01305
01306 QMatrix mat = p->worldMatrix();
01307 if ( ( mat.m11() != 1.0 || mat.m22() != 1.0 || mat.m12() != 0.0 || mat.m21() != 0.0 )
01308 && brush.style() != Qt::SolidPattern )
01309 useDoubleBuffer = false;
01310
01311 #ifdef DEBUG_PAINTING
01312 kDebug(32500) << "KoTextDocument::drawParagWYSIWYG parag->rect=" << parag->rect()
01313 << " pixelRect(ir)=" << ir
01314 << " crect (pixels)=" << crect
01315 << " useDoubleBuffer=" << useDoubleBuffer << endl;
01316 #endif
01317
01318 if ( useDoubleBuffer ) {
01319 painter = new QPainter;
01320 if ( cx >= 0 && cy >= 0 )
01321 ir = ir.intersect( crect );
01322 if ( !doubleBuffer ||
01323 ir.width() > doubleBuffer->width() ||
01324 ir.height() > doubleBuffer->height() )
01325 {
01326 doubleBuffer = bufferPixmap( ir.size() );
01327 }
01328 painter->begin( doubleBuffer );
01329
01330 } else {
01331 p->save();
01332 painter = p;
01333 painter->translate( ir.x(), ir.y() );
01334 }
01335
01336
01337
01338
01339
01340
01341
01342 if ( useDoubleBuffer || is_printer( painter ) ) {
01343
01344 if ( brush.style() != Qt::SolidPattern ) {
01345 bitBlt( doubleBuffer, 0, 0, p->device(),
01346 ir.x() + (int)p->translationX(), ir.y() + (int)p->translationY(),
01347 ir.width(), ir.height() );
01348 }
01349 }
01350
01351 if ( needBrush )
01352 painter->fillRect( QRect( 0, 0, ir.width(), ir.height() ), brush );
01353
01354
01355 painter->translate( rect.x() - ir.x(), rect.y() - ir.y() );
01356 #ifdef DEBUG_PAINTING
01357 kDebug(32500) << "KoTextDocument::drawParagWYSIWYG translate " << rect.x() - ir.x() << "," << rect.y() - ir.y() << endl;
01358 #endif
01359
01360
01361
01362 QRect crect_lu( zoomHandler->pixelToLayoutUnit( crect ) );
01363 #ifdef DEBUG_PAINTING
01364 kDebug(32500) << "KoTextDocument::drawParagWYSIWYG crect_lu=" << crect_lu << endl;
01365 #endif
01366
01367
01368
01369
01370 painter->translate( 0, -offsetY );
01371
01372 parag->paint( *painter, cg, drawCursor ? cursor : 0, (m_drawingFlags & DrawSelections),
01373 crect_lu.x(), crect_lu.y(), crect_lu.width(), crect_lu.height() );
01374
01375
01376 if ( useDoubleBuffer ) {
01377 delete painter;
01378 painter = 0;
01379 p->drawPixmap( ir.topLeft(), *doubleBuffer, QRect( QPoint( 0, 0 ), ir.size() ) );
01380 #if 0 // for debug!
01381 p->save();
01382 p->setPen( Qt::blue );
01383 p->drawRect( ir.x(), ir.y(), ir.width(), ir.height() );
01384 p->restore();
01385 #endif
01386 } else {
01387
01388 p->restore();
01389
01390
01391
01392 }
01393
01394 if ( needBrush ) {
01395 int docright = zoomHandler->layoutUnitToPixelX( parag->document()->x() + parag->document()->width() );
01396 #ifdef DEBUG_PAINTING
01397
01398 #endif
01399 if ( rect.x() + rect.width() < docright ) {
01400 #ifdef DEBUG_PAINTING
01401 kDebug(32500) << "KoTextDocument::drawParagWYSIWYG rect doesn't go up to docright=" << docright << endl;
01402 #endif
01403 p->fillRect( rect.x() + rect.width(), rect.y(),
01404 docright - ( rect.x() + rect.width() ),
01405 rect.height(), cg.brush( QColorGroup::Base ) );
01406 }
01407 }
01408
01409 if ( resetChanged )
01410 parag->setChanged( false );
01411 }
01412
01413
01414 KoTextDocCommand *KoTextDocument::deleteTextCommand( KoTextDocument *textdoc, int id, int index, const Q3MemArray<KoTextStringChar> & str, const CustomItemsMap & customItemsMap, const Q3ValueList<KoParagLayout> & oldParagLayouts )
01415 {
01416 return new KoTextDeleteCommand( textdoc, id, index, str, customItemsMap, oldParagLayouts );
01417 }
01418
01419 KoTextParag* KoTextDocument::loadOasisText( const QDomElement& bodyElem, KoOasisContext& context, KoTextParag* lastParagraph, KoStyleCollection* styleColl, KoTextParag* nextParagraph )
01420 {
01421
01422 QDomElement tag;
01423 forEachElement( tag, bodyElem )
01424 {
01425 context.styleStack().save();
01426 const QString localName = tag.localName();
01427 const bool isTextNS = tag.namespaceURI() == KoXmlNS::text;
01428 uint pos = 0;
01429 if ( isTextNS && localName == "p" ) {
01430 context.fillStyleStack( tag, KoXmlNS::text, "style-name", "paragraph" );
01431
01432 KoTextParag *parag = createParag( this, lastParagraph, nextParagraph );
01433 parag->loadOasis( tag, context, styleColl, pos );
01434 if ( !lastParagraph )
01435 setFirstParag( parag );
01436 lastParagraph = parag;
01437 }
01438 else if ( isTextNS && localName == "h" )
01439 {
01440
01441 context.fillStyleStack( tag, KoXmlNS::text, "style-name", "paragraph" );
01442 int level = tag.attributeNS( KoXmlNS::text, "outline-level", QString::null ).toInt();
01443 bool listOK = false;
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454 listOK = context.pushOutlineListLevelStyle( level );
01455 int restartNumbering = -1;
01456 if ( tag.hasAttributeNS( KoXmlNS::text, "start-value" ) )
01457
01458 restartNumbering = tag.attributeNS( KoXmlNS::text, "start-value", QString::null ).toInt();
01459
01460 KoTextParag *parag = createParag( this, lastParagraph, nextParagraph );
01461 parag->loadOasis( tag, context, styleColl, pos );
01462 if ( !lastParagraph )
01463 setFirstParag( parag );
01464 lastParagraph = parag;
01465 if ( listOK ) {
01466 parag->applyListStyle( context, restartNumbering, true , true , level );
01467 context.listStyleStack().pop();
01468 }
01469 }
01470 else if ( isTextNS &&
01471 ( localName == "unordered-list" || localName == "ordered-list"
01472 || localName == "list" || localName == "numbered-paragraph" ) )
01473 {
01474 lastParagraph = loadList( tag, context, lastParagraph, styleColl, nextParagraph );
01475 }
01476 else if ( isTextNS && localName == "section" )
01477 {
01478 kDebug(32500) << "Section found!" << endl;
01479 context.fillStyleStack( tag, KoXmlNS::text, "style-name", "section" );
01480 lastParagraph = loadOasisText( tag, context, lastParagraph, styleColl, nextParagraph );
01481 }
01482 else if ( isTextNS && localName == "variable-decls" )
01483 {
01484
01485
01486 }
01487 else if ( isTextNS && localName == "user-field-decls" )
01488 {
01489 QDomElement fd;
01490 forEachElement( fd, tag )
01491 {
01492 if ( fd.namespaceURI() == KoXmlNS::text && fd.localName() == "user-field-decl" )
01493 {
01494 const QString name = fd.attributeNS( KoXmlNS::text, "name", QString::null );
01495 const QString value = fd.attributeNS( KoXmlNS::office, "value", QString::null );
01496 if ( !name.isEmpty() )
01497 context.variableCollection().setVariableValue( name, value );
01498 }
01499 }
01500 }
01501 else if ( isTextNS && localName == "number" )
01502 {
01503
01504
01505 }
01506 else if ( !loadOasisBodyTag( tag, context, lastParagraph, styleColl, nextParagraph ) )
01507 {
01508 kWarning(32500) << "Unsupported body element '" << localName << "'" << endl;
01509 }
01510
01511 context.styleStack().restore();
01512
01513
01514 }
01515 return lastParagraph;
01516 }
01517
01518 KoTextParag* KoTextDocument::loadList( const QDomElement& list, KoOasisContext& context, KoTextParag* lastParagraph, KoStyleCollection * styleColl, KoTextParag* nextParagraph )
01519 {
01520
01521
01522 const QString oldListStyleName = context.currentListStyleName();
01523 if ( list.hasAttributeNS( KoXmlNS::text, "style-name" ) )
01524 context.setCurrentListStyleName( list.attributeNS( KoXmlNS::text, "style-name", QString::null ) );
01525 bool listOK = !context.currentListStyleName().isEmpty();
01526 int level;
01527 if ( list.localName() == "numbered-paragraph" )
01528 level = list.attributeNS( KoXmlNS::text, "level", "1" ).toInt();
01529 else
01530 level = context.listStyleStack().level() + 1;
01531 if ( listOK )
01532 listOK = context.pushListLevelStyle( context.currentListStyleName(), level );
01533
01534 const QDomElement listStyle = context.listStyleStack().currentListStyle();
01535
01536 const bool orderedList = listStyle.localName() == "list-level-style-number";
01537
01538 if ( list.localName() == "numbered-paragraph" )
01539 {
01540
01541 int restartNumbering = -1;
01542 if ( list.hasAttributeNS( KoXmlNS::text, "start-value" ) )
01543 restartNumbering = list.attributeNS( KoXmlNS::text, "start-value", QString::null ).toInt();
01544 KoTextParag* oldLast = lastParagraph;
01545 lastParagraph = loadOasisText( list, context, lastParagraph, styleColl, nextParagraph );
01546 KoTextParag* firstListItem = oldLast ? oldLast->next() : firstParag();
01547
01548
01549 bool isOutline = firstListItem->counter() && firstListItem->counter()->numbering() == KoParagCounter::NUM_CHAPTER;
01550 firstListItem->applyListStyle( context, restartNumbering, orderedList,
01551 isOutline, level );
01552 }
01553 else
01554 {
01555
01556 for ( QDomNode n = list.firstChild(); !n.isNull(); n = n.nextSibling() )
01557 {
01558 QDomElement listItem = n.toElement();
01559 int restartNumbering = -1;
01560 if ( listItem.hasAttributeNS( KoXmlNS::text, "start-value" ) )
01561 restartNumbering = listItem.attributeNS( KoXmlNS::text, "start-value", QString::null ).toInt();
01562 bool isListHeader = listItem.localName() == "list-header" || listItem.attributeNS( KoXmlNS::text, "is-list-header", QString::null ) == "is-list-header";
01563 KoTextParag* oldLast = lastParagraph;
01564 lastParagraph = loadOasisText( listItem, context, lastParagraph, styleColl, nextParagraph );
01565 KoTextParag* firstListItem = oldLast ? oldLast->next() : firstParag();
01566 KoTextParag* p = firstListItem;
01567
01568 if ( !isListHeader && firstListItem ) {
01569
01570 bool isOutline = firstListItem->counter() && firstListItem->counter()->numbering() == KoParagCounter::NUM_CHAPTER;
01571 firstListItem->applyListStyle( context, restartNumbering, orderedList, isOutline, level );
01572 p = p->next();
01573 }
01574
01575 while ( p && p != lastParagraph->next() ) {
01576 if ( p->counter() )
01577 p->counter()->setNumbering( KoParagCounter::NUM_NONE );
01578 p = p->next();
01579 }
01580 }
01581 }
01582 if ( listOK )
01583 context.listStyleStack().pop();
01584 context.setCurrentListStyleName( oldListStyleName );
01585 return lastParagraph;
01586 }
01587
01588 void KoTextDocument::saveOasisContent( KoXmlWriter& writer, KoSavingContext& context ) const
01589 {
01590
01591
01592 KoTextParag* parag = firstParag();
01593 while ( parag ) {
01594
01595 parag->saveOasis( writer, context, 0, parag->lastCharPos() );
01596 parag = parag->next();
01597 }
01598 }
01599
01600 #include "KoTextDocument.moc"