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