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 "kozoomhandler.h"
00022 #include "kotextformatter.h"
00023 #include <kdebug.h>
00024 #include <kdeversion.h>
00025 #if ! KDE_IS_VERSION(3,1,90)
00026 #include <kdebugclasses.h>
00027 #endif
00028 #include "kocommand.h"
00029
00030
00031
00034
00035 KoTextDocument::KoTextDocument( KoZoomHandler *zoomHandler, KoTextFormatCollection *fc,
00036 KoTextFormatter *formatter, bool createInitialParag )
00037 : m_zoomHandler( zoomHandler ),
00038 m_bDestroying( false ),
00039 #ifdef QTEXTTABLE_AVAILABLE
00040 par( 0L ),
00041 tc( 0 ),
00042 #endif
00043 tArray( 0 ), tStopWidth( 0 )
00044 {
00045 fCollection = fc;
00046 init();
00047
00048 m_drawingFlags = 0;
00049 setAddMargins( true );
00050 if ( !formatter )
00051 formatter = new KoTextFormatter;
00052 setFormatter( formatter );
00053
00054 setY( 0 );
00055 setLeftMargin( 0 );
00056 setRightMargin( 0 );
00057
00058
00059 if ( !createInitialParag )
00060 clear( false );
00061 }
00062
00063 bool KoTextDocument::visitSelection( int selectionId, KoParagVisitor* visitor, bool forward )
00064 {
00065 KoTextCursor c1 = selectionStartCursor( selectionId );
00066 KoTextCursor c2 = selectionEndCursor( selectionId );
00067 if ( c1 == c2 )
00068 return true;
00069 return visitFromTo( c1.parag(), c1.index(), c2.parag(), c2.index(), visitor, forward );
00070 }
00071
00072 bool KoTextDocument::hasSelection( int id, bool visible ) const
00073 {
00074 return ( selections.find( id ) != selections.end() &&
00075 ( !visible ||
00076 ( (KoTextDocument*)this )->selectionStartCursor( id ) !=
00077 ( (KoTextDocument*)this )->selectionEndCursor( id ) ) );
00078 }
00079
00080 void KoTextDocument::setSelectionStart( int id, KoTextCursor *cursor )
00081 {
00082 KoTextDocumentSelection sel;
00083 sel.startCursor = *cursor;
00084 sel.endCursor = *cursor;
00085 sel.swapped = FALSE;
00086 selections[ id ] = sel;
00087 }
00088
00089 KoTextParag *KoTextDocument::paragAt( int i ) const
00090 {
00091 KoTextParag *s = fParag;
00092 while ( s ) {
00093 if ( s->paragId() == i )
00094 return s;
00095 s = s->next();
00096 }
00097 return 0;
00098 }
00099
00100 bool KoTextDocument::visitDocument( KoParagVisitor *visitor, bool forward )
00101 {
00102 return visitFromTo( firstParag(), 0, lastParag(), lastParag()->length()-1, visitor, forward );
00103 }
00104
00105 bool KoTextDocument::visitFromTo( KoTextParag *firstParag, int firstIndex, KoTextParag* lastParag, int lastIndex, KoParagVisitor* visitor, bool forw )
00106 {
00107 if ( firstParag == lastParag )
00108 {
00109 return visitor->visit( firstParag, firstIndex, lastIndex );
00110 }
00111 else
00112 {
00113 bool ret = true;
00114 if ( forw )
00115 {
00116
00117 ret = visitor->visit( firstParag, firstIndex, firstParag->length() - 1 );
00118 if (!ret) return false;
00119 }
00120 else
00121 {
00122 ret = visitor->visit( lastParag, 0, lastIndex );
00123 if (!ret) return false;
00124 }
00125
00126 KoTextParag* currentParag = forw ? firstParag->next() : lastParag->prev();
00127 KoTextParag * endParag = forw ? lastParag : firstParag;
00128 while ( currentParag && currentParag != endParag )
00129 {
00130 ret = visitor->visit( currentParag, 0, currentParag->length() - 1 );
00131 if (!ret) return false;
00132 currentParag = forw ? currentParag->next() : currentParag->prev();
00133 }
00134 Q_ASSERT( currentParag );
00135 Q_ASSERT( endParag == currentParag );
00136 if ( forw )
00137 ret = visitor->visit( lastParag, 0, lastIndex );
00138 else
00139 ret = visitor->visit( currentParag, firstIndex, currentParag->length() - 1 );
00140 return ret;
00141 }
00142 }
00143
00144 static bool is_printer( QPainter *p )
00145 {
00146 return p && p->device() && p->device()->devType() == QInternal::Printer;
00147 }
00148
00149 KoTextParag *KoTextDocument::drawWYSIWYG( QPainter *p, int cx, int cy, int cw, int ch, const QColorGroup &cg,
00150 KoZoomHandler* zoomHandler, bool onlyChanged,
00151 bool drawCursor, KoTextCursor *cursor,
00152 bool resetChanged, uint drawingFlags )
00153 {
00154 m_drawingFlags = drawingFlags;
00155 if ( is_printer( p ) ) {
00156
00157
00158
00159
00160 QRect crect( cx, cy, cw, ch );
00161 drawWithoutDoubleBuffer( p, crect, cg, zoomHandler );
00162 return 0;
00163 }
00164
00165
00166 if ( !firstParag() )
00167 return 0;
00168
00169 KoTextParag *lastFormatted = 0;
00170 KoTextParag *parag = firstParag();
00171
00172 QPixmap *doubleBuffer = 0;
00173 QPainter painter;
00174
00175 QRect crect( cx, cy, cw, ch );
00176 #ifdef DEBUG_PAINTING
00177 kdDebug(32500) << "\nKoTextDocument::drawWYSIWYG crect=" << crect << endl;
00178 #endif
00179
00180
00181 QRect pixelRect = parag->pixelRect( zoomHandler );
00182 if ( isPageBreakEnabled() && parag && cy <= pixelRect.y() && pixelRect.y() > 0 ) {
00183 QRect r( 0, 0,
00184 zoomHandler->layoutUnitToPixelX( parag->document()->x() + parag->document()->width() ),
00185 pixelRect.y() );
00186 r &= crect;
00187 if ( !r.isEmpty() ) {
00188 #ifdef DEBUG_PAINTING
00189 kdDebug(32500) << " drawWYSIWYG: space above first parag: " << r << " (pixels)" << endl;
00190 p->fillRect( r, cg.brush( QColorGroup::Base ) );
00191 #endif
00192 }
00193 }
00194
00195 while ( parag ) {
00196 lastFormatted = parag;
00197 if ( !parag->isValid() )
00198 parag->format();
00199
00200 QRect ir = parag->pixelRect( zoomHandler );
00201 #ifdef DEBUG_PAINTING
00202 kdDebug(32500) << " drawWYSIWYG: ir=" << ir << endl;
00203 #endif
00204 if ( isPageBreakEnabled() && parag->next() )
00205 {
00206 int nexty = parag->next()->pixelRect(zoomHandler).y();
00207
00208
00209 if ( ir.y() + ir.height() < nexty ) {
00210 QRect r( 0, ir.y() + ir.height(),
00211 zoomHandler->layoutUnitToPixelX( parag->document()->x() + parag->document()->width() ),
00212 nexty - ( ir.y() + ir.height() ) );
00213 r &= crect;
00214 if ( !r.isEmpty() )
00215 {
00216 #ifdef DEBUG_PAINTING
00217 kdDebug(32500) << " drawWYSIWYG: space between parag " << parag->paragId() << " and " << parag->next()->paragId() << " : " << r << " (pixels)" << endl;
00218 #endif
00219 p->fillRect( r, cg.brush( QColorGroup::Base ) );
00220 }
00221 }
00222 }
00223 if ( !ir.intersects( crect ) ) {
00224
00225 ir.setWidth( zoomHandler->layoutUnitToPixelX( parag->document()->width() ) );
00226 if ( ir.intersects( crect ) )
00227 p->fillRect( ir.intersect( crect ), cg.brush( QColorGroup::Base ) );
00228 if ( ir.y() > cy + ch ) {
00229
00230 goto floating;
00231 }
00232 }
00233 else if ( parag->hasChanged() || !onlyChanged ) {
00234
00235
00236
00237 if ( !onlyChanged && parag->lineChanged() > 0 )
00238 parag->setChanged( false );
00239 drawParagWYSIWYG( p, parag, cx, cy, cw, ch, doubleBuffer, cg,
00240 zoomHandler, drawCursor, cursor, resetChanged, drawingFlags );
00241 }
00242
00243 parag = parag->next();
00244 }
00245
00246 parag = lastParag();
00247
00248 floating:
00249 pixelRect = parag->pixelRect(zoomHandler);
00250 int docheight = zoomHandler->layoutUnitToPixelY( parag->document()->height() );
00251 if ( pixelRect.y() + pixelRect.height() < docheight ) {
00252 int docwidth = zoomHandler->layoutUnitToPixelX( parag->document()->width() );
00253 p->fillRect( 0, pixelRect.y() + pixelRect.height(),
00254 docwidth, docheight - ( pixelRect.y() + pixelRect.height() ),
00255 cg.brush( QColorGroup::Base ) );
00256 if ( !flow()->isEmpty() ) {
00257 QRect cr( cx, cy, cw, ch );
00258 cr = cr.intersect( QRect( 0, pixelRect.y() + pixelRect.height(), docwidth,
00259 docheight - ( pixelRect.y() + pixelRect.height() ) ) );
00260 flow()->drawFloatingItems( p, cr.x(), cr.y(), cr.width(), cr.height(), cg, FALSE );
00261 }
00262 }
00263
00264 if ( buf_pixmap && buf_pixmap->height() > 300 ) {
00265 delete buf_pixmap;
00266 buf_pixmap = 0;
00267 }
00268
00269
00270 return lastFormatted;
00271 }
00272
00273 void KoTextDocument::drawWithoutDoubleBuffer( QPainter *p, const QRect &cr, const QColorGroup &cg,
00274 KoZoomHandler* zoomHandler, const QBrush *paper )
00275 {
00276 if ( !firstParag() )
00277 return;
00278
00279 Q_ASSERT( (m_drawingFlags & DrawSelections) == 0 );
00280 if (m_drawingFlags & DrawSelections)
00281 kdDebug() << kdBacktrace();
00282 if ( paper ) {
00283 p->setBrushOrigin( -(int)p->translationX(),
00284 -(int)p->translationY() );
00285 p->fillRect( cr, *paper );
00286 }
00287
00288 KoTextParag *parag = firstParag();
00289 while ( parag ) {
00290 if ( !parag->isValid() )
00291 parag->format();
00292
00293 QRect pr( parag->pixelRect( zoomHandler ) );
00294 pr.setLeft( 0 );
00295 pr.setWidth( QWIDGETSIZE_MAX );
00296
00297 QRect crect_lu( parag->rect() );
00298
00299 if ( !cr.isNull() && !cr.intersects( pr ) ) {
00300 parag = parag->next();
00301 continue;
00302 }
00303 p->translate( 0, pr.y() );
00304 QBrush brush =
00305 cg.brush( QColorGroup::Base );
00306 if ( brush != Qt::NoBrush )
00307 p->fillRect( QRect( 0, 0, pr.width(), pr.height() ), brush );
00308
00309 parag->paint( *p, cg, 0, FALSE,
00310 crect_lu.x(), crect_lu.y(), crect_lu.width(), crect_lu.height() );
00311 p->translate( 0, -pr.y() );
00312
00313 parag = parag->next();
00314 }
00315 }
00316
00317
00318 void KoTextDocument::drawParagWYSIWYG( QPainter *p, KoTextParag *parag, int cx, int cy, int cw, int ch,
00319 QPixmap *&doubleBuffer, const QColorGroup &cg,
00320 KoZoomHandler* zoomHandler, bool drawCursor,
00321 KoTextCursor *cursor, bool resetChanged, uint drawingFlags )
00322 {
00323 if ((cw == 0) || (ch == 0)) return;
00324
00325 #ifdef DEBUG_PAINTING
00326 kdDebug(32500) << "KoTextDocument::drawParagWYSIWYG " << (void*)parag << " id:" << parag->paragId() << endl;
00327 #endif
00328 m_drawingFlags = drawingFlags;
00329 QPainter *painter = 0;
00330
00331 QRect rect = parag->pixelRect( zoomHandler );
00332
00333 int offsetY = 0;
00334
00335 if ( parag->lineChanged() > -1 )
00336 {
00337 offsetY = zoomHandler->layoutUnitToPixelY( parag->lineY( parag->lineChanged() ) - parag->topMargin() );
00338 #ifdef DEBUG_PAINTING
00339 kdDebug(32500) << " Repainting from lineChanged=" << parag->lineChanged() << " -> adding " << offsetY << " to rect" << endl;
00340 #endif
00341
00342 rect.rTop() += offsetY;
00343 }
00344
00345 QRect crect( cx, cy, cw, ch );
00346 QRect ir( rect );
00347 QBrush brush =
00348 cg.brush( QColorGroup::Base );
00349
00350 bool needBrush = brush.style() != Qt::NoBrush &&
00351 !(brush.style() == Qt::SolidPattern && brush.color() == Qt::white && is_printer(p));
00352
00353 bool useDoubleBuffer = !parag->document()->parent();
00354 if ( is_printer(p) )
00355 useDoubleBuffer = FALSE;
00356
00357
00359
00360 QWMatrix mat = p->worldMatrix();
00361 if ( ( mat.m11() != 1.0 || mat.m22() != 1.0 || mat.m12() != 0.0 || mat.m21() != 0.0 )
00362 && brush.style() != Qt::SolidPattern )
00363 useDoubleBuffer = FALSE;
00364
00365 #ifdef DEBUG_PAINTING
00366 kdDebug(32500) << "KoTextDocument::drawParagWYSIWYG parag->rect=" << parag->rect()
00367 << " pixelRect(ir)=" << ir
00368 << " crect (pixels)=" << crect
00369 << " useDoubleBuffer=" << useDoubleBuffer << endl;
00370 #endif
00371
00372 if ( useDoubleBuffer ) {
00373 painter = new QPainter;
00374 if ( cx >= 0 && cy >= 0 )
00375 ir = ir.intersect( crect );
00376 if ( !doubleBuffer ||
00377 ir.width() > doubleBuffer->width() ||
00378 ir.height() > doubleBuffer->height() )
00379 {
00380 doubleBuffer = bufferPixmap( ir.size() );
00381 }
00382 painter->begin( doubleBuffer );
00383
00384 } else {
00385 p->save();
00386 painter = p;
00387 painter->translate( ir.x(), ir.y() );
00388 }
00389
00390
00391
00392
00393
00394
00395
00396 if ( useDoubleBuffer || is_printer( painter ) ) {
00397
00398 if ( brush.style() != Qt::SolidPattern ) {
00399 bitBlt( doubleBuffer, 0, 0, p->device(),
00400 ir.x() + (int)p->translationX(), ir.y() + (int)p->translationY(),
00401 ir.width(), ir.height() );
00402 }
00403 }
00404 if ( needBrush )
00405 painter->fillRect( QRect( 0, 0, ir.width(), ir.height() ), brush );
00406
00407
00408 painter->translate( rect.x() - ir.x(), rect.y() - ir.y() );
00409 #ifdef DEBUG_PAINTING
00410 kdDebug(32500) << "KoTextDocument::drawParagWYSIWYG translate " << rect.x() - ir.x() << "," << rect.y() - ir.y() << endl;
00411 #endif
00412
00413
00414
00415 QRect crect_lu( zoomHandler->pixelToLayoutUnit( crect ) );
00416 #ifdef DEBUG_PAINTING
00417 kdDebug(32500) << "KoTextDocument::drawParagWYSIWYG crect_lu=" << crect_lu << endl;
00418 #endif
00419
00420
00421
00422
00423 painter->translate( 0, -offsetY );
00424
00425 parag->paint( *painter, cg, drawCursor ? cursor : 0, (m_drawingFlags & DrawSelections),
00426 crect_lu.x(), crect_lu.y(), crect_lu.width(), crect_lu.height() );
00427
00428
00429 if ( useDoubleBuffer ) {
00430 delete painter;
00431 painter = 0;
00432 p->drawPixmap( ir.topLeft(), *doubleBuffer, QRect( QPoint( 0, 0 ), ir.size() ) );
00433 #if 0 // for debug!
00434 p->save();
00435 p->setPen( Qt::blue );
00436 p->drawRect( ir.x(), ir.y(), ir.width(), ir.height() );
00437 p->restore();
00438 #endif
00439 } else {
00440
00441 p->restore();
00442
00443
00444
00445 }
00446
00447 if ( needBrush ) {
00448 int docright = zoomHandler->layoutUnitToPixelX( parag->document()->x() + parag->document()->width() );
00449 #ifdef DEBUG_PAINTING
00450
00451 #endif
00452 if ( rect.x() + rect.width() < docright ) {
00453 #ifdef DEBUG_PAINTING
00454 kdDebug(32500) << "KoTextDocument::drawParagWYSIWYG rect doesn't go up to docright=" << docright << endl;
00455 #endif
00456 p->fillRect( rect.x() + rect.width(), rect.y(),
00457 docright - ( rect.x() + rect.width() ),
00458 rect.height(), cg.brush( QColorGroup::Base ) );
00459 }
00460 }
00461
00462 if ( resetChanged )
00463 parag->setChanged( FALSE );
00464 }
00465
00466
00467 KoTextDocCommand *KoTextDocument::deleteTextCommand( KoTextDocument *textdoc, int id, int index, const QMemArray<KoTextStringChar> & str, const CustomItemsMap & customItemsMap, const QValueList<KoParagLayout> & oldParagLayouts )
00468 {
00469 return new KoTextDeleteCommand( textdoc, id, index, str, customItemsMap, oldParagLayouts );
00470 }
00471
00472 #include "kotextdocument.moc"