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