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