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"