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