00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
#include "kotextdocument.h"
00022
#include "koparagcounter.h"
00023
#include "kozoomhandler.h"
00024
#include "kostyle.h"
00025
#include <kglobal.h>
00026
#include <klocale.h>
00027
#include <assert.h>
00028
#include <kdebug.h>
00029
#include "kovariable.h"
00030
00031
00032
00033
00034
KoParagCounter *KoTextParag::counter()
00035 {
00036
if ( !m_layout.
counter )
00037
return 0L;
00038
00039
00040
if ( m_layout.
counter->
numbering() == KoParagCounter::NUM_NONE )
00041 setNoCounter();
00042
return m_layout.
counter;
00043 }
00044
00045
void KoTextParag::setMargin( QStyleSheetItem::Margin m,
double _i )
00046 {
00047
00048 m_layout.
margins[m] = _i;
00049
if ( m == QStyleSheetItem::MarginTop && prev() )
00050 prev()->invalidate(0);
00051 invalidate(0);
00052 }
00053
00054
void KoTextParag::setMargins(
const double * margins )
00055 {
00056
for (
int i = 0 ; i < 5 ; ++i )
00057 m_layout.
margins[i] = margins[i];
00058 invalidate(0);
00059 }
00060
00061
void KoTextParag::setAlign(
int align )
00062 {
00063 Q_ASSERT( align <= Qt::AlignJustify );
00064 align &= Qt::AlignHorizontal_Mask;
00065 setAlignment( align );
00066 m_layout.
alignment = align;
00067 }
00068
00069
int KoTextParag::resolveAlignment()
const
00070
{
00071
if ( m_layout.
alignment == Qt::AlignAuto )
00072
return string()->isRightToLeft() ? Qt::AlignRight : Qt::AlignLeft;
00073
return m_layout.
alignment;
00074 }
00075
00076
void KoTextParag::setLineSpacing(
double _i )
00077 {
00078 m_layout.
setLineSpacingValue(_i);
00079 invalidate(0);
00080 }
00081
00082
void KoTextParag::setLineSpacingType( KoParagLayout::SpacingType _type )
00083 {
00084 m_layout.
lineSpacingType = _type;
00085 invalidate(0);
00086 }
00087
00088
void KoTextParag::setTopBorder(
const KoBorder & _brd )
00089 {
00090 m_layout.
topBorder = _brd;
00091 invalidate(0);
00092 }
00093
00094
void KoTextParag::setBottomBorder(
const KoBorder & _brd )
00095 {
00096 m_layout.
bottomBorder = _brd;
00097 invalidate(0);
00098 }
00099
00100
void KoTextParag::setNoCounter()
00101 {
00102
delete m_layout.
counter;
00103 m_layout.
counter = 0L;
00104 invalidateCounters();
00105 }
00106
00107
void KoTextParag::setCounter(
const KoParagCounter & counter )
00108 {
00109
00110
if ( counter.
numbering() == KoParagCounter::NUM_NONE )
00111 {
00112 setNoCounter();
00113 }
00114
else
00115 {
00116
delete m_layout.
counter;
00117 m_layout.
counter =
new KoParagCounter( counter );
00118
00119
00120 invalidateCounters();
00121 }
00122 }
00123
00124
void KoTextParag::invalidateCounters()
00125 {
00126
00127
00128 invalidate( 0 );
00129
if ( m_layout.
counter )
00130 m_layout.
counter->
invalidate();
00131 KoTextParag *s = next();
00132
while ( s ) {
00133
if ( s->m_layout.counter )
00134 s->m_layout.counter->invalidate();
00135 s->invalidate( 0 );
00136 s = s->next();
00137 }
00138 }
00139
00140
int KoTextParag::counterWidth()
const
00141
{
00142
if ( !m_layout.
counter )
00143
return 0;
00144
00145
return m_layout.
counter->
width(
this );
00146 }
00147
00148
00149
00150
void KoTextParag::drawLabel(
QPainter* p,
int xLU,
int yLU,
int ,
int ,
int baseLU,
const QColorGroup& )
00151 {
00152
if ( !m_layout.
counter )
00153
return;
00154
00155
if ( m_layout.
counter->
numbering() == KoParagCounter::NUM_NONE )
00156 {
00157
delete m_layout.
counter;
00158 m_layout.
counter = 0L;
00159
return;
00160 }
00161
00162
int counterWidthLU = m_layout.
counter->
width(
this );
00163
00164
00165
00166
KoTextFormat counterFormat( *KoParagCounter::counterFormat(
this ) );
00167 counterFormat.
setBold(
false );
00168 counterFormat.
setItalic(
false );
00169
KoTextFormat* format = &counterFormat;
00170 p->save();
00171
00172
QColor textColor( format->
color() );
00173
if ( !textColor.isValid() )
00174 textColor =
KoTextFormat::defaultTextColor( p );
00175 p->setPen(
QPen( textColor ) );
00176
00177
KoZoomHandler * zh =
textDocument()->paintingZoomHandler();
00178 assert( zh );
00179
00180
00181
bool rtl = str->isRightToLeft();
00182
int xLeft = zh->
layoutUnitToPixelX( xLU - (rtl ? 0 : counterWidthLU) );
00183
int y = zh->
layoutUnitToPixelY( yLU );
00184
00185
int base = zh->
layoutUnitToPixelY( yLU, baseLU );
00186
int counterWidth = zh->
layoutUnitToPixelX( xLU, counterWidthLU );
00187
int height = zh->
layoutUnitToPixelY( yLU, format->
height() );
00188
00189
QFont font( format->
screenFont( zh ) );
00190
00191
if ( m_layout.
counter->
numbering() == KoParagCounter::NUM_FOOTNOTE )
00192 {
00193
int pointSize = ( ( font.
pointSize() * 2 ) / 3 );
00194 font.setPointSize( pointSize );
00195 y -= ( height -
QFontMetrics(font).height() );
00196 }
00197 p->setFont( font );
00198
00199
00200
if ( m_layout.
counter->
isBullet() )
00201 {
00202
int xBullet = xLeft + zh->
layoutUnitToPixelX( m_layout.
counter->
bulletX() );
00203
00204
00205
00206
int width = zh->
layoutUnitToPixelX( xLeft, format->
width(
' ' ) );
00207
00208
00209
00210
00211
QString prefix = m_layout.
counter->
prefix();
00212
if ( !prefix.isEmpty() )
00213 {
00214
if ( rtl )
00215 prefix.prepend(
' ' );
00216 KoTextParag::drawFontEffects( p, format, zh, format->
screenFont( zh ), textColor, xLeft, base, width, y, height, prefix[0] );
00217
00218
int posY =y + base - format->
offsetFromBaseLine();
00219
00220
00221
int sy = format->
shadowY( zh );
00222
if ( sy < 0)
00223 posY -= sy;
00224
00225 p->drawText( xLeft, posY, prefix );
00226 }
00227
00228
QRect er( xBullet + (rtl ? width : 0), y + height / 2 - width / 2, width, width );
00229
00230
int posY = 0;
00231
switch ( m_layout.
counter->
style() )
00232 {
00233
case KoParagCounter::STYLE_DISCBULLET:
00234 p->setBrush(
QBrush(textColor) );
00235 p->drawEllipse( er );
00236 p->setBrush( Qt::NoBrush );
00237
break;
00238
case KoParagCounter::STYLE_SQUAREBULLET:
00239 p->fillRect( er,
QBrush(textColor) );
00240
break;
00241
case KoParagCounter::STYLE_BOXBULLET:
00242 p->drawRect( er );
00243
break;
00244
case KoParagCounter::STYLE_CIRCLEBULLET:
00245 p->drawEllipse( er );
00246
break;
00247
case KoParagCounter::STYLE_CUSTOMBULLET:
00248 {
00249
00250
00251
if ( !m_layout.
counter->
customBulletFont().isEmpty() )
00252 {
00253
QFont bulletFont( p->font() );
00254 bulletFont.setFamily( m_layout.
counter->
customBulletFont() );
00255 p->setFont( bulletFont );
00256 }
00257 KoTextParag::drawFontEffects( p, format, zh, format->
screenFont( zh ), textColor, xBullet, base, width, y, height,
' ' );
00258
00259 posY = y + base- format->
offsetFromBaseLine();
00260
00261
00262
int sy = format->
shadowY( zh );
00263
if ( sy < 0)
00264 posY -= sy;
00265
00266 p->drawText( xBullet, posY, m_layout.
counter->
customBulletCharacter() );
00267
break;
00268 }
00269
default:
00270
break;
00271 }
00272
00273
QString suffix = m_layout.
counter->
suffix();
00274
if ( !suffix.isEmpty() )
00275 {
00276
if ( !rtl )
00277 suffix +=
' ' ;
00278
00279 KoTextParag::drawFontEffects( p, format, zh, format->
screenFont( zh ), textColor, xBullet + width, base, counterWidth, y,height, suffix[0] );
00280
00281
int posY =y + base- format->
offsetFromBaseLine();
00282
00283
00284
int sy = format->
shadowY( zh );
00285
if ( sy < 0)
00286 posY -= sy;
00287
00288 p->drawText( xBullet + width, posY, suffix, -1 );
00289 }
00290 }
00291
else
00292 {
00293
QString counterText = m_layout.
counter->
text(
this );
00294
00295
00296
if ( !counterText.isEmpty() )
00297 {
00298 KoTextParag::drawFontEffects( p, format, zh, format->
screenFont( zh ), textColor, xLeft, base, counterWidth, y, height, counterText[0] );
00299
00300 counterText +=
' ' ;
00301
00302
int posY =y + base - format->
offsetFromBaseLine();
00303
00304
00305
int sy = format->
shadowY( zh );
00306
if ( sy < 0)
00307 posY -= sy;
00308
00309 p->drawText( xLeft, posY , counterText, -1 );
00310 }
00311 }
00312 p->restore();
00313 }
00314
00315
int KoTextParag::breakableTopMargin()
const
00316
{
00317
KoZoomHandler * zh =
textDocument()->formattingZoomHandler();
00318
return zh->
ptToLayoutUnitPixY(
00319 m_layout.
margins[ QStyleSheetItem::MarginTop ] );
00320 }
00321
00322
int KoTextParag::topMargin()
const
00323
{
00324
KoZoomHandler * zh =
textDocument()->formattingZoomHandler();
00325
return zh->
ptToLayoutUnitPixY(
00326 m_layout.
margins[ QStyleSheetItem::MarginTop ]
00327 + m_layout.
topBorder.
width() );
00328 }
00329
00330
int KoTextParag::bottomMargin()
const
00331
{
00332
KoZoomHandler * zh =
textDocument()->formattingZoomHandler();
00333
return zh->
ptToLayoutUnitPixY(
00334 m_layout.
margins[ QStyleSheetItem::MarginBottom ]
00335 + m_layout.
bottomBorder.
width() );
00336 }
00337
00338
int KoTextParag::leftMargin()
const
00339
{
00340
KoZoomHandler * zh =
textDocument()->formattingZoomHandler();
00341
return zh->
ptToLayoutUnitPixX(
00342 m_layout.
margins[ QStyleSheetItem::MarginLeft ]
00343 + m_layout.
leftBorder.
width() );
00344 }
00345
00346
int KoTextParag::rightMargin()
const
00347
{
00348
KoZoomHandler * zh =
textDocument()->formattingZoomHandler();
00349
int cw=0;
00350
if( m_layout.
counter && str->isRightToLeft() &&
00351 (( m_layout.
counter->
alignment() == Qt::AlignRight ) || ( m_layout.
counter->
alignment() == Qt::AlignAuto )))
00352 cw = counterWidth();
00353
00354
return zh->
ptToLayoutUnitPixX(
00355 m_layout.
margins[ QStyleSheetItem::MarginRight ]
00356 + m_layout.
rightBorder.
width() )
00357 + cw;
00358 }
00359
00360
int KoTextParag::firstLineMargin()
const
00361
{
00362
KoZoomHandler * zh =
textDocument()->formattingZoomHandler();
00363
return zh->
ptToLayoutUnitPixY(
00364 m_layout.
margins[ QStyleSheetItem::MarginFirstLine ] );
00365 }
00366
00367
int KoTextParag::lineSpacing(
int line )
const
00368
{
00369
KoZoomHandler * zh =
textDocument()->formattingZoomHandler();
00370
00371
int shadow = 0;
00372
if ( m_layout.
lineSpacingType == KoParagLayout::LS_SINGLE )
00373
return shadow;
00374
else if ( m_layout.
lineSpacingType == KoParagLayout::LS_CUSTOM )
00375
return zh->
ptToLayoutUnitPixY( m_layout.
lineSpacingValue() ) + shadow;
00376
else {
00377 KoTextParag * that = const_cast<KoTextParag *>(
this);
00378
if( line >= (
int)that->lineStartList().count() )
00379 {
00380 kdError() <<
"KoTextParag::lineSpacing assert(line<lines) failed: line=" << line <<
" lines=" << that->lineStartList().count() << endl;
00381
return 0+shadow;
00382 }
00383
QMap<int, KoTextParagLineStart*>::ConstIterator it = that->lineStartList().begin();
00384
while ( line-- > 0 )
00385 ++it;
00386
if ( isValid() )
00387
return (*it)->lineSpacing;
00388
00389
int height = ( *it )->h;
00390
00391
switch ( m_layout.
lineSpacingType )
00392 {
00393
case KoParagLayout::LS_MULTIPLE:
00394 {
00395
double n = QMAX( m_layout.
lineSpacingValue() - 1.0, 0.0 );
00396
return shadow + qRound( n * height );
00397 }
00398
case KoParagLayout::LS_ONEANDHALF:
00399 {
00400
00401
return shadow + height / 2;
00402 }
00403
case KoParagLayout::LS_DOUBLE:
00404 {
00405
00406
return shadow + height;
00407 }
00408
case KoParagLayout::LS_AT_LEAST:
00409 {
00410
int atLeast = zh->
ptToLayoutUnitPixY( m_layout.
lineSpacingValue() );
00411
int h = QMAX( height, atLeast );
00412
00413
return shadow + h - height;
00414 }
00415
case KoParagLayout::LS_FIXED:
00416 {
00417
return shadow + zh->
ptToLayoutUnitPixY( m_layout.
lineSpacingValue() ) - height;
00418 }
00419
00420
case KoParagLayout::LS_SINGLE:
00421
case KoParagLayout::LS_CUSTOM:
00422
break;
00423 }
00424 }
00425 kdWarning() <<
"Unhandled linespacing type : " << m_layout.
lineSpacingType << endl;
00426
return 0+shadow;
00427 }
00428
00429
QRect KoTextParag::pixelRect(
KoZoomHandler *zh )
const
00430
{
00431
QRect rct( zh->
layoutUnitToPixel( rect() ) );
00432
00433
00434
00435
00436
if ( prev() )
00437 {
00438
QRect prevRect( zh->
layoutUnitToPixel( prev()->rect() ) );
00439
if ( rct.top() < prevRect.bottom() + 1 )
00440 {
00441
00442 rct.setTop( prevRect.bottom() + 1 );
00443 }
00444 }
00445
return rct;
00446 }
00447
00448
00449
00450
void KoTextParag::paint(
QPainter &painter,
const QColorGroup &cg, KoTextCursor *cursor,
bool drawSelections,
00451
int clipx,
int clipy,
int clipw,
int cliph )
00452 {
00453
#ifdef DEBUG_PAINT
00454
kdDebug(32500) <<
"KoTextParag::paint ===== id=" << paragId() <<
" clipx=" << clipx <<
" clipy=" << clipy <<
" clipw=" << clipw <<
" cliph=" << cliph << endl;
00455 kdDebug(32500) <<
" clipw in pix (approx) : " <<
textDocument()->paintingZoomHandler()->layoutUnitToPixelX( clipw ) <<
" cliph in pix (approx) : " <<
textDocument()->paintingZoomHandler()->layoutUnitToPixelX( cliph ) << endl;
00456
#endif
00457
00458
00459
if ( m_layout.
counter && m_layout.
counter->
numbering() != KoParagCounter::NUM_NONE && m_lineChanged <= 0 )
00460 {
00461
int cy, h, baseLine;
00462 lineInfo( 0, cy, h, baseLine );
00463
int xLabel = at(0)->x;
00464
if ( str->isRightToLeft() )
00465 xLabel += at(0)->width;
00466 drawLabel( &painter, xLabel, cy, 0, 0, baseLine, cg );
00467 }
00468
00469 paintLines( painter, cg, cursor, drawSelections, clipx, clipy, clipw, cliph );
00470
00471
00472
if ( m_layout.
hasBorder() )
00473 {
00474
KoZoomHandler * zh =
textDocument()->paintingZoomHandler();
00475 assert(zh);
00476
00477
QRect r;
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488 r.setLeft( KoBorder::zoomWidthX( m_layout.
leftBorder.
width(), zh, 0 ) );
00489
00490 r.setRight( zh->
layoutUnitToPixelX(rect().width()) - KoBorder::zoomWidthX( m_layout.
rightBorder.
width(), zh, 0 ) );
00491 r.setTop( zh->
layoutUnitToPixelY(lineY( 0 )) );
00492
00493
int lastLine = lines() - 1;
00494
00495
00496
int paragBottom = pixelRect(zh).height()-1;
00497
00498
00499
if ( m_layout.
bottomBorder.
width() > 0 )
00500 paragBottom -= zh->
layoutUnitToPixelY( lineSpacing( lastLine ) );
00501 paragBottom -= KoBorder::zoomWidthY( m_layout.
bottomBorder.
width(), zh, 0 );
00502
00503
00504 r.setBottom( paragBottom );
00505
00506
00507 KoBorder::drawBorders( painter, zh, r,
00508 m_layout.
leftBorder, m_layout.
rightBorder, m_layout.
topBorder, m_layout.
bottomBorder,
00509 0,
QPen() );
00510 }
00511 }
00512
00513
00514
void KoTextParag::paintLines(
QPainter &painter,
const QColorGroup &cg, KoTextCursor *cursor,
bool drawSelections,
00515
int clipx,
int clipy,
int clipw,
int cliph )
00516 {
00517
if ( !visible )
00518
return;
00519
00520
00521
00522
00523
00524
#define CHECK_PIXELXADJ
00525
00526
int curx = -1, cury = 0, curh = 0, curline = 0;
00527
int xstart, xend = 0;
00528
00529
QString qstr = str->toString();
00530 qstr.replace(
QChar(0x00a0U),
' ' );
00531
00532
const int nSels = doc ? doc->numSelections() : 1;
00533
QMemArray<int> selectionStarts( nSels );
00534
QMemArray<int> selectionEnds( nSels );
00535
if ( drawSelections ) {
00536
bool hasASelection = FALSE;
00537
for (
int i = 0; i < nSels; ++i ) {
00538
if ( !
hasSelection( i ) ) {
00539 selectionStarts[ i ] = -1;
00540 selectionEnds[ i ] = -1;
00541 }
else {
00542 hasASelection = TRUE;
00543 selectionStarts[ i ] = selectionStart( i );
00544
int end = selectionEnd( i );
00545
if ( end == length() - 1 && n && n->hasSelection( i ) )
00546 end++;
00547 selectionEnds[ i ] = end;
00548 }
00549 }
00550
if ( !hasASelection )
00551 drawSelections = FALSE;
00552 }
00553
00554
00555
int line = m_lineChanged;
00556
if (line<0) line = 0;
00557
00558
int numLines = lines();
00559
#ifdef DEBUG_PAINT
00560
kdDebug(32500) <<
" paintLines: from line " << line <<
" to " << numLines-1 << endl;
00561
#endif
00562
for( ; line<numLines ; line++ )
00563 {
00564
00565
int nextLine;
00566
int startOfLine;
00567 lineStartOfLine(line, &startOfLine);
00568
if (line == numLines-1 )
00569 nextLine = length();
00570
else
00571 lineStartOfLine(line+1, &nextLine);
00572
00573
00574
int cy, h, baseLine;
00575 lineInfo( line, cy, h, baseLine );
00576
if ( clipy != -1 && cy > clipy - r.y() + cliph )
00577
break;
00578
00579
00580
int paintStart = startOfLine;
00581 KoTextStringChar* chr = at(startOfLine);
00582 KoTextStringChar* nextchr = chr;
00583
00584
00585
for(
int i=startOfLine;i<nextLine;i++)
00586 {
00587 chr = nextchr;
00588
if ( i < nextLine-1 )
00589 nextchr = at( i+1 );
00590
00591
00592
bool flush = ( i == nextLine - 1 );
00593
00594
00595
00596 flush = flush || ( nextchr->format() != chr->format() );
00597
00598
00599
00600
if ( !flush && chr->format()->attributeFont() == KoTextFormat::ATT_SMALL_CAPS )
00601 {
00602
bool isLowercase = chr->c.upper() != chr->c;
00603
bool nextLowercase = nextchr->c.upper() != nextchr->c;
00604 flush = isLowercase != nextLowercase;
00605 }
00606
00607 flush = flush || nextchr->startOfRun;
00608
00609 flush = flush || ( nextchr->rightToLeft != chr->rightToLeft );
00610
#ifdef CHECK_PIXELXADJ
00611
00612
00613 flush = flush || ( nextchr->pixelxadj != chr->pixelxadj && nextchr->charStop );
00614
#endif
00615
00616 flush = flush || ( chr->c ==
'\t' || nextchr->c ==
'\t' );
00617
00618 flush = flush || ( chr->c.unicode() == 0xad );
00619
00620 flush = flush || chr->isCustom();
00621
00622 flush = flush || nextchr->isCustom();
00623
00624
if ((alignment() & Qt::AlignJustify) == Qt::AlignJustify )
00625
00626 flush = flush || chr->whiteSpace;
00627
00628
if (!flush && chr->format()->wordByWord() && chr->format()->isStrikedOrUnderlined())
00629 flush = flush || chr->whiteSpace || nextchr->whiteSpace;
00630
00631 flush = flush || ( i - paintStart >= 256 );
00632
00633
if ( drawSelections ) {
00634
00635
bool selectionChange = FALSE;
00636
if ( drawSelections ) {
00637
for (
int j = 0; j < nSels; ++j ) {
00638 selectionChange = selectionStarts[ j ] == i+1 || selectionEnds[ j ] == i+1;
00639
if ( selectionChange )
00640
break;
00641 }
00642 }
00643 flush = flush || selectionChange;
00644 }
00645
00646
00647
if ( cursor &&
this == cursor->parag() && i == cursor->index() ) {
00648 curx = cursor->x();
00649 curline = line;
00650 KoTextStringChar *c = chr;
00651
if ( i > 0 )
00652 --c;
00653 curh = c->height();
00654 cury = cy + baseLine - c->ascent();
00655 }
00656
00657
if ( flush ) {
00658
00659 KoTextStringChar* cStart = at( paintStart );
00660
if ( chr->rightToLeft ) {
00661 xstart = chr->x;
00662 xend = cStart->x + cStart->width;
00663 }
else {
00664 xstart = cStart->x;
00665
if ( i < length() - 1 && !str->at( i + 1 ).lineStart &&
00666 str->at( i + 1 ).rightToLeft == chr->rightToLeft )
00667 xend = str->at( i + 1 ).x;
00668
else
00669 xend = chr->x + chr->width;
00670 }
00671
00672
if ( (clipx == -1 || clipw == -1) || (xend >= clipx && xstart <= clipx + clipw) ) {
00673
if ( !chr->isCustom() ) {
00674 drawParagString( painter, qstr, paintStart, i - paintStart + 1, xstart, cy,
00675 baseLine, xend-xstart, h, drawSelections,
00676 chr->format(), selectionStarts, selectionEnds,
00677 cg, chr->rightToLeft, line );
00678 }
00679
else
00680
if ( chr->customItem()->placement() == KoTextCustomItem::PlaceInline ) {
00681 chr->customItem()->draw( &painter, chr->x, cy + baseLine - chr->customItem()->ascent(), clipx - r.x(), clipy - r.y(), clipw, cliph, cg,
00682 drawSelections && nSels && selectionStarts[ 0 ] <= i && selectionEnds[ 0 ] > i );
00683 }
00684 }
00685 paintStart = i+1;
00686 }
00687 }
00688 }
00689
00690
00691
if ( curx != -1 && cursor ) {
00692 drawCursor( painter, cursor, curx, cury, curh, cg );
00693 }
00694 }
00695
00696
00697
00698
00699
void KoTextParag::drawParagString(
QPainter &painter,
const QString &str,
int start,
int len,
int startX,
00700
int lastY,
int baseLine,
int bw,
int h,
bool drawSelections,
00701
KoTextFormat *format,
const QMemArray<int> &selectionStarts,
00702
const QMemArray<int> &selectionEnds,
const QColorGroup &cg,
bool rightToLeft,
int line )
00703 {
00704
KoZoomHandler * zh =
textDocument()->paintingZoomHandler();
00705 assert(zh);
00706
00707
#ifdef DEBUG_PAINT
00708
kdDebug(32500) <<
"KoTextParag::drawParagString drawing from " << start <<
" to " << start+len << endl;
00709 kdDebug(32500) <<
" startX in LU: " << startX <<
" lastY in LU:" << lastY
00710 <<
" baseLine in LU:" << baseLine << endl;
00711
#endif
00712
00713
00714
00715
00716
int shadowOffsetX_pix = zh->
layoutUnitToPixelX( format->
offsetX() );
00717
int shadowOffsetY_pix = zh->
layoutUnitToPixelY( format->
offsetY() );
00718
00719
00720
int startX_pix = zh->
layoutUnitToPixelX( startX ) ;
00721
#ifdef DEBUG_PAINT
00722
kdDebug(32500) <<
"KoTextParag::drawParagString startX in pixels : " << startX_pix <<
" bw=" << bw << endl;
00723
#endif
00724
00725
int bw_pix = zh->
layoutUnitToPixelX( startX, bw );
00726
int lastY_pix = zh->
layoutUnitToPixelY( lastY );
00727
int baseLine_pix = zh->
layoutUnitToPixelY( lastY, baseLine );
00728
int h_pix = zh->
layoutUnitToPixelY( lastY, h );
00729
#ifdef DEBUG_PAINT
00730
kdDebug(32500) <<
"KoTextParag::drawParagString h(LU)=" << h <<
" lastY(LU)=" << lastY
00731 <<
" h(PIX)=" << h_pix <<
" lastY(PIX)=" << lastY_pix
00732 <<
" baseLine(PIX)=" << baseLine_pix << endl;
00733
#endif
00734
00735
if ( format->
textBackgroundColor().isValid() )
00736 painter.fillRect( startX_pix, lastY_pix, bw_pix, h_pix, format->
textBackgroundColor() );
00737
00738
00739
int draw_len = len;
00740
int draw_startX = startX;
00741
int draw_bw = bw_pix;
00742
if ( at( start + len - 1 )->c ==
'\n' )
00743 {
00744 draw_len--;
00745 draw_bw -= at( start + len - 1 )->pixelwidth;
00746
if ( rightToLeft && draw_len > 0 )
00747 draw_startX = at( start + draw_len - 1 )->x;
00748 }
00749
00750
00751
00752
if ( drawSelections ) {
00753
bool inSelection =
false;
00754
const int nSels = doc ? doc->numSelections() : 1;
00755
for (
int j = 0; j < nSels; ++j ) {
00756
if ( start >= selectionStarts[ j ] && start < selectionEnds[ j ] ) {
00757 inSelection =
true;
00758
if ( j == KoTextDocument::Standard )
00759 painter.fillRect( startX_pix, lastY_pix, bw_pix, h_pix, cg.color( QColorGroup::Highlight ) );
00760
else
00761 painter.fillRect( startX_pix, lastY_pix, bw_pix, h_pix, doc ? doc->selectionColor( j ) : cg.color(
QColorGroup::Highlight ) );
00762
break;
00763 }
00764 }
00765
if ( !inSelection )
00766 drawSelections =
false;
00767 }
00768
00769
if ( draw_len > 0 )
00770 {
00771
int draw_startX_pix = zh->
layoutUnitToPixelX( draw_startX ) ;
00772 draw_startX_pix += shadowOffsetX_pix;
00773 lastY_pix += shadowOffsetY_pix;
00774
00775
if ( format->
shadowDistanceX() != 0 || format->
shadowDistanceY() != 0 ) {
00776
int sx = format->
shadowX( zh );
00777
int sy = format->
shadowY( zh );
00778
if ( sx != 0 || sy != 0 )
00779 {
00780 painter.save();
00781 painter.
translate( sx, sy );
00782 drawParagStringInternal( painter, str, start, draw_len, draw_startX_pix,
00783 lastY_pix, baseLine_pix,
00784 draw_bw,
00785 h_pix, FALSE ,
00786 format, selectionStarts,
00787 selectionEnds, cg, rightToLeft, line, zh,
true );
00788 painter.restore();
00789 }
00790 }
00791
00792 drawParagStringInternal( painter, str, start, draw_len, draw_startX_pix,
00793 lastY_pix, baseLine_pix,
00794 draw_bw,
00795 h_pix, drawSelections, format, selectionStarts,
00796 selectionEnds, cg, rightToLeft, line, zh,
false );
00797 }
00798
00799
bool forPrint = ( painter.device()->devType() == QInternal::Printer );
00800
if (
textDocument()->drawFormattingChars() && !forPrint )
00801 {
00802 drawFormattingChars( painter, start, len,
00803 lastY_pix, baseLine_pix, h_pix,
00804 drawSelections,
00805 format, selectionStarts,
00806 selectionEnds, cg, rightToLeft,
00807 line, zh, AllFormattingChars );
00808 }
00809 }
00810
00811
00812
00813
00814
00815
void KoTextParag::drawParagStringInternal(
QPainter &painter,
const QString &s,
int start,
int len,
int startX,
00816
int lastY,
int baseLine,
int bw,
int h,
bool drawSelections,
00817
KoTextFormat *format,
const QMemArray<int> &selectionStarts,
00818
const QMemArray<int> &selectionEnds,
const QColorGroup &cg,
bool rightToLeft,
int line,
KoZoomHandler* zh,
bool drawingShadow )
00819 {
00820
#ifdef DEBUG_PAINT
00821
kdDebug(32500) <<
"KoTextParag::drawParagStringInternal start=" << start <<
" len=" << len <<
" : '" << s.mid(start,len) <<
"'" << endl;
00822 kdDebug(32500) <<
"In pixels: startX=" << startX <<
" lastY=" << lastY <<
" baseLine=" << baseLine
00823 <<
" bw=" << bw <<
" h=" << h <<
" rightToLeft=" << rightToLeft << endl;
00824
#endif
00825
if ( drawingShadow && format->
shadowDistanceX() == 0 && format->
shadowDistanceY() == 0 )
00826
return;
00827
00828
QColor textColor( drawingShadow ? format->
shadowColor() : format->color() );
00829
if ( !textColor.isValid() )
00830 textColor =
KoTextFormat::defaultTextColor( &painter );
00831
00832
00833
QFont font( format->
screenFont( zh ) );
00834
if ( format->
attributeFont() == KoTextFormat::ATT_SMALL_CAPS && s[start].upper() != s[start] )
00835 font = format->
smallCapsFont( zh,
true );
00836
00837
#if 0
00838
QFontInfo fi( font );
00839 kdDebug(32500) <<
"KoTextParag::drawParagStringInternal requested font " << font.pointSizeFloat() <<
" using font " << fi.pointSize() <<
"pt (format font: " << format->
font().pointSizeFloat() <<
"pt)" << endl;
00840
QFontMetrics fm( font );
00841 kdDebug(32500) <<
"Real font: " << fi.family() <<
". Font height in pixels: " << fm.height() << endl;
00842
#endif
00843
00844
00845
QString str( s );
00846
if ( str[ (
int)str.length() - 1 ].unicode() == 0xad )
00847 str.remove( str.length() - 1, 1 );
00848 painter.setPen(
QPen( textColor ) );
00849 painter.setFont( font );
00850
00851 KoTextDocument* doc = document();
00852
00853
if ( drawSelections ) {
00854
const int nSels = doc ? doc->numSelections() : 1;
00855
for (
int j = 0; j < nSels; ++j ) {
00856
if ( start >= selectionStarts[ j ] && start < selectionEnds[ j ] ) {
00857
if ( !doc || doc->invertSelectionText( j ) )
00858 textColor = cg.color( QColorGroup::HighlightedText );
00859 painter.setPen(
QPen( textColor ) );
00860
break;
00861 }
00862 }
00863 }
00864
00865 QPainter::TextDirection dir = rightToLeft ? QPainter::RTL : QPainter::LTR;
00866
00867
if ( dir != QPainter::RTL && start + len == length() )
00868 {
00869 len--;
00870
if ( len <= 0 )
00871
return;
00872 bw-=at(length()-1)->pixelwidth;
00873 }
00874 KoTextParag::drawFontEffects( &painter, format, zh, font, textColor, startX, baseLine, bw, lastY, h, str[start] );
00875
00876
if ( str[ start ] !=
'\t' && str[ start ].unicode() != 0xad ) {
00877 str = format->
displayedString( str );
00878
if ( format->
vAlign() == KoTextFormat::AlignNormal ) {
00879
int posY = lastY + baseLine - format->
offsetFromBaseLine();
00880
00881
00882
int sy = format->
shadowY( zh );
00883
if ( sy < 0)
00884 posY -= sy;
00885 painter.drawText( startX, posY, str, start, len, dir );
00886
#ifdef BIDI_DEBUG
00887
painter.save();
00888 painter.setPen ( Qt::red );
00889 painter.drawLine( startX, lastY, startX, lastY + baseLine );
00890 painter.drawLine( startX, lastY + baseLine/2, startX + 10, lastY + baseLine/2 );
00891
int w = 0;
00892
int i = 0;
00893
while( i < len )
00894 w += painter.fontMetrics().charWidth( str, start + i++ );
00895 painter.setPen ( Qt::blue );
00896 painter.drawLine( startX + w - 1, lastY, startX + w - 1, lastY + baseLine );
00897 painter.drawLine( startX + w - 1, lastY + baseLine/2, startX + w - 1 - 10, lastY + baseLine/2 );
00898 painter.restore();
00899
#endif
00900
}
else if ( format->
vAlign() == KoTextFormat::AlignSuperScript ) {
00901
int posY =lastY + baseLine - ( painter.fontMetrics().height() / 2 )-format->
offsetFromBaseLine();
00902
00903
00904
int sy = format->
shadowY( zh );
00905
if ( sy < 0)
00906 posY -= sy;
00907 painter.drawText( startX, posY, str, start, len, dir );
00908 }
else if ( format->
vAlign() == KoTextFormat::AlignSubScript ) {
00909
int posY =lastY + baseLine + ( painter.fontMetrics().height() / 6 )-format->
offsetFromBaseLine();
00910
00911
00912
int sy = format->
shadowY( zh );
00913
if ( sy < 0)
00914 posY -= sy;
00915 painter.drawText( startX, posY, str, start, len, dir );
00916 }
00917 }
00918
if ( str[ start ] ==
'\t' && m_tabCache.contains( start ) ) {
00919 painter.save();
00920
KoZoomHandler * zh =
textDocument()->paintingZoomHandler();
00921
const KoTabulator& tab = m_layout.
tabList()[ m_tabCache[ start ] ];
00922
int lineWidth = zh->
zoomItY( tab.
ptWidth );
00923
switch ( tab.
filling ) {
00924
case TF_DOTS:
00925 painter.setPen(
QPen( textColor, lineWidth, Qt::DotLine ) );
00926 painter.drawLine( startX, lastY + baseLine, startX + bw, lastY + baseLine );
00927
break;
00928
case TF_LINE:
00929 painter.setPen(
QPen( textColor, lineWidth, Qt::SolidLine ) );
00930 painter.drawLine( startX, lastY + baseLine, startX + bw, lastY + baseLine );
00931
case TF_DASH:
00932 painter.setPen(
QPen( textColor, lineWidth, Qt::DashLine ) );
00933 painter.drawLine( startX, lastY + baseLine, startX + bw, lastY + baseLine );
00934
break;
00935
case TF_DASH_DOT:
00936 painter.setPen(
QPen( textColor, lineWidth, Qt::DashDotLine ) );
00937 painter.drawLine( startX, lastY + baseLine, startX + bw, lastY + baseLine );
00938
break;
00939
case TF_DASH_DOT_DOT:
00940 painter.setPen(
QPen( textColor, lineWidth, Qt::DashDotDotLine ) );
00941 painter.drawLine( startX, lastY + baseLine, startX + bw, lastY + baseLine );
00942
break;
00943
00944
default:
00945
break;
00946 }
00947 painter.restore();
00948 }
00949
00950
if ( start+len < length() && at( start+len )->lineStart )
00951 {
00952
#ifdef DEBUG_PAINT
00953
00954
#endif
00955
bool drawHyphen = at( start+len-1 )->c.unicode() == 0xad;
00956 drawHyphen = drawHyphen || lineHyphenated( line );
00957
if ( drawHyphen ) {
00958
#ifdef DEBUG_PAINT
00959
kdDebug(32500) <<
"drawing hyphen at x=" << startX+bw << endl;
00960
#endif
00961
painter.drawText( startX + bw, lastY + baseLine,
"-" );
00962 }
00963 }
00964
00965
00966
if(
00967 painter.device()->devType() != QInternal::Printer &&
00968 format->
isMisspelled() &&
00969 !drawingShadow &&
00970
textDocument()->drawingMissingSpellLine() )
00971 {
00972 painter.save();
00973 painter.setPen(
QPen( Qt::red, 1 ) );
00974
00975
00976
for(
int zigzag_line = 0; zigzag_line < 3; ++zigzag_line )
00977 {
00978
for(
int zigzag_x = zigzag_line; zigzag_x < bw; zigzag_x += 4 )
00979 {
00980 painter.drawPoint(
00981 startX + zigzag_x,
00982 lastY + baseLine + h/12 - 1 + zigzag_line );
00983 }
00984 }
00985
00986
00987
for(
int zigzag_x = 3; zigzag_x < bw; zigzag_x += 4 )
00988 {
00989 painter.drawPoint(
00990 startX + zigzag_x,
00991 lastY + baseLine + h/12 );
00992 }
00993
00994 painter.restore();
00995 }
00996 }
00997
00998
bool KoTextParag::lineHyphenated(
int l )
const
00999
{
01000
if ( l > (
int)lineStarts.count() - 1 ) {
01001 kdWarning() <<
"KoTextParag::lineHyphenated: line " << l <<
" out of range!" << endl;
01002
return false;
01003 }
01004
01005
if ( !isValid() )
01006 const_cast<KoTextParag*>(
this)->format();
01007
01008
QMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
01009
while ( l-- > 0 )
01010 ++it;
01011
return ( *it )->hyphenated;
01012 }
01013
01015
void KoTextParag::drawCursor(
QPainter &painter, KoTextCursor *cursor,
int curx,
int cury,
int curh,
const QColorGroup &cg )
01016 {
01017
KoZoomHandler * zh =
textDocument()->paintingZoomHandler();
01018
int x = zh->
layoutUnitToPixelX( curx ) ;
01019
01020 KoTextParag::drawCursorDefault( painter, cursor, x,
01021 zh->
layoutUnitToPixelY( cury ),
01022 zh->
layoutUnitToPixelY( cury, curh ), cg );
01023 }
01024
01025
01026
void KoTextParag::copyParagData( KoTextParag *parag )
01027 {
01028
01029
KoStyle * style = parag->style();
01030
01031
bool styleApplied =
false;
01032
if ( style )
01033 {
01034
KoStyle * newStyle = style->
followingStyle();
01035
if ( newStyle && style != newStyle )
01036 {
01037 setParagLayout( newStyle->
paragLayout() );
01038
KoTextFormat * format = &newStyle->format();
01039
setFormat( format );
01040 format->
addRef();
01041 string()->setFormat( 0, format,
true );
01042 styleApplied =
true;
01043 }
01044 }
01045
01046
01047
01048
01049
01050
if (!styleApplied)
01051 {
01052 setParagLayout( parag->paragLayout() );
01053
01054 parag->m_layout.pageBreaking &= ~
KoParagLayout::HardFrameBreakBefore;
01055 parag->m_layout.pageBreaking &= ~
KoParagLayout::HardFrameBreakAfter;
01056
01057
if ( m_layout.
counter && m_layout.
counter->
numbering() == KoParagCounter::NUM_FOOTNOTE )
01058 setNoCounter();
01059
01060
if ( m_layout.
counter )
01061 m_layout.
counter->
setRestartCounter(
false);
01062
01063
01064
setFormat( parag->at( parag->length()-1 )->format() );
01065
01066
01067 }
01068
01069
01070
01071
01072
01073 }
01074
01075
void KoTextParag::setTabList(
const KoTabulatorList &tabList )
01076 {
01077
KoTabulatorList lst( tabList );
01078 m_layout.
setTabList( lst );
01079
if ( !tabList.isEmpty() )
01080 {
01081
KoZoomHandler* zh =
textDocument()->formattingZoomHandler();
01082
int * tabs =
new int[ tabList.count() + 1 ];
01083 KoTabulatorList::Iterator it = lst.begin();
01084
unsigned int i = 0;
01085
for ( ; it != lst.end() ; ++it, ++i )
01086 tabs[i] = zh->
ptToLayoutUnitPixX( (*it).ptPos );
01087 tabs[i] = 0;
01088 assert( i == tabList.count() );
01089 setTabArray( tabs );
01090 }
else
01091 {
01092 setTabArray( 0 );
01093 }
01094 invalidate( 0 );
01095 }
01096
01098
int KoTextParag::nextTab(
int chnum,
int x )
01099 {
01100
if ( !m_layout.
tabList().isEmpty() )
01101 {
01102
01103
01104
int * tArray = tabArray();
01105
int i = 0;
01106
if ( string()->isRightToLeft() )
01107 i = m_layout.
tabList().size() - 1;
01108
01109
while ( i >= 0 && i < (
int)m_layout.
tabList().size() ) {
01110
01111
int tab = tArray[ i ];
01112
if ( string()->isRightToLeft() )
01113 tab = rect().width() - tab;
01114
01115
if ( tab > x ) {
01116
int type = m_layout.
tabList()[i].type;
01117
01118
01119
if ( string()->isRightToLeft() )
01120
if ( type == T_RIGHT )
01121 type = T_LEFT;
01122
else if ( type == T_LEFT )
01123 type = T_RIGHT;
01124
01125
switch ( type ) {
01126
case T_RIGHT:
01127
case T_CENTER:
01128 {
01129
01130
int c = chnum + 1;
01131
int w = 0;
01132
while ( c < string()->length() - 1 && string()->at( c ).c !=
'\t' && string()->at( c ).c !=
'\n' )
01133 {
01134 KoTextStringChar & ch = string()->at( c );
01135
01136
01137
if ( ch.isCustom() )
01138 w += ch.customItem()->width;
01139
else
01140 {
01141
KoTextFormat *charFormat = ch.format();
01142
int ww = charFormat->
charWidth(
textDocument()->formattingZoomHandler(),
false, &ch,
this, c );
01143 ww =
KoTextZoomHandler::ptToLayoutUnitPt( ww );
01144 w += ww;
01145 }
01146 ++c;
01147 }
01148
01149 m_tabCache[chnum] = i;
01150
01151
if ( type == T_RIGHT )
01152
return tab - w;
01153
else
01154
return tab - w/2;
01155 }
01156
case T_DEC_PNT:
01157 {
01158
01159
01160
int c = chnum + 1;
01161
int w = 0;
01162
while ( c < string()->length()-1 && string()->at( c ).c !=
'\t' && string()->at( c ).c !=
'\n' )
01163 {
01164 KoTextStringChar & ch = string()->at( c );
01165
if ( ch.c == m_layout.
tabList()[i].alignChar )
01166 {
01167
if ( string()->isRightToLeft() )
01168 {
01169 w = ch.width / 2;
01170 ++c;
01171
continue;
01172 }
01173
else
01174 {
01175 w += ch.width / 2;
01176
break;
01177 }
01178 }
01179
01180
01181
if ( ch.isCustom() )
01182 w += ch.customItem()->width;
01183
else
01184 {
01185
KoTextFormat *charFormat = ch.format();
01186
int ww = charFormat->
charWidth(
textDocument()->formattingZoomHandler(),
false, &ch,
this, c );
01187 ww =
KoTextZoomHandler::ptToLayoutUnitPt( ww );
01188 w += ww;
01189 }
01190
01191 ++c;
01192 }
01193 m_tabCache[chnum] = i;
01194
return tab - w;
01195 }
01196
default:
01197 m_tabCache[chnum] = i;
01198
return tab;
01199 }
01200 }
01201
if ( string()->isRightToLeft() )
01202 --i;
01203
else
01204 ++i;
01205 }
01206 }
01207
01208
return KoTextParag::nextTabDefault( chnum, x );
01209 }
01210
01211
void KoTextParag::applyStyle(
KoStyle *style )
01212 {
01213 setParagLayout( style->
paragLayout() );
01214
KoTextFormat *newFormat = &style->format();
01215
setFormat( 0, string()->length(), newFormat );
01216
setFormat( newFormat );
01217 }
01218
01219
void KoTextParag::setParagLayout(
const KoParagLayout & layout,
int flags )
01220 {
01221
01222
if ( flags & KoParagLayout::Alignment )
01223 setAlign( layout.
alignment );
01224
if ( flags & KoParagLayout::Margins )
01225 setMargins( layout.
margins );
01226
if ( flags & KoParagLayout::LineSpacing )
01227 {
01228 setLineSpacingType( layout.
lineSpacingType );
01229 setLineSpacing( layout.
lineSpacingValue() );
01230 }
01231
if ( flags & KoParagLayout::Borders )
01232 {
01233 setLeftBorder( layout.
leftBorder );
01234 setRightBorder( layout.
rightBorder );
01235 setTopBorder( layout.
topBorder );
01236 setBottomBorder( layout.
bottomBorder );
01237 }
01238
if ( flags & KoParagLayout::BulletNumber )
01239 setCounter( layout.
counter );
01240
if ( flags & KoParagLayout::Tabulator )
01241 setTabList( layout.
tabList() );
01242
if ( flags == KoParagLayout::All )
01243 {
01244 setDirection( static_cast<QChar::Direction>(layout.
direction) );
01245
01246 setStyle( layout.
style );
01247 }
01248 }
01249
01250
void KoTextParag::setCustomItem(
int index, KoTextCustomItem * custom,
KoTextFormat * currentFormat )
01251 {
01252
01253
01254
if ( currentFormat )
01255
setFormat( index, 1, currentFormat );
01256 at( index )->setCustomItem( custom );
01257
01258 document()->registerCustomItem( custom,
this );
01259 custom->recalc();
01260 invalidate( 0 );
01261 setChanged(
true );
01262 }
01263
01264
void KoTextParag::removeCustomItem(
int index )
01265 {
01266 Q_ASSERT( at( index )->isCustom() );
01267 KoTextCustomItem * item = at( index )->customItem();
01268 at( index )->loseCustomItem();
01269
01270 document()->unregisterCustomItem( item,
this );
01271 }
01272
01273
01274
int KoTextParag::findCustomItem(
const KoTextCustomItem * custom )
const
01275
{
01276
int len = string()->length();
01277
for (
int i = 0; i < len; ++i )
01278 {
01279 KoTextStringChar & ch = string()->at(i);
01280
if ( ch.isCustom() && ch.customItem() == custom )
01281
return i;
01282 }
01283 kdWarning() <<
"KoTextParag::findCustomItem custom item " << (
void*)custom
01284 <<
" not found in paragraph " << paragId() << endl;
01285
return 0;
01286 }
01287
01288
#ifndef NDEBUG
01289
void KoTextParag::printRTDebug(
int info )
01290 {
01291 kdDebug(32500) <<
"Paragraph " <<
this <<
" (" << paragId() <<
") [changed="
01292 << hasChanged() <<
", valid=" << isValid()
01293 <<
", needsSpellCheck=" << string()->needsSpellCheck()
01294 <<
", wasMovedDown=" << wasMovedDown()
01295
01296 <<
"] ------------------ " << endl;
01297
if ( prev() && prev()->paragId() + 1 != paragId() )
01298 kdWarning() <<
" Previous paragraph " << prev() <<
" has ID " << prev()->paragId() << endl;
01299
if ( next() && next()->paragId() != paragId() + 1 )
01300 kdWarning() <<
" Next paragraph " << next() <<
" has ID " << next()->paragId() << endl;
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314 kdDebug(32500) <<
" Style: " << style() <<
" " << ( style() ? style()->name().local8Bit().data() : "NO STYLE" ) << endl;
01315 kdDebug(32500) <<
" Text: '" << string()->toString() <<
"'" << endl;
01316
if ( info == 0 )
01317 {
01318
if ( m_layout.
counter )
01319 {
01320
QString additionalInfo;
01321
if ( m_layout.
counter->
restartCounter() )
01322 additionalInfo =
"[restartCounter]";
01323
static const char *
const s_numbering[] = {
"List",
"Chapter",
"None",
"Footnote" };
01324 kdDebug(32500) <<
" Counter style=" << m_layout.
counter->
style()
01325 <<
" numbering=" << s_numbering[ m_layout.
counter->
numbering() ]
01326 <<
" depth=" << m_layout.
counter->
depth()
01327 <<
" number=" << m_layout.
counter->
number(
this )
01328 <<
" text='" << m_layout.
counter->
text(
this ) <<
"'"
01329 <<
" width=" << m_layout.
counter->
width(
this )
01330 << additionalInfo << endl;
01331 }
01332
static const char *
const s_align[] = {
"Auto",
"Left",
"Right",
"ERROR",
"HCenter",
"ERR",
"ERR",
"ERR",
"Justify", };
01333
static const char *
const s_linespacing[] = {
"Single",
"1.5",
"2",
"custom",
"atLeast",
"Multiple",
"Fixed" };
01334
static const char *
const s_dir[] = {
"DirL",
"DirR",
"DirEN",
"DirES",
"DirET",
"DirAN",
"DirCS",
"DirB",
"DirS",
"DirWS",
"DirON",
"DirLRE",
"DirLRO",
"DirAL",
"DirRLE",
"DirRLO",
"DirPDF",
"DirNSM",
"DirBN" };
01335 kdDebug(32500) <<
" align: " << s_align[alignment()] <<
" resolveAlignment: " << s_align[resolveAlignment()]
01336 <<
" isRTL:" << string()->isRightToLeft()
01337 <<
" dir: " << s_dir[direction()] << endl;
01338
QRect pixr = pixelRect(
textDocument()->paintingZoomHandler() );
01339 kdDebug(32500) <<
" rect() : " << DEBUGRECT( rect() )
01340 <<
" pixelRect() : " << DEBUGRECT( pixr ) << endl;
01341 kdDebug(32500) <<
" topMargin()=" << topMargin() <<
" bottomMargin()=" << bottomMargin()
01342 <<
" leftMargin()=" << leftMargin() <<
" firstLineMargin()=" << firstLineMargin()
01343 <<
" rightMargin()=" << rightMargin() << endl;
01344
if ( kwLineSpacingType() != KoParagLayout::LS_SINGLE )
01345 kdDebug(32500) <<
" linespacing type=" << s_linespacing[ -kwLineSpacingType() ]
01346 <<
" value=" << kwLineSpacing() << endl;
01347
01348
static const char *
const tabtype[] = {
"T_LEFT",
"T_CENTER",
"T_RIGHT",
"T_DEC_PNT",
"error!!!" };
01349
KoTabulatorList tabList = m_layout.
tabList();
01350
if ( tabList.isEmpty() ) {
01351
if ( string()->toString().find(
'\t' ) != -1 )
01352 kdDebug(32500) <<
"Tab width: " <<
textDocument()->tabStopWidth() << endl;
01353 }
else {
01354 KoTabulatorList::Iterator it = tabList.begin();
01355
for ( ; it != tabList.end() ; it++ )
01356 kdDebug(32500) <<
"Tab type:" << tabtype[(*it).type] <<
" at: " << (*it).ptPos << endl;
01357 }
01358 }
else if ( info == 1 )
01359 {
01360 kdDebug(32500) <<
" Paragraph format=" << paragFormat() <<
" " << paragFormat()->key()
01361 <<
" fontsize:" << dynamic_cast<KoTextFormat *>(paragFormat())->pointSize() << endl;
01362
01363
for (
int line = 0 ; line < lines(); ++ line ) {
01364
int y, h, baseLine;
01365 lineInfo( line, y, h, baseLine );
01366
int startOfLine;
01367 lineStartOfLine( line, &startOfLine );
01368 kdDebug(32500) <<
" Line " << line <<
" y=" << y <<
" height=" << h <<
" baseLine=" << baseLine <<
" startOfLine(index)=" << startOfLine << endl;
01369 }
01370 kdDebug(32500) << endl;
01371 KoTextString * s = string();
01372
int lastX = 0;
01373
int lastW = 0;
01374
for (
int i = 0 ; i < s->length() ; ++i )
01375 {
01376 KoTextStringChar & ch = s->at(i);
01377
int pixelx =
textDocument()->formattingZoomHandler()->layoutUnitToPixelX( ch.x )
01378 + ch.pixelxadj;
01379
if ( ch.lineStart )
01380 kdDebug(32500) <<
"LINESTART" << endl;
01381 kdDebug(32500) << i <<
": '" <<
QString(ch.c) <<
"' (" << ch.c.unicode() <<
")"
01382 <<
" x(LU)=" << ch.x
01383 <<
" w(LU)=" << ch.width
01384 <<
" x(PIX)=" << pixelx
01385 <<
" (xadj=" << + ch.pixelxadj <<
")"
01386 <<
" w(PIX)=" << ch.pixelwidth
01387 <<
" height=" << ch.height()
01388
01389 <<
" \"" << ch.format()->key() <<
"\" "
01390
01391 << endl;
01392
01393
01394
if ( ch.format() !=
textDocument()->formatCollection()->defaultFormat() )
01395 Q_ASSERT(
textDocument()->formatCollection()->dict()[ch.format()->key()] );
01396
01397
if ( !string()->isBidi() && !ch.lineStart )
01398 Q_ASSERT( lastX + lastW == pixelx );
01399 lastX = pixelx;
01400 lastW = ch.pixelwidth;
01401
if ( ch.isCustom() )
01402 {
01403 KoTextCustomItem * item = ch.customItem();
01404 kdDebug(32500) <<
" - custom item " << item
01405 <<
" ownline=" << item->ownLine()
01406 <<
" size=" << item->width <<
"x" << item->height
01407 << endl;
01408 }
01409 }
01410 }
01411 }
01412
#endif
01413
01414
void KoTextParag::drawFontEffects(
QPainter * p,
KoTextFormat *format,
KoZoomHandler *zh,
QFont font,
const QColor & color,
int startX,
int baseLine,
int bw,
int lastY,
int ,
QChar firstChar )
01415 {
01416
01417
01418
if ( !format->
isStrikedOrUnderlined() )
01419
return;
01420
01421
01422
01423
if ( format->
wordByWord() && firstChar.isSpace() )
01424
return;
01425
01426
double dimd;
01427
int y;
01428
int offset = 0;
01429
if (format->
vAlign() == KoTextFormat::AlignSubScript )
01430 offset = p->fontMetrics().height() / 6;
01431
else if (format->
vAlign() == KoTextFormat::AlignSuperScript )
01432 offset = -p->fontMetrics().height() / 2;
01433
01434 dimd = KoBorder::zoomWidthY( format->
underLineWidth(), zh, 1 );
01435
if((format->
vAlign() == KoTextFormat::AlignSuperScript) ||
01436 (format->
vAlign() == KoTextFormat::AlignSubScript ))
01437 dimd*=format->
relativeTextSize();
01438 y = lastY + baseLine + offset - format->
offsetFromBaseLine();
01439
01440
if ( format->
doubleUnderline())
01441 {
01442
QColor col = format->
textUnderlineColor().isValid() ? format->
textUnderlineColor(): color ;
01443
int dim=static_cast<int>(0.75*dimd);
01444 dim=dim?dim:1;
01445 p->save();
01446
01447
switch( format->
underlineStyle())
01448 {
01449
case KoTextFormat::U_SOLID:
01450 p->setPen(
QPen( col, dim, Qt::SolidLine ) );
01451
break;
01452
case KoTextFormat::U_DASH:
01453 p->setPen(
QPen( col, dim, Qt::DashLine ) );
01454
break;
01455
case KoTextFormat::U_DOT:
01456 p->setPen(
QPen( col, dim, Qt::DotLine ) );
01457
break;
01458
case KoTextFormat::U_DASH_DOT:
01459 p->setPen(
QPen( col, dim, Qt::DashDotLine ) );
01460
break;
01461
case KoTextFormat::U_DASH_DOT_DOT:
01462 p->setPen(
QPen( col, dim, Qt::DashDotDotLine ) );
01463
break;
01464
default:
01465 p->setPen(
QPen( color, dim, Qt::SolidLine ) );
01466 }
01467
01468 y += static_cast<int>(1.125*dimd);
01469 p->drawLine( startX, y, startX + bw, y );
01470 y += static_cast<int>(1.5*dimd);
01471 p->drawLine( startX, y, startX + bw, y );
01472 p->restore();
01473
if ( font.underline() ) {
01474 font.setUnderline( FALSE );
01475 p->setFont( font );
01476 }
01477 }
01478
else if ( format->
underline() ||
01479 format->
underlineType() == KoTextFormat::U_SIMPLE_BOLD)
01480 {
01481
01482
QColor col = format->
textUnderlineColor().isValid() ? format->
textUnderlineColor(): color ;
01483 p->save();
01484
int dim=(format->
underlineType() == KoTextFormat::U_SIMPLE_BOLD)?static_cast<int>(2*dimd):static_cast<int>(dimd);
01485 dim=dim?dim:1;
01486 y += static_cast<int>(1.875*dimd);
01487
01488
switch( format->
underlineStyle() )
01489 {
01490
case KoTextFormat::U_SOLID:
01491 p->setPen(
QPen( col, dim, Qt::SolidLine ) );
01492
break;
01493
case KoTextFormat::U_DASH:
01494 p->setPen(
QPen( col, dim, Qt::DashLine ) );
01495
break;
01496
case KoTextFormat::U_DOT:
01497 p->setPen(
QPen( col, dim, Qt::DotLine ) );
01498
break;
01499
case KoTextFormat::U_DASH_DOT:
01500 p->setPen(
QPen( col, dim, Qt::DashDotLine ) );
01501
break;
01502
case KoTextFormat::U_DASH_DOT_DOT:
01503 p->setPen(
QPen( col, dim, Qt::DashDotDotLine ) );
01504
break;
01505
default:
01506 p->setPen(
QPen( col, dim, Qt::SolidLine ) );
01507 }
01508
01509 p->drawLine( startX, y, startX + bw, y );
01510 p->restore();
01511 font.setUnderline( FALSE );
01512 p->setFont( font );
01513 }
01514
else if ( format->
waveUnderline() )
01515 {
01516
int dim=static_cast<int>(dimd);
01517 dim=dim?dim:1;
01518 y += dim;
01519
QColor col = format->
textUnderlineColor().isValid() ? format->
textUnderlineColor(): color ;
01520 p->save();
01521
int offset = 2 * dim;
01522
QPen pen(col, dim, Qt::SolidLine);
01523 pen.setCapStyle(Qt::RoundCap);
01524 p->setPen(pen);
01525 Q_ASSERT(offset);
01526
double anc=acos(1.0-2*(static_cast<double>(offset-(startX)%offset)/static_cast<double>(offset)))/3.1415*180;
01527
int pos=1;
01528
01529
if(2*((startX/offset)/2)==startX/offset)
01530 pos*=-1;
01531
01532 p->drawArc( (startX/offset)*offset, y, offset, offset, 0, -qRound(pos*anc*16) );
01533
01534
int zigzag_x = (startX/offset+1)*offset;
01535
for ( ; zigzag_x + offset <= bw+startX; zigzag_x += offset)
01536 {
01537 p->drawArc( zigzag_x, y, offset, offset, 0, pos*180*16 );
01538 pos*=-1;
01539 }
01540
01541 anc=acos(1.0-2*(static_cast<double>((startX+bw)%offset)/static_cast<double>(offset)))/3.1415*180;
01542 p->drawArc( zigzag_x, y, offset, offset, 180*16, -qRound(pos*anc*16) );
01543 p->restore();
01544 font.setUnderline( FALSE );
01545 p->setFont( font );
01546 }
01547
01548 dimd = KoBorder::zoomWidthY( static_cast<double>(format->
pointSize())/18.0, zh, 1 );
01549
if((format->
vAlign() == KoTextFormat::AlignSuperScript) ||
01550 (format->
vAlign() == KoTextFormat::AlignSubScript ))
01551 dimd*=format->
relativeTextSize();
01552 y = lastY + baseLine + offset - format->
offsetFromBaseLine();
01553
01554
if ( format->
strikeOutType() == KoTextFormat::S_SIMPLE
01555 || format->
strikeOutType() == KoTextFormat::S_SIMPLE_BOLD)
01556 {
01557
unsigned int dim = (format->
strikeOutType() == KoTextFormat::S_SIMPLE_BOLD)? static_cast<int>(2*dimd) : static_cast<int>(dimd);
01558 p->save();
01559
01560
switch( format->
strikeOutStyle() )
01561 {
01562
case KoTextFormat::S_SOLID:
01563 p->setPen(
QPen( color, dim, Qt::SolidLine ) );
01564
break;
01565
case KoTextFormat::S_DASH:
01566 p->setPen(
QPen( color, dim, Qt::DashLine ) );
01567
break;
01568
case KoTextFormat::S_DOT:
01569 p->setPen(
QPen( color, dim, Qt::DotLine ) );
01570
break;
01571
case KoTextFormat::S_DASH_DOT:
01572 p->setPen(
QPen( color, dim, Qt::DashDotLine ) );
01573
break;
01574
case KoTextFormat::S_DASH_DOT_DOT:
01575 p->setPen(
QPen( color, dim, Qt::DashDotDotLine ) );
01576
break;
01577
default:
01578 p->setPen(
QPen( color, dim, Qt::SolidLine ) );
01579 }
01580
01581 y -= static_cast<int>(5*dimd);
01582 p->drawLine( startX, y, startX + bw, y );
01583 p->restore();
01584 font.setStrikeOut( FALSE );
01585 p->setFont( font );
01586 }
01587
else if ( format->
strikeOutType() == KoTextFormat::S_DOUBLE )
01588 {
01589
unsigned int dim = static_cast<int>(dimd);
01590 p->save();
01591
01592
switch( format->
strikeOutStyle() )
01593 {
01594
case KoTextFormat::S_SOLID:
01595 p->setPen(
QPen( color, dim, Qt::SolidLine ) );
01596
break;
01597
case KoTextFormat::S_DASH:
01598 p->setPen(
QPen( color, dim, Qt::DashLine ) );
01599
break;
01600
case KoTextFormat::S_DOT:
01601 p->setPen(
QPen( color, dim, Qt::DotLine ) );
01602
break;
01603
case KoTextFormat::S_DASH_DOT:
01604 p->setPen(
QPen( color, dim, Qt::DashDotLine ) );
01605
break;
01606
case KoTextFormat::S_DASH_DOT_DOT:
01607 p->setPen(
QPen( color, dim, Qt::DashDotDotLine ) );
01608
break;
01609
default:
01610 p->setPen(
QPen( color, dim, Qt::SolidLine ) );
01611 }
01612
01613 y -= static_cast<int>(4*dimd);
01614 p->drawLine( startX, y, startX + bw, y);
01615 y -= static_cast<int>(2*dimd);
01616 p->drawLine( startX, y, startX + bw, y);
01617 p->restore();
01618 font.setStrikeOut( FALSE );
01619 p->setFont( font );
01620 }
01621
01622 }
01623
01624
01625 QString KoTextParag::toString(
int from,
int length )
const
01626
{
01627 QString str;
01628
if ( from == 0 && m_layout.
counter )
01629 str += m_layout.
counter->
text(
this ) +
' ';
01630
if ( length == -1 )
01631 length = this->length() - from;
01632
for (
int i = from ; i < (length+from) ; ++i )
01633 {
01634 KoTextStringChar *ch = at( i );
01635
if ( ch->isCustom() )
01636 {
01637
KoVariable * var = dynamic_cast<KoVariable *>(ch->customItem());
01638
if ( var )
01639 str += var->
text(
true);
01640
else
01641 str +=
' ';
01642 }
01643
else
01644 str += ch->c;
01645 }
01646
return str;
01647 }
01648
01649
int KoTextParag::documentWidth()
const
01650
{
01651
return doc ? doc->width() : 0;
01652 }
01653
01654
01655
01656
01657
01658
01659
int KoTextParag::documentX()
const
01660
{
01661
return doc ? doc->x() : 0;
01662 }
01663
01664
int KoTextParag::documentY()
const
01665
{
01666
return doc ? doc->y() : 0;
01667 }
01668
01669
void KoTextParag::fixParagWidth(
bool viewFormattingChars )
01670 {
01671
01672
if ( viewFormattingChars && lineStartList().count() == 1 )
01673 {
01674
KoTextFormat * lastFormat = at( length() - 1 )->format();
01675 setWidth( QMIN( rect().width() + lastFormat->
width(
'x'), doc->width() ) );
01676 }
01677
01678 }
01679
01680
01681
void KoTextParag::drawFormattingChars(
QPainter &painter,
int start,
int len,
01682
int lastY_pix,
int baseLine_pix,
int h_pix,
01683
bool ,
01684
KoTextFormat * ,
const QMemArray<int> &,
01685
const QMemArray<int> &,
const QColorGroup &cg,
01686
bool rightToLeft,
int ,
KoZoomHandler* zh,
01687
int whichFormattingChars )
01688 {
01689
if ( !whichFormattingChars )
01690
return;
01691 painter.save();
01692
QPen pen( cg.color( QColorGroup::Highlight ) );
01693 painter.setPen( pen );
01694
01695
if ( start + len == length() && ( whichFormattingChars & FormattingEndParag ) )
01696 {
01697
01698 KoTextStringChar &ch = string()->at( length() - 1 );
01699
KoTextFormat* format = static_cast<KoTextFormat *>( ch.format() );
01700
int w = format->
charWidth( zh,
true, &ch,
this,
'X' );
01701
int size = QMIN( w, h_pix * 3 / 4 );
01702
01703
01704
int x;
01705
if ( rightToLeft )
01706 x = zh->
layoutUnitToPixelX( ch.x ) + ch.pixelwidth - 1;
01707
else
01708 x = zh->
layoutUnitToPixelX( ch.x ) + w;
01709
int y = lastY_pix + baseLine_pix;
01710
01711 painter.drawLine( (
int)(x - size * 0.2), y - size, (
int)(x - size * 0.2), y );
01712 painter.drawLine( (
int)(x - size * 0.5), y - size, (
int)(x - size * 0.5), y );
01713 painter.drawLine( x, y, (
int)(x - size * 0.7), y );
01714 painter.drawLine( x, y - size, (
int)(x - size * 0.5), y - size);
01715 painter.drawArc( x - size, y - size, size, (
int)(size / 2), -90*16, -180*16 );
01716
#ifdef DEBUG_FORMATTING
01717
painter.setPen( Qt::blue );
01718 painter.drawRect( zh->
layoutUnitToPixelX( ch.x ) - 1, lastY_pix, ch.pixelwidth, baseLine_pix );
01719
QPen pen( cg.color( QColorGroup::Highlight ) );
01720 painter.setPen( pen );
01721
#endif
01722
}
01723
01724
01725
if ( (whichFormattingChars & FormattingSpace) ||
01726 (whichFormattingChars & FormattingTabs) ||
01727 (whichFormattingChars & FormattingBreak) )
01728 {
01729
int end = QMIN( start + len, length() - 1 );
01730
for (
int i = start ; i < end ; ++i )
01731 {
01732 KoTextStringChar &ch = string()->at(i);
01733
#ifdef DEBUG_FORMATTING
01734
painter.setPen( (i % 2)? Qt::red: Qt::green );
01735 painter.drawRect( zh->
layoutUnitToPixelX( ch.x ) - 1, lastY_pix, ch.pixelwidth, baseLine_pix );
01736
QPen pen( cg.color( QColorGroup::Highlight ) );
01737 painter.setPen( pen );
01738
#endif
01739
if ( ch.isCustom() )
01740
continue;
01741
if ( (ch.c ==
' ' || ch.c.unicode() == 0x00a0U)
01742 && (whichFormattingChars & FormattingSpace))
01743 {
01744
01745
01746
int w = zh->
layoutUnitToPixelX( ch.format()->width(
' ' ) );
01747
int height = zh->
layoutUnitToPixelY( ch.ascent() );
01748
int size = QMAX( 2, QMIN( w/2, height/3 ) );
01749
int x = zh->
layoutUnitToPixelX( ch.x );
01750
QRect spcRect( x + (ch.pixelwidth - size) / 2, lastY_pix + baseLine_pix - (height - size) / 2, size, size );
01751
if ( ch.c ==
' ' )
01752 painter.drawRect( spcRect );
01753
else
01754 painter.fillRect( spcRect, pen.color() );
01755 }
01756
else if ( ch.c ==
'\t' && (whichFormattingChars & FormattingTabs) )
01757 {
01758
01759
01760
01761
01762
01763
01764
01765
int availWidth = ch.pixelwidth;
01766
01767
KoTextFormat* format = ch.format();
01768
int x = zh->
layoutUnitToPixelX( ch.x ) + availWidth / 2;
01769
int charWidth = format->
screenFontMetrics( zh ).width(
'W' );
01770
int size = QMIN( availWidth, charWidth ) / 2 ;
01771
int y = lastY_pix + baseLine_pix - zh->
layoutUnitToPixelY( ch.ascent()/2 );
01772
int arrowsize = zh->
zoomItY( 2 );
01773 painter.drawLine( x - size, y, x + size, y );
01774
if ( rightToLeft )
01775 {
01776 painter.drawLine( x - size, y, x - size + arrowsize, y - arrowsize );
01777 painter.drawLine( x - size, y, x - size + arrowsize, y + arrowsize );
01778 }
01779
else
01780 {
01781 painter.drawLine( x + size, y, x + size - arrowsize, y - arrowsize );
01782 painter.drawLine( x + size, y, x + size - arrowsize, y + arrowsize );
01783 }
01784 }
01785
else if ( ch.c ==
'\n' && (whichFormattingChars & FormattingBreak) )
01786 {
01787
01788
KoTextFormat* format = static_cast<KoTextFormat *>( ch.format() );
01789
int w = format->
charWidth( zh,
true, &ch,
this,
'X' );
01790
int size = QMIN( w, h_pix * 3 / 4 );
01791
int arrowsize = zh->
zoomItY( 2 );
01792
01793
01794
int y = lastY_pix + baseLine_pix - arrowsize;
01795
01796
if ( rightToLeft )
01797 {
01798
int x = zh->
layoutUnitToPixelX( ch.x ) + ch.pixelwidth - 1;
01799 painter.drawLine( x - size, y - size, x - size, y );
01800 painter.drawLine( x - size, y, (
int)(x - size * 0.3), y );
01801
01802 painter.drawLine( (
int)(x - size * 0.3), y, (
int)(x - size * 0.3 - arrowsize), y - arrowsize );
01803 painter.drawLine( (
int)(x - size * 0.3), y, (
int)(x - size * 0.3 - arrowsize), y + arrowsize );
01804 }
01805
else
01806 {
01807
int x = zh->
layoutUnitToPixelX( ch.x ) + w - 1;
01808 painter.drawLine( x, y - size, x, y );
01809 painter.drawLine( x, y, (
int)(x - size * 0.7), y );
01810
01811 painter.drawLine( (
int)(x - size * 0.7), y, (
int)(x - size * 0.7 + arrowsize), y - arrowsize );
01812 painter.drawLine( (
int)(x - size * 0.7), y, (
int)(x - size * 0.7 + arrowsize), y + arrowsize );
01813 }
01814 }
01815 }
01816 painter.restore();
01817 }
01818 }