00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
#include "korichtext.h"
00037
#include "kotextformat.h"
00038
00039
#include <qpaintdevicemetrics.h>
00040
#include "qdrawutil.h"
00041
00042
#include <stdlib.h>
00043
#include "koparagcounter.h"
00044
#include "kotextdocument.h"
00045
#include <kdebug.h>
00046
#include <kdeversion.h>
00047
#if ! KDE_IS_VERSION(3,1,90)
00048
#include <kdebugclasses.h>
00049
#endif
00050
#include <kglobal.h>
00051
#include <klocale.h>
00052
#include <private/qtextengine_p.h>
00053
00054
00055
00056
00057
00058
00059
00060
#if defined(PARSER_DEBUG)
00061
static QString debug_indent;
00062
#endif
00063
00064
static bool is_printer(
QPainter *p )
00065 {
00066
return p && p->device() && p->device()->devType() == QInternal::Printer;
00067 }
00068
00069
static inline int scale(
int value,
QPainter *painter )
00070 {
00071
if ( is_printer( painter ) ) {
00072
QPaintDeviceMetrics metrics( painter->device() );
00073
#if defined(Q_WS_X11)
00074
value = value * metrics.logicalDpiY() / QPaintDevice::x11AppDpiY();
00075
#elif defined (Q_WS_WIN)
00076
int gdc = GetDeviceCaps( GetDC( 0 ), LOGPIXELSY );
00077
if ( gdc )
00078 value = value * metrics.logicalDpiY() / gdc;
00079
#elif defined (Q_WS_MAC)
00080
value = value * metrics.logicalDpiY() / 75;
00081
#elif defined (Q_WS_QWS)
00082
value = value * metrics.logicalDpiY() / 75;
00083
#endif
00084
}
00085
return value;
00086 }
00087
00088
00089
00090
void KoTextDocCommandHistory::addCommand( KoTextDocCommand *cmd )
00091 {
00092
if ( current < (
int)history.count() - 1 ) {
00093
QPtrList<KoTextDocCommand> commands;
00094 commands.setAutoDelete( FALSE );
00095
00096
for(
int i = 0; i <= current; ++i ) {
00097 commands.insert( i, history.at( 0 ) );
00098 history.take( 0 );
00099 }
00100
00101 commands.append( cmd );
00102 history.clear();
00103 history = commands;
00104 history.setAutoDelete( TRUE );
00105 }
else {
00106 history.append( cmd );
00107 }
00108
00109
if ( (
int)history.count() > steps )
00110 history.removeFirst();
00111
else
00112 ++current;
00113 }
00114
00115 KoTextCursor *KoTextDocCommandHistory::undo( KoTextCursor *c )
00116 {
00117
if ( current > -1 ) {
00118 KoTextCursor *c2 = history.at( current )->unexecute( c );
00119 --current;
00120
return c2;
00121 }
00122
return 0;
00123 }
00124
00125 KoTextCursor *KoTextDocCommandHistory::redo( KoTextCursor *c )
00126 {
00127
if ( current > -1 ) {
00128
if ( current < (
int)history.count() - 1 ) {
00129 ++current;
00130
return history.at( current )->execute( c );
00131 }
00132 }
else {
00133
if ( history.count() > 0 ) {
00134 ++current;
00135
return history.at( current )->execute( c );
00136 }
00137 }
00138
return 0;
00139 }
00140
00141
bool KoTextDocCommandHistory::isUndoAvailable()
00142 {
00143
return current > -1;
00144 }
00145
00146
bool KoTextDocCommandHistory::isRedoAvailable()
00147 {
00148
return current > -1 && current < (
int)history.count() - 1 || current == -1 && history.count() > 0;
00149 }
00150
00151
00152
00153 KoTextDocDeleteCommand::KoTextDocDeleteCommand( KoTextDocument *d,
int i,
int idx,
const QMemArray<KoTextStringChar> &str )
00154 : KoTextDocCommand( d ), id( i ), index( idx ), parag( 0 ), text( str )
00155 {
00156
for (
int j = 0; j < (
int)text.size(); ++j ) {
00157
if ( text[ j ].format() )
00158 text[ j ].format()->addRef();
00159 }
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171 KoTextDocDeleteCommand::~KoTextDocDeleteCommand()
00172 {
00173
for (
int i = 0; i < (
int)text.size(); ++i ) {
00174
if ( text[ i ].format() )
00175 text[ i ].format()->removeRef();
00176 }
00177 text.resize( 0 );
00178 }
00179
00180 KoTextCursor *KoTextDocDeleteCommand::execute( KoTextCursor *c )
00181 {
00182 KoTextParag *s = doc ? doc->paragAt(
id ) : parag;
00183
if ( !s ) {
00184 kdWarning(32500) <<
"can't locate parag at " <<
id <<
", last parag: " << doc->lastParag()->paragId() << endl;
00185
return 0;
00186 }
00187
00188 cursor.setParag( s );
00189 cursor.setIndex( index );
00190
int len = text.size();
00191
if ( c )
00192 *c = cursor;
00193
if ( doc ) {
00194 doc->setSelectionStart( KoTextDocument::Temp, &cursor );
00195
for (
int i = 0; i < len; ++i )
00196 cursor.gotoNextLetter();
00197 doc->setSelectionEnd( KoTextDocument::Temp, &cursor );
00198 doc->removeSelectedText( KoTextDocument::Temp, &cursor );
00199
if ( c )
00200 *c = cursor;
00201 }
else {
00202 s->remove( index, len );
00203 }
00204
00205
return c;
00206 }
00207
00208 KoTextCursor *KoTextDocDeleteCommand::unexecute( KoTextCursor *c )
00209 {
00210 KoTextParag *s = doc ? doc->paragAt(
id ) : parag;
00211
if ( !s ) {
00212 kdWarning(32500) <<
"can't locate parag at " <<
id <<
", last parag: " << doc->lastParag()->paragId() << endl;
00213
return 0;
00214 }
00215
00216 cursor.setParag( s );
00217 cursor.setIndex( index );
00218
QString str = KoTextString::toString( text );
00219 cursor.insert( str, TRUE, &text );
00220 cursor.setParag( s );
00221 cursor.setIndex( index );
00222
if ( c ) {
00223 c->setParag( s );
00224 c->setIndex( index );
00225
for (
int i = 0; i < (
int)text.size(); ++i )
00226 c->gotoNextLetter();
00227 }
00228
00229 s = cursor.parag();
00230
while ( s ) {
00231 s->format();
00232 s->setChanged( TRUE );
00233
if ( s == c->parag() )
00234
break;
00235 s = s->next();
00236 }
00237
00238
return &cursor;
00239 }
00240
00241 KoTextDocFormatCommand::KoTextDocFormatCommand( KoTextDocument *d,
int sid,
int sidx,
int eid,
int eidx,
00242
const QMemArray<KoTextStringChar> &old,
const KoTextFormat *f,
int fl )
00243 : KoTextDocCommand( d ), startId( sid ), startIndex( sidx ), endId( eid ), endIndex( eidx ), oldFormats( old ), flags( fl )
00244 {
00245 format = d->formatCollection()->format( f );
00246
for (
int j = 0; j < (
int)oldFormats.size(); ++j ) {
00247
if ( oldFormats[ j ].format() )
00248 oldFormats[ j ].format()->addRef();
00249 }
00250 }
00251
00252 KoTextDocFormatCommand::~KoTextDocFormatCommand()
00253 {
00254 format->
removeRef();
00255
for (
int j = 0; j < (
int)oldFormats.size(); ++j ) {
00256
if ( oldFormats[ j ].format() )
00257 oldFormats[ j ].format()->removeRef();
00258 }
00259 }
00260
00261 KoTextCursor *KoTextDocFormatCommand::execute( KoTextCursor *c )
00262 {
00263 KoTextParag *sp = doc->paragAt( startId );
00264 KoTextParag *ep = doc->paragAt( endId );
00265
if ( !sp || !ep )
00266
return c;
00267
00268 KoTextCursor start( doc );
00269 start.setParag( sp );
00270 start.setIndex( startIndex );
00271 KoTextCursor end( doc );
00272 end.setParag( ep );
00273 end.setIndex( endIndex );
00274
00275 doc->setSelectionStart( KoTextDocument::Temp, &start );
00276 doc->setSelectionEnd( KoTextDocument::Temp, &end );
00277 doc->setFormat( KoTextDocument::Temp, format, flags );
00278 doc->removeSelection( KoTextDocument::Temp );
00279
if ( endIndex == ep->length() )
00280 end.gotoLeft();
00281 *c = end;
00282
return c;
00283 }
00284
00285 KoTextCursor *KoTextDocFormatCommand::unexecute( KoTextCursor *c )
00286 {
00287 KoTextParag *sp = doc->paragAt( startId );
00288 KoTextParag *ep = doc->paragAt( endId );
00289
if ( !sp || !ep )
00290
return 0;
00291
00292
int idx = startIndex;
00293
int fIndex = 0;
00294
if( !oldFormats.isEmpty())
00295 {
00296
for ( ;; ) {
00297
if ( oldFormats.at( fIndex ).c ==
'\n' ) {
00298
if ( idx > 0 ) {
00299
if ( idx < sp->length() && fIndex > 0 )
00300 sp->setFormat( idx, 1, oldFormats.at( fIndex - 1 ).format() );
00301
if ( sp == ep )
00302
break;
00303 sp = sp->next();
00304 idx = 0;
00305 }
00306 fIndex++;
00307 }
00308
if ( oldFormats.at( fIndex ).format() )
00309 sp->setFormat( idx, 1, oldFormats.at( fIndex ).format() );
00310 idx++;
00311 fIndex++;
00312
if ( fIndex >= (
int)oldFormats.size() )
00313
break;
00314
if ( idx >= sp->length() ) {
00315
if ( sp == ep )
00316
break;
00317 sp = sp->next();
00318 idx = 0;
00319 }
00320 }
00321 }
00322 KoTextCursor end( doc );
00323 end.setParag( ep );
00324 end.setIndex( endIndex );
00325
if ( endIndex == ep->length() )
00326 end.gotoLeft();
00327 *c = end;
00328
return c;
00329 }
00330
00331 KoTextAlignmentCommand::KoTextAlignmentCommand( KoTextDocument *d,
int fParag,
int lParag,
int na,
const QMemArray<int> &oa )
00332 : KoTextDocCommand( d ), firstParag( fParag ), lastParag( lParag ), newAlign( na ), oldAligns( oa )
00333 {
00334 }
00335
00336 KoTextCursor *KoTextAlignmentCommand::execute( KoTextCursor *c )
00337 {
00338 KoTextParag *p = doc->paragAt( firstParag );
00339
if ( !p )
00340
return c;
00341
while ( p ) {
00342 p->setAlignment( newAlign );
00343
if ( p->paragId() == lastParag )
00344
break;
00345 p = p->next();
00346 }
00347
return c;
00348 }
00349
00350 KoTextCursor *KoTextAlignmentCommand::unexecute( KoTextCursor *c )
00351 {
00352 KoTextParag *p = doc->paragAt( firstParag );
00353
if ( !p )
00354
return c;
00355
int i = 0;
00356
while ( p ) {
00357
if ( i < (
int)oldAligns.size() )
00358 p->setAlignment( oldAligns.at( i ) );
00359
if ( p->paragId() == lastParag )
00360
break;
00361 p = p->next();
00362 ++i;
00363 }
00364
return c;
00365 }
00366
00367
00368
00369
00370 KoTextCursor::KoTextCursor( KoTextDocument *d )
00371 : doc( d ), ox( 0 ), oy( 0 )
00372 {
00373 nested = FALSE;
00374 idx = 0;
00375 string = doc ? doc->firstParag() : 0;
00376 tmpIndex = -1;
00377 }
00378
00379 KoTextCursor::KoTextCursor()
00380 {
00381 }
00382
00383 KoTextCursor::KoTextCursor(
const KoTextCursor &c )
00384 {
00385 doc = c.doc;
00386 ox = c.ox;
00387 oy = c.oy;
00388 nested = c.nested;
00389 idx = c.idx;
00390 string = c.string;
00391 tmpIndex = c.tmpIndex;
00392 indices = c.indices;
00393 parags = c.parags;
00394 xOffsets = c.xOffsets;
00395 yOffsets = c.yOffsets;
00396 }
00397
00398 KoTextCursor &KoTextCursor::operator=(
const KoTextCursor &c )
00399 {
00400 doc = c.doc;
00401 ox = c.ox;
00402 oy = c.oy;
00403 nested = c.nested;
00404 idx = c.idx;
00405 string = c.string;
00406 tmpIndex = c.tmpIndex;
00407 indices = c.indices;
00408 parags = c.parags;
00409 xOffsets = c.xOffsets;
00410 yOffsets = c.yOffsets;
00411
00412
return *
this;
00413 }
00414
00415
bool KoTextCursor::operator==(
const KoTextCursor &c )
const
00416
{
00417
return doc == c.doc && string == c.string && idx == c.idx;
00418 }
00419
00420
int KoTextCursor::totalOffsetX()
const
00421
{
00422
if ( !nested )
00423
return 0;
00424
QValueStack<int>::ConstIterator xit = xOffsets.begin();
00425
int xoff = ox;
00426
for ( ; xit != xOffsets.end(); ++xit )
00427 xoff += *xit;
00428
return xoff;
00429 }
00430
00431
int KoTextCursor::totalOffsetY()
const
00432
{
00433
if ( !nested )
00434
return 0;
00435
QValueStack<int>::ConstIterator yit = yOffsets.begin();
00436
int yoff = oy;
00437
for ( ; yit != yOffsets.end(); ++yit )
00438 yoff += *yit;
00439
return yoff;
00440 }
00441
00442
void KoTextCursor::gotoIntoNested(
const QPoint &globalPos )
00443 {
00444
if ( !doc )
00445
return;
00446 push();
00447 ox = 0;
00448
int bl, y;
00449 string->lineHeightOfChar( idx, &bl, &y );
00450 oy = y + string->rect().y();
00451 nested = TRUE;
00452
QPoint p( globalPos.x() - offsetX(), globalPos.y() - offsetY() );
00453 Q_ASSERT( string->at( idx )->isCustom() );
00454 ox = string->at( idx )->x;
00455 string->at( idx )->customItem()->enterAt(
this, doc, string, idx, ox, oy, p );
00456 }
00457
00458
void KoTextCursor::invalidateNested()
00459 {
00460
if ( nested ) {
00461
QValueStack<KoTextParag*>::Iterator it = parags.begin();
00462
QValueStack<int>::Iterator it2 = indices.begin();
00463
for ( ; it != parags.end(); ++it, ++it2 ) {
00464
if ( *it == string )
00465
continue;
00466 (*it)->invalidate( 0 );
00467
if ( (*it)->at( *it2 )->isCustom() )
00468 (*it)->at( *it2 )->customItem()->invalidate();
00469 }
00470 }
00471 }
00472
00473
void KoTextCursor::insert(
const QString &str,
bool checkNewLine,
QMemArray<KoTextStringChar> *formatting )
00474 {
00475 string->invalidate( idx );
00476 tmpIndex = -1;
00477
bool justInsert = TRUE;
00478
QString s( str );
00479
#if defined(Q_WS_WIN)
00480
if ( checkNewLine )
00481 s = s.replace(
QRegExp(
"\\r" ),
"" );
00482
#endif
00483
if ( checkNewLine )
00484 justInsert = s.find(
'\n' ) == -1;
00485
if ( justInsert ) {
00486 string->insert( idx, s );
00487
if ( formatting ) {
00488
for (
int i = 0; i < (
int)s.length(); ++i ) {
00489
if ( formatting->at( i ).format() ) {
00490 formatting->at( i ).format()->addRef();
00491 string->string()->setFormat( idx + i, formatting->at( i ).format(), TRUE );
00492 }
00493 }
00494 }
00495 idx += s.length();
00496 }
else {
00497
QStringList lst = QStringList::split(
'\n', s, TRUE );
00498 QStringList::Iterator it = lst.begin();
00499
00500
int lastIndex = 0;
00501
KoTextFormat *lastFormat = 0;
00502
for ( ; it != lst.end(); ) {
00503
if ( it != lst.begin() ) {
00504 splitAndInsertEmptyParag( FALSE, TRUE );
00505
00506
#if 0 // no!
00507
string->prev()->format( -1, FALSE );
00508
#endif
00509
if ( lastFormat && formatting && string->prev() ) {
00510 lastFormat->
addRef();
00511 string->prev()->string()->setFormat( string->prev()->length() - 1, lastFormat, TRUE );
00512 }
00513 }
00514 lastFormat = 0;
00515
QString s = *it;
00516 ++it;
00517
if ( !s.isEmpty() )
00518 string->insert( idx, s );
00519
else
00520 string->invalidate( 0 );
00521
00522
if ( formatting ) {
00523
int len = s.length();
00524
for (
int i = 0; i < len; ++i ) {
00525
if ( formatting->at( i + lastIndex ).format() ) {
00526 formatting->at( i + lastIndex ).format()->addRef();
00527 string->string()->setFormat( i + idx, formatting->at( i + lastIndex ).format(), TRUE );
00528 }
00529 }
00530
if ( it != lst.end() )
00531 lastFormat = formatting->at( len + lastIndex ).format();
00532 ++len;
00533 lastIndex += len;
00534 }
00535
00536 idx += s.length();
00537 }
00538
#if 0
00539
string->format( -1, FALSE );
00540
int dy = string->rect().y() + string->rect().height() - y;
00541
#endif
00542
KoTextParag *p = string;
00543 p->setParagId( p->prev()->paragId() + 1 );
00544 p = p->next();
00545
while ( p ) {
00546 p->setParagId( p->prev()->paragId() + 1 );
00547
00548 p->invalidate( 0 );
00549 p = p->next();
00550 }
00551 }
00552
00553
#if 0
00554
int h = string->rect().height();
00555
string->format( -1, TRUE );
00556
if ( h != string->rect().height() )
00557 invalidateNested();
00558
else if ( doc && doc->parent() )
00559 doc->nextDoubleBuffered = TRUE;
00560
#endif
00561
fixCursorPosition();
00562 }
00563
00564
void KoTextCursor::gotoLeft()
00565 {
00566
if ( string->string()->isRightToLeft() )
00567 gotoNextLetter();
00568
else
00569 gotoPreviousLetter();
00570 }
00571
00572
void KoTextCursor::gotoPreviousLetter()
00573 {
00574 tmpIndex = -1;
00575
00576
if ( idx > 0 ) {
00577 idx = string->string()->previousCursorPosition( idx );
00578 }
else if ( string->prev() ) {
00579 string = string->prev();
00580
while ( !string->isVisible() )
00581 string = string->prev();
00582 idx = string->length() - 1;
00583
#if 0
00584
}
else {
00585
if ( nested ) {
00586 pop();
00587 processNesting( Prev );
00588
if ( idx == -1 ) {
00589 pop();
00590
if ( idx > 0 ) {
00591 idx--;
00592 }
else if ( string->prev() ) {
00593 string = string->prev();
00594 idx = string->length() - 1;
00595 }
00596 }
00597 }
00598
#endif
00599
}
00600
00601
const KoTextStringChar *tsc = string->at( idx );
00602
if ( tsc && tsc->isCustom() && tsc->customItem()->isNested() ) {
00603 processNesting( EnterEnd );
00604 }
00605 }
00606
00607
void KoTextCursor::push()
00608 {
00609 indices.push( idx );
00610 parags.push( string );
00611 xOffsets.push( ox );
00612 yOffsets.push( oy );
00613 nestedStack.push( nested );
00614 }
00615
00616
void KoTextCursor::pop()
00617 {
00618
if ( !doc )
00619
return;
00620 idx = indices.pop();
00621 string = parags.pop();
00622 ox = xOffsets.pop();
00623 oy = yOffsets.pop();
00624
00625
00626 nested = nestedStack.pop();
00627 }
00628
00629
void KoTextCursor::restoreState()
00630 {
00631
while ( !indices.isEmpty() )
00632 pop();
00633 }
00634
00635
bool KoTextCursor::place(
const QPoint &p, KoTextParag *s,
bool link,
int *customItemIndex )
00636 {
00637
if ( customItemIndex )
00638 *customItemIndex = -1;
00639
QPoint pos( p );
00640
QRect r;
00641
if ( pos.y() < s->rect().y() )
00642 pos.setY( s->rect().y() );
00643
while ( s ) {
00644 r = s->rect();
00645 r.setWidth( doc ? doc->width() : QWIDGETSIZE_MAX );
00646
if ( !s->next() || ( pos.y() >= r.y() && pos.y() < s->next()->rect().y() ) )
00647
break;
00648 s = s->next();
00649 }
00650
00651
if ( !s )
00652
return FALSE;
00653
00654 setParag( s, FALSE );
00655
int y = s->rect().y();
00656
int lines = s->lines();
00657 KoTextStringChar *chr = 0;
00658
int index = 0;
00659
int i = 0;
00660
int cy = 0;
00661
00662
for ( ; i < lines; ++i ) {
00663 chr = s->lineStartOfLine( i, &index );
00664 cy = s->lineY( i );
00665
00666
if ( !chr )
00667
return FALSE;
00668
if ( i < lines - 1 && pos.y() >= y + cy && pos.y() <= y + s->lineY( i+1 ) )
00669
break;
00670 }
00671
int nextLine;
00672
if ( i < lines - 1 )
00673 s->lineStartOfLine( i+1, &nextLine );
00674
else
00675 nextLine = s->length();
00676 i = index;
00677
int x = s->rect().x();
00678
if ( pos.x() < x )
00679 pos.setX( x + 1 );
00680
int cw;
00681
int curpos = s->length()-1;
00682
int dist = 10000000;
00683
bool inCustom = FALSE;
00684
while ( i < nextLine ) {
00685 chr = s->at(i);
00686
int cpos = x + chr->x;
00687 cw = chr->width;
00688
if ( chr->isCustom() ) {
00689
if ( pos.x() >= cpos && pos.x() <= cpos + cw &&
00690 pos.y() >= y + cy && pos.y() <= y + cy + chr->height() ) {
00691
if ( customItemIndex )
00692 *customItemIndex = i;
00693
if ( chr->customItem()->isNested() )
00694 {
00695 curpos = i;
00696 inCustom = TRUE;
00697
break;
00698 }
00699 }
00700 }
00701
if( chr->rightToLeft )
00702 cpos += cw;
00703
int d = cpos - pos.x();
00704
bool dm = d < 0 ? !chr->rightToLeft : chr->rightToLeft;
00705
if ( (QABS( d ) < dist || (dist == d && dm == TRUE )) && string->string()->validCursorPosition( i ) ) {
00706 dist = QABS( d );
00707
if ( !link || pos.x() >= x + chr->x ) {
00708 curpos = i;
00709 }
00710 }
00711 i++;
00712 }
00713 setIndex( curpos, FALSE );
00714
00715
#if 0
00716
if ( inCustom && doc && parag()->at( curpos )->isCustom() && parag()->at( curpos )->customItem()->isNested() ) {
00717 KoTextDocument *oldDoc = doc;
00718 pos.setX( pos.x() - parag()->at( curpos )->x );
00719 gotoIntoNested( pos );
00720
if ( oldDoc == doc )
00721
return TRUE;
00722
QPoint p( pos.x() - offsetX(), pos.y() - offsetY() );
00723
if ( !place( p, document()->firstParag() ) )
00724 pop();
00725 }
00726
#endif
00727
return TRUE;
00728 }
00729
00730
void KoTextCursor::processNesting( Operation op )
00731 {
00732
if ( !doc )
00733
return;
00734 push();
00735 ox = string->at( idx )->x;
00736
int bl, y;
00737 string->lineHeightOfChar( idx, &bl, &y );
00738 oy = y + string->rect().y();
00739 nested = TRUE;
00740
bool ok = FALSE;
00741
00742
switch ( op ) {
00743
case EnterBegin:
00744 ok = string->at( idx )->customItem()->enter(
this, doc, string, idx, ox, oy );
00745
break;
00746
case EnterEnd:
00747 ok = string->at( idx )->customItem()->enter(
this, doc, string, idx, ox, oy, TRUE );
00748
break;
00749
case Next:
00750 ok = string->at( idx )->customItem()->next(
this, doc, string, idx, ox, oy );
00751
break;
00752
case Prev:
00753 ok = string->at( idx )->customItem()->prev(
this, doc, string, idx, ox, oy );
00754
break;
00755
case Down:
00756 ok = string->at( idx )->customItem()->down(
this, doc, string, idx, ox, oy );
00757
break;
00758
case Up:
00759 ok = string->at( idx )->customItem()->up(
this, doc, string, idx, ox, oy );
00760
break;
00761 }
00762
if ( !ok )
00763 pop();
00764 }
00765
00766
void KoTextCursor::gotoRight()
00767 {
00768
if ( string->string()->isRightToLeft() )
00769 gotoPreviousLetter();
00770
else
00771 gotoNextLetter();
00772 }
00773
00774
void KoTextCursor::gotoNextLetter()
00775 {
00776 tmpIndex = -1;
00777
00778
int len = string->length() - 1;
00779
const KoTextStringChar *tsc = string->at( idx );
00780
if ( tsc && tsc->isCustom() && tsc->customItem()->isNested() ) {
00781 processNesting( EnterBegin );
00782
return;
00783 }
00784
00785
if ( idx < len ) {
00786 idx = string->string()->nextCursorPosition( idx );
00787 }
else if ( string->next() ) {
00788 string = string->next();
00789
while ( !string->isVisible() )
00790 string = string->next();
00791 idx = 0;
00792
#if 0
00793
}
else {
00794
if ( nested ) {
00795 pop();
00796 processNesting( Next );
00797
if ( idx == -1 ) {
00798 pop();
00799
if ( idx < string->length() - 1 ) {
00800 idx++;
00801 }
else if ( string->next() ) {
00802 string = string->next();
00803 idx = 0;
00804 }
00805 }
00806 }
00807
#endif
00808
}
00809 }
00810
00811
void KoTextCursor::gotoUp()
00812 {
00813
int indexOfLineStart;
00814
int line;
00815 KoTextStringChar *c = string->lineStartOfChar( idx, &indexOfLineStart, &line );
00816
if ( !c )
00817
return;
00818
00819 tmpIndex = QMAX( tmpIndex, idx - indexOfLineStart );
00820
if ( indexOfLineStart == 0 ) {
00821
if ( !string->prev() ) {
00822
if ( !nested )
00823
return;
00824 pop();
00825 processNesting( Up );
00826
if ( idx == -1 ) {
00827 pop();
00828
if ( !string->prev() )
00829
return;
00830 idx = tmpIndex = 0;
00831 }
else {
00832 tmpIndex = -1;
00833
return;
00834 }
00835 }
00836 string = string->prev();
00837
while ( !string->isVisible() )
00838 string = string->prev();
00839
int lastLine = string->lines() - 1;
00840
if ( !string->lineStartOfLine( lastLine, &indexOfLineStart ) )
00841
return;
00842
if ( indexOfLineStart + tmpIndex < string->length() )
00843 idx = indexOfLineStart + tmpIndex;
00844
else
00845 idx = string->length() - 1;
00846 }
else {
00847 --line;
00848
int oldIndexOfLineStart = indexOfLineStart;
00849
if ( !string->lineStartOfLine( line, &indexOfLineStart ) )
00850
return;
00851
if ( indexOfLineStart + tmpIndex < oldIndexOfLineStart )
00852 idx = indexOfLineStart + tmpIndex;
00853
else
00854 idx = oldIndexOfLineStart - 1;
00855 }
00856 fixCursorPosition();
00857 }
00858
00859
void KoTextCursor::gotoDown()
00860 {
00861
int indexOfLineStart;
00862
int line;
00863 KoTextStringChar *c = string->lineStartOfChar( idx, &indexOfLineStart, &line );
00864
if ( !c )
00865
return;
00866
00867 tmpIndex = QMAX( tmpIndex, idx - indexOfLineStart );
00868
if ( line == string->lines() - 1 ) {
00869
if ( !string->next() ) {
00870
if ( !nested )
00871
return;
00872 pop();
00873 processNesting( Down );
00874
if ( idx == -1 ) {
00875 pop();
00876
if ( !string->next() )
00877
return;
00878 idx = tmpIndex = 0;
00879 }
else {
00880 tmpIndex = -1;
00881
return;
00882 }
00883 }
00884 string = string->next();
00885
while ( !string->isVisible() )
00886 string = string->next();
00887
if ( !string->lineStartOfLine( 0, &indexOfLineStart ) )
00888
return;
00889
int end;
00890
if ( string->lines() == 1 )
00891 end = string->length();
00892
else
00893 string->lineStartOfLine( 1, &end );
00894
if ( indexOfLineStart + tmpIndex < end )
00895 idx = indexOfLineStart + tmpIndex;
00896
else
00897 idx = end - 1;
00898 }
else {
00899 ++line;
00900
int end;
00901
if ( line == string->lines() - 1 )
00902 end = string->length();
00903
else
00904 string->lineStartOfLine( line + 1, &end );
00905
if ( !string->lineStartOfLine( line, &indexOfLineStart ) )
00906
return;
00907
if ( indexOfLineStart + tmpIndex < end )
00908 idx = indexOfLineStart + tmpIndex;
00909
else
00910 idx = end - 1;
00911 }
00912 fixCursorPosition();
00913 }
00914
00915
void KoTextCursor::gotoLineEnd()
00916 {
00917 tmpIndex = -1;
00918
int indexOfLineStart;
00919
int line;
00920 KoTextStringChar *c = string->lineStartOfChar( idx, &indexOfLineStart, &line );
00921
if ( !c )
00922
return;
00923
00924
if ( line == string->lines() - 1 ) {
00925 idx = string->length() - 1;
00926 }
else {
00927 c = string->lineStartOfLine( ++line, &indexOfLineStart );
00928 indexOfLineStart--;
00929 idx = indexOfLineStart;
00930 }
00931 }
00932
00933
void KoTextCursor::gotoLineStart()
00934 {
00935 tmpIndex = -1;
00936
int indexOfLineStart;
00937
int line;
00938 KoTextStringChar *c = string->lineStartOfChar( idx, &indexOfLineStart, &line );
00939
if ( !c )
00940
return;
00941
00942 idx = indexOfLineStart;
00943 }
00944
00945
void KoTextCursor::gotoHome()
00946 {
00947 tmpIndex = -1;
00948
if ( doc )
00949 string = doc->firstParag();
00950 idx = 0;
00951 }
00952
00953
void KoTextCursor::gotoEnd()
00954 {
00955
if ( doc && !doc->lastParag()->isValid() )
00956 {
00957 kdDebug(32500) <<
"Last parag, " << doc->lastParag()->paragId() <<
", is invalid - aborting gotoEnd() !" << endl;
00958
return;
00959 }
00960
00961 tmpIndex = -1;
00962
if ( doc )
00963 string = doc->lastParag();
00964 idx = string->length() - 1;
00965 }
00966
00967
void KoTextCursor::gotoPageUp(
int visibleHeight )
00968 {
00969 tmpIndex = -1;
00970 KoTextParag *s = string;
00971
int h = visibleHeight;
00972
int y = s->rect().y();
00973
while ( s ) {
00974
if ( y - s->rect().y() >= h )
00975
break;
00976 s = s->prev();
00977 }
00978
00979
if ( !s && doc )
00980 s = doc->firstParag();
00981
00982 string = s;
00983 idx = 0;
00984 }
00985
00986
void KoTextCursor::gotoPageDown(
int visibleHeight )
00987 {
00988 tmpIndex = -1;
00989 KoTextParag *s = string;
00990
int h = visibleHeight;
00991
int y = s->rect().y();
00992
while ( s ) {
00993
if ( s->rect().y() - y >= h )
00994
break;
00995 s = s->next();
00996 }
00997
00998
if ( !s && doc ) {
00999 s = doc->lastParag();
01000 string = s;
01001 idx = string->length() - 1;
01002
return;
01003 }
01004
01005
if ( !s->isValid() )
01006
return;
01007
01008 string = s;
01009 idx = 0;
01010 }
01011
01012
void KoTextCursor::gotoWordRight()
01013 {
01014
if ( string->string()->isRightToLeft() )
01015 gotoPreviousWord();
01016
else
01017 gotoNextWord();
01018 }
01019
01020
void KoTextCursor::gotoWordLeft()
01021 {
01022
if ( string->string()->isRightToLeft() )
01023 gotoNextWord();
01024
else
01025 gotoPreviousWord();
01026 }
01027
01028
void KoTextCursor::gotoPreviousWord()
01029 {
01030 gotoPreviousLetter();
01031 tmpIndex = -1;
01032 KoTextString *s = string->string();
01033
bool allowSame = FALSE;
01034
if ( idx == ( (
int)s->length()-1 ) )
01035
return;
01036
for (
int i = idx; i >= 0; --i ) {
01037
if ( s->at( i ).c.isSpace() || s->at( i ).c ==
'\t' || s->at( i ).c ==
'.' ||
01038 s->at( i ).c ==
',' || s->at( i ).c ==
':' || s->at( i ).c ==
';' ) {
01039
if ( !allowSame )
01040
continue;
01041 idx = i + 1;
01042
return;
01043 }
01044
if ( !allowSame && !( s->at( i ).c.isSpace() || s->at( i ).c ==
'\t' || s->at( i ).c ==
'.' ||
01045 s->at( i ).c ==
',' || s->at( i ).c ==
':' || s->at( i ).c ==
';' ) )
01046 allowSame = TRUE;
01047 }
01048 idx = 0;
01049 }
01050
01051
void KoTextCursor::gotoNextWord()
01052 {
01053 tmpIndex = -1;
01054 KoTextString *s = string->string();
01055
bool allowSame = FALSE;
01056
for (
int i = idx; i < (
int)s->length(); ++i ) {
01057
if ( ! ( s->at( i ).c.isSpace() || s->at( i ).c ==
'\t' || s->at( i ).c ==
'.' ||
01058 s->at( i ).c ==
',' || s->at( i ).c ==
':' || s->at( i ).c ==
';' ) ) {
01059
if ( !allowSame )
01060
continue;
01061 idx = i;
01062
return;
01063 }
01064
if ( !allowSame && ( s->at( i ).c.isSpace() || s->at( i ).c ==
'\t' || s->at( i ).c ==
'.' ||
01065 s->at( i ).c ==
',' || s->at( i ).c ==
':' || s->at( i ).c ==
';' ) )
01066 allowSame = TRUE;
01067 }
01068
01069
if ( idx < ((
int)s->length()-1) ) {
01070 gotoLineEnd();
01071 }
else if ( string->next() ) {
01072 string = string->next();
01073
while ( !string->isVisible() )
01074 string = string->next();
01075 idx = 0;
01076 }
else {
01077 gotoLineEnd();
01078 }
01079 }
01080
01081
bool KoTextCursor::atParagStart()
const
01082
{
01083
return idx == 0;
01084 }
01085
01086
bool KoTextCursor::atParagEnd()
const
01087
{
01088
return idx == string->length() - 1;
01089 }
01090
01091
void KoTextCursor::splitAndInsertEmptyParag(
bool ind,
bool updateIds )
01092 {
01093
if ( !doc )
01094
return;
01095 tmpIndex = -1;
01096
KoTextFormat *f = 0;
01097
if ( doc->useFormatCollection() ) {
01098 f = string->at( idx )->format();
01099
if ( idx == string->length() - 1 && idx > 0 )
01100 f = string->at( idx - 1 )->format();
01101
if ( f->
isMisspelled() ) {
01102
KoTextFormat fNoMisspelled( *f );
01103 fNoMisspelled.
setMisspelled(
false );
01104 f = doc->formatCollection()->format( &fNoMisspelled );
01105 }
01106 }
01107
01108
if ( atParagEnd() ) {
01109 KoTextParag *n = string->next();
01110 KoTextParag *s = doc->createParag( doc, string, n, updateIds );
01111
if ( f )
01112 s->setFormat( 0, 1, f, TRUE );
01113 s->copyParagData( string );
01114
if ( ind ) {
01115
int oi, ni;
01116 s->indent( &oi, &ni );
01117 string = s;
01118 idx = ni;
01119 }
else {
01120 string = s;
01121 idx = 0;
01122 }
01123 }
else if ( atParagStart() ) {
01124 KoTextParag *p = string->prev();
01125 KoTextParag *s = doc->createParag( doc, p, string, updateIds );
01126
if ( f )
01127 s->setFormat( 0, 1, f, TRUE );
01128 s->copyParagData( string );
01129
if ( ind ) {
01130 s->indent();
01131 s->format();
01132 indent();
01133 string->format();
01134 }
01135 }
else {
01136
QString str = string->string()->toString().mid( idx, 0xFFFFFF );
01137 KoTextParag *n = string->next();
01138 KoTextParag *s = doc->createParag( doc, string, n, updateIds );
01139 s->copyParagData( string );
01140 s->remove( 0, 1 );
01141 s->append( str, TRUE );
01142
for ( uint i = 0; i < str.length(); ++i ) {
01143 KoTextStringChar* tsc = string->at( idx + i );
01144 s->setFormat( i, 1, tsc->format(), TRUE );
01145
if ( tsc->isCustom() ) {
01146 KoTextCustomItem * item = tsc->customItem();
01147 s->at( i )->setCustomItem( item );
01148 tsc->loseCustomItem();
01149
#if 0
01150
s->addCustomItem();
01151 string->removeCustomItem();
01152
#endif
01153
doc->unregisterCustomItem( item, string );
01154 doc->registerCustomItem( item, s );
01155 }
01156 }
01157 string->truncate( idx );
01158
if ( ind ) {
01159
int oi, ni;
01160 s->indent( &oi, &ni );
01161 string = s;
01162 idx = ni;
01163 }
else {
01164 string = s;
01165 idx = 0;
01166 }
01167 }
01168
01169 invalidateNested();
01170 }
01171
01172
bool KoTextCursor::removePreviousChar()
01173 {
01174 tmpIndex = -1;
01175
if ( !atParagStart() ) {
01176 string->remove( idx-1, 1 );
01177
int h = string->rect().height();
01178 idx--;
01179
01180 fixCursorPosition();
01181 string->format( -1, TRUE );
01182
if ( h != string->rect().height() )
01183 invalidateNested();
01184
01185
01186
return FALSE;
01187 }
else if ( string->prev() ) {
01188 string = string->prev();
01189 string->join( string->next() );
01190 string->invalidateCounters();
01191 invalidateNested();
01192
return TRUE;
01193 }
01194
return FALSE;
01195 }
01196
01197
bool KoTextCursor::remove()
01198 {
01199 tmpIndex = -1;
01200
if ( !atParagEnd() ) {
01201
int next = string->string()->nextCursorPosition( idx );
01202 string->remove( idx, next-idx );
01203
int h = string->rect().height();
01204 string->format( -1, TRUE );
01205
if ( h != string->rect().height() )
01206 invalidateNested();
01207
01208
01209
return FALSE;
01210 }
else if ( string->next() ) {
01211
if ( string->length() == 1 ) {
01212 string->next()->setPrev( string->prev() );
01213
if ( string->prev() )
01214 string->prev()->setNext( string->next() );
01215 KoTextParag *p = string->next();
01216
delete string;
01217 string = p;
01218 string->invalidate( 0 );
01220 string->invalidateCounters();
01222 KoTextParag *s = string;
01223
while ( s ) {
01224 s->id = s->p ? s->p->id + 1 : 0;
01225
01226
01227 s->changed = TRUE;
01228 s = s->n;
01229 }
01230 string->format();
01231 }
else {
01232 string->join( string->next() );
01233 }
01234 invalidateNested();
01235
return TRUE;
01236 }
01237
return FALSE;
01238 }
01239
01240
void KoTextCursor::killLine()
01241 {
01242
if ( atParagEnd() )
01243
return;
01244 string->remove( idx, string->length() - idx - 1 );
01245
int h = string->rect().height();
01246 string->format( -1, TRUE );
01247
if ( h != string->rect().height() )
01248 invalidateNested();
01249
01250
01251 }
01252
01253
void KoTextCursor::indent()
01254 {
01255
int oi = 0, ni = 0;
01256 string->indent( &oi, &ni );
01257
if ( oi == ni )
01258
return;
01259
01260
if ( idx >= oi )
01261 idx += ni - oi;
01262
else
01263 idx = ni;
01264 }
01265
01266
void KoTextCursor::setDocument( KoTextDocument *d )
01267 {
01268 doc = d;
01269 string = d->firstParag();
01270 idx = 0;
01271 nested = FALSE;
01272 restoreState();
01273 tmpIndex = -1;
01274 }
01275
01276
01277
int KoTextCursor::x()
const
01278
{
01279 KoTextStringChar *c = string->at( idx );
01280
int curx = c->x;
01281
if ( c->rightToLeft )
01282 curx += c->width;
01283
return curx;
01284 }
01285
01286
int KoTextCursor::y()
const
01287
{
01288
int dummy, line;
01289 string->lineStartOfChar( idx, &dummy, &line );
01290
return string->lineY( line );
01291 }
01292
01293
01294
01295
01296
01297
void KoTextDocument::init()
01298 {
01299
#if defined(PARSER_DEBUG)
01300
kdDebug(32500) << debug_indent +
"new KoTextDocument (%p)",
this << endl;
01301
#endif
01302
01303
01304
01305
01306 useFC = TRUE;
01307 pFormatter = 0;
01308 indenter = 0;
01309 fParag = 0;
01310 m_pageBreakEnabled =
false;
01311
01312 align = Qt::AlignAuto;
01313 nSelections = 1;
01314 addMargs = FALSE;
01315
01316
#if 0
01317
preferRichText = FALSE;
01318 txtFormat = Qt::AutoText;
01319 focusIndicator.parag = 0;
01320 minwParag = 0;
01321 sheet_ = QStyleSheet::defaultSheet();
01322 factory_ = QMimeSourceFactory::defaultFactory();
01323 contxt = QString::null;
01324 fCollection->setStyleSheet( sheet_ );
01325
#endif
01326
01327 underlLinks = TRUE;
01328 backBrush = 0;
01329 buf_pixmap = 0;
01330
01331
01332
01333
01334
01335 withoutDoubleBuffer = FALSE;
01336
01337 lParag = fParag = createParag(
this, 0, 0 );
01338 tmpCursor = 0;
01339
01340
01341
01342
01343 cx = cy = 0;
01344
01345
01346 flow_ =
new KoTextFlow;
01347
01348
01349 leftmargin = 0;
01350 rightmargin = 0;
01351
01352 selectionColors[ Standard ] = QApplication::palette().color( QPalette::Active, QColorGroup::Highlight );
01353 selectionText[ Standard ] = TRUE;
01354 commandHistory =
new KoTextDocCommandHistory( 100 );
01355 tStopWidth = formatCollection()->defaultFormat()->width(
'x' ) * 8;
01356 }
01357
01358 KoTextDocument::~KoTextDocument()
01359 {
01360
01361
01363 m_bDestroying =
true;
01364 clear(
false );
01366
delete commandHistory;
01367
delete flow_;
01368
01369
delete pFormatter;
01370
delete fCollection;
01371
01372
delete buf_pixmap;
01373
delete indenter;
01374
delete backBrush;
01375
if ( tArray )
01376
delete [] tArray;
01377 }
01378
01379
void KoTextDocument::clear(
bool createEmptyParag )
01380 {
01381
if ( flow_ )
01382 flow_->clear();
01383
while ( fParag ) {
01384 KoTextParag *p = fParag->next();
01385
delete fParag;
01386 fParag = p;
01387 }
01388 fParag = lParag = 0;
01389
if ( createEmptyParag )
01390 fParag = lParag = createParag(
this );
01391 selections.clear();
01392 }
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
int KoTextDocument::height()
const
01415
{
01416
int h = 0;
01417
if ( lParag )
01418 h = lParag->rect().top() + lParag->rect().height() + 1;
01419
01420
01421
return h;
01422 }
01423
01424
01425
01426 KoTextParag *KoTextDocument::createParag( KoTextDocument *d, KoTextParag *pr, KoTextParag *nx,
bool updateIds )
01427 {
01428
return new KoTextParag( d, pr, nx, updateIds );
01429 }
01430
01431
#if 0
01432
bool KoTextDocument::setMinimumWidth(
int w, KoTextParag *p )
01433 {
01434
if ( w == -1 ) {
01435 minw = 0;
01436 p = 0;
01437 }
01438
if ( p == minwParag ) {
01439 minw = w;
01440 emit minimumWidthChanged( minw );
01441 }
else if ( w > minw ) {
01442 minw = w;
01443 minwParag = p;
01444 emit minimumWidthChanged( minw );
01445 }
01446 cw = QMAX( minw, cw );
01447
return TRUE;
01448 }
01449
#endif
01450
01451
void KoTextDocument::setPlainText(
const QString &text )
01452 {
01453 clear();
01454
01455
01456
01457
01458
int lastNl = 0;
01459
int nl = text.find(
'\n' );
01460
if ( nl == -1 ) {
01461 lParag = createParag(
this, lParag, 0 );
01462
if ( !fParag )
01463 fParag = lParag;
01464
QString s = text;
01465
if ( !s.isEmpty() ) {
01466
if ( s[ (
int)s.length() - 1 ] ==
'\r' )
01467 s.remove( s.length() - 1, 1 );
01468 lParag->append( s );
01469 }
01470 }
else {
01471
for (;;) {
01472 lParag = createParag(
this, lParag, 0 );
01473
if ( !fParag )
01474 fParag = lParag;
01475
QString s = text.mid( lastNl, nl - lastNl );
01476
if ( !s.isEmpty() ) {
01477
if ( s[ (
int)s.length() - 1 ] ==
'\r' )
01478 s.remove( s.length() - 1, 1 );
01479 lParag->append( s );
01480 }
01481
if ( nl == 0xffffff )
01482
break;
01483 lastNl = nl + 1;
01484 nl = text.find(
'\n', nl + 1 );
01485
if ( nl == -1 )
01486 nl = 0xffffff;
01487 }
01488 }
01489
if ( !lParag )
01490 lParag = fParag = createParag(
this, 0, 0 );
01491 }
01492
01493
void KoTextDocument::setText(
const QString &text,
const QString & )
01494 {
01495
01496 selections.clear();
01497
#if 0
01498
if ( txtFormat == Qt::AutoText && QStyleSheet::mightBeRichText( text ) ||
01499 txtFormat == Qt::RichText )
01500 setRichText( text, context );
01501
else
01502
#endif
01503
setPlainText( text );
01504 }
01505
01506
QString KoTextDocument::plainText( KoTextParag *p )
const
01507
{
01508
if ( !p ) {
01509
QString buffer;
01510
QString s;
01511 KoTextParag *p = fParag;
01512
while ( p ) {
01513 s = p->string()->toString();
01514 s.remove( s.length() - 1, 1 );
01515
if ( p->next() )
01516 s +=
"\n";
01517 buffer += s;
01518 p = p->next();
01519 }
01520
return buffer;
01521 }
else {
01522
return p->string()->toString();
01523 }
01524 }
01525
01526
QString KoTextDocument::richText( KoTextParag * )
const
01527
{
01528
QString s;
01529
01530
return s;
01531 }
01532
01533
QString KoTextDocument::text()
const
01534
{
01535
if ( plainText().simplifyWhiteSpace().isEmpty() )
01536
return QString(
"");
01537
01538
01539
return plainText( 0 );
01540 }
01541
01542
QString KoTextDocument::text(
int parag )
const
01543
{
01544 KoTextParag *p = paragAt( parag );
01545
if ( !p )
01546
return QString::null;
01547
01548
01549
01550
01551
return plainText( p );
01552 }
01553
01554
void KoTextDocument::invalidate()
01555 {
01556 KoTextParag *s = fParag;
01557
while ( s ) {
01558 s->invalidate( 0 );
01559 s = s->next();
01560 }
01561 }
01562
01563
void KoTextDocument::informParagraphDeleted( KoTextParag* parag )
01564 {
01565
QMap<int, KoTextDocumentSelection>::Iterator it = selections.begin();
01566
for ( ; it != selections.end(); ++it )
01567 {
01568
if ( (*it).startCursor.parag() == parag ) {
01569
if ( parag->prev() ) {
01570 KoTextParag* prevP = parag->prev();
01571 (*it).startCursor.setParag( prevP );
01572 (*it).startCursor.setIndex( prevP->length()-1 );
01573 }
else
01574 (*it).startCursor.setParag( parag->next() );
01575 }
01576
if ( (*it).endCursor.parag() == parag ) {
01577
if ( parag->prev() ) {
01578 KoTextParag* prevP = parag->prev();
01579 (*it).endCursor.setParag( prevP );
01580 (*it).endCursor.setIndex( prevP->length()-1 );
01581 }
else
01582 (*it).endCursor.setParag( parag->next() );
01583 }
01584 }
01585 emit paragraphDeleted( parag );
01586 }
01587
01588
void KoTextDocument::selectionStart(
int id,
int ¶gId,
int &index )
01589 {
01590
QMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
01591
if ( it == selections.end() )
01592
return;
01593 KoTextDocumentSelection &sel = *it;
01594 paragId = !sel.swapped ? sel.startCursor.parag()->paragId() : sel.endCursor.parag()->paragId();
01595 index = !sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
01596 }
01597
01598 KoTextCursor KoTextDocument::selectionStartCursor(
int id)
01599 {
01600
QMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
01601
if ( it == selections.end() )
01602
return KoTextCursor(
this );
01603 KoTextDocumentSelection &sel = *it;
01604
if ( sel.swapped )
01605
return sel.endCursor;
01606
return sel.startCursor;
01607 }
01608
01609 KoTextCursor KoTextDocument::selectionEndCursor(
int id)
01610 {
01611
QMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
01612
if ( it == selections.end() )
01613
return KoTextCursor(
this );
01614 KoTextDocumentSelection &sel = *it;
01615
if ( !sel.swapped )
01616
return sel.endCursor;
01617
return sel.startCursor;
01618 }
01619
01620
void KoTextDocument::selectionEnd(
int id,
int ¶gId,
int &index )
01621 {
01622
QMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
01623
if ( it == selections.end() )
01624
return;
01625 KoTextDocumentSelection &sel = *it;
01626 paragId = sel.swapped ? sel.startCursor.parag()->paragId() : sel.endCursor.parag()->paragId();
01627 index = sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
01628 }
01629
01630
bool KoTextDocument::isSelectionSwapped(
int id )
01631 {
01632
QMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
01633
if ( it == selections.end() )
01634
return false;
01635 KoTextDocumentSelection &sel = *it;
01636
return sel.swapped;
01637 }
01638
01639 KoTextParag *KoTextDocument::selectionStart(
int id )
01640 {
01641
QMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
01642
if ( it == selections.end() )
01643
return 0;
01644 KoTextDocumentSelection &sel = *it;
01645
if ( sel.startCursor.parag()->paragId() < sel.endCursor.parag()->paragId() )
01646
return sel.startCursor.parag();
01647
return sel.endCursor.parag();
01648 }
01649
01650 KoTextParag *KoTextDocument::selectionEnd(
int id )
01651 {
01652
QMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
01653
if ( it == selections.end() )
01654
return 0;
01655 KoTextDocumentSelection &sel = *it;
01656
if ( sel.startCursor.parag()->paragId() > sel.endCursor.parag()->paragId() )
01657
return sel.startCursor.parag();
01658
return sel.endCursor.parag();
01659 }
01660
01661
void KoTextDocument::addSelection(
int id )
01662 {
01663 nSelections = QMAX( nSelections,
id + 1 );
01664 }
01665
01666
static void setSelectionEndHelper(
int id, KoTextDocumentSelection &sel, KoTextCursor &start, KoTextCursor &end )
01667 {
01668 KoTextCursor c1 = start;
01669 KoTextCursor c2 = end;
01670
if ( sel.swapped ) {
01671 c1 = end;
01672 c2 = start;
01673 }
01674
01675 c1.parag()->removeSelection(
id );
01676 c2.parag()->removeSelection(
id );
01677
if ( c1.parag() != c2.parag() ) {
01678 c1.parag()->setSelection(
id, c1.index(), c1.parag()->length() - 1 );
01679 c2.parag()->setSelection(
id, 0, c2.index() );
01680 }
else {
01681 c1.parag()->setSelection(
id, QMIN( c1.index(), c2.index() ), QMAX( c1.index(), c2.index() ) );
01682 }
01683
01684 sel.startCursor = start;
01685 sel.endCursor = end;
01686
if ( sel.startCursor.parag() == sel.endCursor.parag() )
01687 sel.swapped = sel.startCursor.index() > sel.endCursor.index();
01688 }
01689
01690
bool KoTextDocument::setSelectionEnd(
int id, KoTextCursor *cursor )
01691 {
01692
QMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
01693
if ( it == selections.end() )
01694
return FALSE;
01695 KoTextDocumentSelection &sel = *it;
01696
01697 KoTextCursor start = sel.startCursor;
01698 KoTextCursor end = *cursor;
01699
01700
if ( start == end ) {
01701 removeSelection(
id );
01702 setSelectionStart(
id, cursor );
01703
return TRUE;
01704 }
01705
01706
if ( sel.endCursor.parag() == end.parag() ) {
01707 setSelectionEndHelper(
id, sel, start, end );
01708
return TRUE;
01709 }
01710
01711
bool inSelection = FALSE;
01712 KoTextCursor c(
this );
01713 KoTextCursor tmp = sel.startCursor;
01714
if ( sel.swapped )
01715 tmp = sel.endCursor;
01716 tmp.restoreState();
01717 KoTextCursor tmp2 = *cursor;
01718 tmp2.restoreState();
01719 c.setParag( tmp.parag()->paragId() < tmp2.parag()->paragId() ? tmp.parag() : tmp2.parag() );
01720 KoTextCursor old;
01721
bool hadStart = FALSE;
01722
bool hadEnd = FALSE;
01723
bool hadStartParag = FALSE;
01724
bool hadEndParag = FALSE;
01725
bool hadOldStart = FALSE;
01726
bool hadOldEnd = FALSE;
01727
bool leftSelection = FALSE;
01728 sel.swapped = FALSE;
01729
for ( ;; ) {
01730
if ( c == start )
01731 hadStart = TRUE;
01732
if ( c == end )
01733 hadEnd = TRUE;
01734
if ( c.parag() == start.parag() )
01735 hadStartParag = TRUE;
01736
if ( c.parag() == end.parag() )
01737 hadEndParag = TRUE;
01738
if ( c == sel.startCursor )
01739 hadOldStart = TRUE;
01740
if ( c == sel.endCursor )
01741 hadOldEnd = TRUE;
01742
01743
if ( !sel.swapped &&
01744 ( hadEnd && !hadStart ||
01745 hadEnd && hadStart && start.parag() == end.parag() && start.index() > end.index() ) )
01746 sel.swapped = TRUE;
01747
01748
if ( c == end && hadStartParag ||
01749 c == start && hadEndParag ) {
01750 KoTextCursor tmp = c;
01751 tmp.restoreState();
01752
if ( tmp.parag() != c.parag() ) {
01753
int sstart = tmp.parag()->selectionStart(
id );
01754 tmp.parag()->removeSelection(
id );
01755 tmp.parag()->setSelection(
id, sstart, tmp.index() );
01756 }
01757 }
01758
01759
if ( inSelection &&
01760 ( c == end && hadStart || c == start && hadEnd ) )
01761 leftSelection = TRUE;
01762
else if ( !leftSelection && !inSelection && ( hadStart || hadEnd ) )
01763 inSelection = TRUE;
01764
01765
bool noSelectionAnymore = hadOldStart && hadOldEnd && leftSelection && !inSelection && !c.parag()->hasSelection(
id ) && c.atParagEnd();
01766 c.parag()->removeSelection(
id );
01767
if ( inSelection ) {
01768
if ( c.parag() == start.parag() && start.parag() == end.parag() ) {
01769 c.parag()->setSelection(
id, QMIN( start.index(), end.index() ), QMAX( start.index(), end.index() ) );
01770 }
else if ( c.parag() == start.parag() && !hadEndParag ) {
01771 c.parag()->setSelection(
id, start.index(), c.parag()->length() - 1 );
01772 }
else if ( c.parag() == end.parag() && !hadStartParag ) {
01773 c.parag()->setSelection(
id, end.index(), c.parag()->length() - 1 );
01774 }
else if ( c.parag() == end.parag() && hadEndParag ) {
01775 c.parag()->setSelection(
id, 0, end.index() );
01776 }
else if ( c.parag() == start.parag() && hadStartParag ) {
01777 c.parag()->setSelection(
id, 0, start.index() );
01778 }
else {
01779 c.parag()->setSelection(
id, 0, c.parag()->length() - 1 );
01780 }
01781 }
01782
01783
if ( leftSelection )
01784 inSelection = FALSE;
01785
01786 old = c;
01787 c.gotoNextLetter();
01788
if ( old == c || noSelectionAnymore )
01789
break;
01790 }
01791
01792
if ( !sel.swapped )
01793 sel.startCursor.parag()->setSelection(
id, sel.startCursor.index(), sel.startCursor.parag()->length() - 1 );
01794
01795 sel.startCursor = start;
01796 sel.endCursor = end;
01797
if ( sel.startCursor.parag() == sel.endCursor.parag() )
01798 sel.swapped = sel.startCursor.index() > sel.endCursor.index();
01799
01800 setSelectionEndHelper(
id, sel, start, end );
01801
01802
return TRUE;
01803 }
01804
01805
void KoTextDocument::selectAll(
int id )
01806 {
01807 removeSelection(
id );
01808
01809 KoTextDocumentSelection sel;
01810 sel.swapped = FALSE;
01811 KoTextCursor c(
this );
01812
01813 c.setParag( fParag );
01814 c.setIndex( 0 );
01815 sel.startCursor = c;
01816
01817 c.setParag( lParag );
01818 c.setIndex( lParag->length() - 1 );
01819 sel.endCursor = c;
01820
01821 KoTextParag *p = fParag;
01822
while ( p ) {
01823 p->setSelection(
id, 0, p->length() - 1 );
01824
#ifdef QTEXTTABLE_AVAILABLE
01825
for (
int i = 0; i < (
int)p->length(); ++i ) {
01826
if ( p->at( i )->isCustom() && p->at( i )->customItem()->isNested() ) {
01827 KoTextTable *t = (KoTextTable*)p->at( i )->customItem();
01828
QPtrList<KoTextTableCell> tableCells = t->tableCells();
01829
for ( KoTextTableCell *c = tableCells.first(); c; c = tableCells.next() )
01830 c->richText()->selectAll(
id );
01831 }
01832 }
01833
#endif
01834
p = p->next();
01835 }
01836
01837 selections.insert(
id, sel );
01838 }
01839
01840
bool KoTextDocument::removeSelection(
int id )
01841 {
01842
QMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
01843
if ( it == selections.end() )
01844
return FALSE;
01845
01846 KoTextDocumentSelection &sel = *it;
01847
01848 KoTextCursor c(
this );
01849 KoTextCursor tmp = sel.startCursor;
01850
if ( sel.swapped )
01851 tmp = sel.endCursor;
01852 tmp.restoreState();
01853 c.setParag( tmp.parag() );
01854 KoTextCursor old;
01855
bool hadStart = FALSE;
01856
bool hadEnd = FALSE;
01857 KoTextParag *lastParag = 0;
01858
bool leftSelection = FALSE;
01859
bool inSelection = FALSE;
01860 sel.swapped = FALSE;
01861
for ( ;; ) {
01862
if ( !hadStart && c.parag() == sel.startCursor.parag() )
01863 hadStart = TRUE;
01864
if ( !hadEnd && c.parag() == sel.endCursor.parag() )
01865 hadEnd = TRUE;
01866
01867
if ( !leftSelection && !inSelection && ( c.parag() == sel.startCursor.parag() || c.parag() == sel.endCursor.parag() ) )
01868 inSelection = TRUE;
01869
01870
if ( inSelection &&
01871 ( c == sel.endCursor && hadStart || c == sel.startCursor && hadEnd ) ) {
01872 leftSelection = TRUE;
01873 inSelection = FALSE;
01874 }
01875
01876
bool noSelectionAnymore = leftSelection && !inSelection && !c.parag()->hasSelection(
id ) && c.atParagEnd();
01877
01878
if ( lastParag != c.parag() )
01879 c.parag()->removeSelection(
id );
01880
01881 old = c;
01882 lastParag = c.parag();
01883 c.gotoNextLetter();
01884
if ( old == c || noSelectionAnymore )
01885
break;
01886 }
01887
01888 selections.remove(
id );
01889
return TRUE;
01890 }
01891
01892
QString KoTextDocument::selectedText(
int id,
bool withCustom )
const
01893
{
01894
01895
QMap<int, KoTextDocumentSelection>::ConstIterator it = selections.find(
id );
01896
if ( it == selections.end() )
01897
return QString::null;
01898
01899 KoTextDocumentSelection sel = *it;
01900
01901
01902 KoTextCursor c1 = sel.startCursor;
01903 KoTextCursor c2 = sel.endCursor;
01904
if ( sel.swapped ) {
01905 c2 = sel.startCursor;
01906 c1 = sel.endCursor;
01907 }
01908
01909 c2.restoreState();
01910 c1.restoreState();
01911
01912
if ( c1.parag() == c2.parag() ) {
01913
QString s;
01914 KoTextParag *p = c1.parag();
01915
int end = c2.index();
01916
if ( p->at( QMAX( 0, end - 1 ) )->isCustom() )
01917 ++end;
01918
if ( !withCustom || !p->customItems() ) {
01919 s += p->string()->toString().mid( c1.index(), end - c1.index() );
01920 }
else {
01921
for (
int i = c1.index(); i < end; ++i ) {
01922
if ( p->at( i )->isCustom() ) {
01923
#ifdef QTEXTTABLE_AVAILABLE
01924
if ( p->at( i )->customItem()->isNested() ) {
01925 s +=
"\n";
01926 KoTextTable *t = (KoTextTable*)p->at( i )->customItem();
01927
QPtrList<KoTextTableCell> cells = t->tableCells();
01928
for ( KoTextTableCell *c = cells.first(); c; c = cells.next() )
01929 s += c->richText()->plainText() +
"\n";
01930 s +=
"\n";
01931 }
01932
#endif
01933
}
else {
01934 s += p->at( i )->c;
01935 }
01936 s +=
"\n";
01937 }
01938 }
01939
return s;
01940 }
01941
01942
QString s;
01943 KoTextParag *p = c1.parag();
01944
int start = c1.index();
01945
while ( p ) {
01946
int end = p == c2.parag() ? c2.index() : p->length() - 1;
01947
if ( p == c2.parag() && p->at( QMAX( 0, end - 1 ) )->isCustom() )
01948 ++end;
01949
if ( !withCustom || !p->customItems() ) {
01950 s += p->string()->toString().mid( start, end - start );
01951
if ( p != c2.parag() )
01952 s +=
"\n";
01953 }
else {
01954
for (
int i = start; i < end; ++i ) {
01955
if ( p->at( i )->isCustom() ) {
01956
#ifdef QTEXTTABLE_AVAILABLE
01957
if ( p->at( i )->customItem()->isNested() ) {
01958 s +=
"\n";
01959 KoTextTable *t = (KoTextTable*)p->at( i )->customItem();
01960
QPtrList<KoTextTableCell> cells = t->tableCells();
01961
for ( KoTextTableCell *c = cells.first(); c; c = cells.next() )
01962 s += c->richText()->plainText() +
"\n";
01963 s +=
"\n";
01964 }
01965
#endif
01966
}
else {
01967 s += p->at( i )->c;
01968 }
01969 s +=
"\n";
01970 }
01971 }
01972 start = 0;
01973
if ( p == c2.parag() )
01974
break;
01975 p = p->next();
01976 }
01977
return s;
01978 }
01979
01980
void KoTextDocument::setFormat(
int id,
const KoTextFormat *f,
int flags )
01981 {
01982
QMap<int, KoTextDocumentSelection>::ConstIterator it = selections.find(
id );
01983
if ( it == selections.end() )
01984
return;
01985
01986 KoTextDocumentSelection sel = *it;
01987
01988 KoTextCursor c1 = sel.startCursor;
01989 KoTextCursor c2 = sel.endCursor;
01990
if ( sel.swapped ) {
01991 c2 = sel.startCursor;
01992 c1 = sel.endCursor;
01993 }
01994
01995 c2.restoreState();
01996 c1.restoreState();
01997
01998
if ( c1.parag() == c2.parag() ) {
01999 c1.parag()->setFormat( c1.index(), c2.index() - c1.index(), f, TRUE, flags );
02000
return;
02001 }
02002
02003 c1.parag()->setFormat( c1.index(), c1.parag()->length() - c1.index(), f, TRUE, flags );
02004 KoTextParag *p = c1.parag()->next();
02005
while ( p && p != c2.parag() ) {
02006 p->setFormat( 0, p->length(), f, TRUE, flags );
02007 p = p->next();
02008 }
02009 c2.parag()->setFormat( 0, c2.index(), f, TRUE, flags );
02010 }
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
void KoTextDocument::removeSelectedText(
int id, KoTextCursor *cursor )
02023 {
02024
QMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
02025
if ( it == selections.end() )
02026
return;
02027
02028 KoTextDocumentSelection sel = *it;
02029
02030 KoTextCursor c1 = sel.startCursor;
02031 KoTextCursor c2 = sel.endCursor;
02032
if ( sel.swapped ) {
02033 c2 = sel.startCursor;
02034 c1 = sel.endCursor;
02035 }
02036
02037
02038
if ( c1.nestedDepth() || c2.nestedDepth() )
02039
return;
02040
02041 c2.restoreState();
02042 c1.restoreState();
02043
02044 *cursor = c1;
02045 removeSelection(
id );
02046
02047
if ( c1.parag() == c2.parag() ) {
02048 c1.parag()->remove( c1.index(), c2.index() - c1.index() );
02049
return;
02050 }
02051
02052
02053
bool valid =
true;
02054
if ( c1.parag() == fParag && c1.index() == 0 &&
02055 c2.parag() == lParag && c2.index() == lParag->length() - 1 )
02056 valid = FALSE;
02057
02058
bool didGoLeft = FALSE;
02059
if ( c1.index() == 0 && c1.parag() != fParag ) {
02060 cursor->gotoPreviousLetter();
02061
if ( valid )
02062 didGoLeft = TRUE;
02063 }
02064
02065 c1.parag()->remove( c1.index(), c1.parag()->length() - 1 - c1.index() );
02066 KoTextParag *p = c1.parag()->next();
02067
int dy = 0;
02068 KoTextParag *tmp;
02069
while ( p && p != c2.parag() ) {
02070 tmp = p->next();
02071 dy -= p->rect().height();
02072
delete p;
02073 p = tmp;
02074 }
02075 c2.parag()->remove( 0, c2.index() );
02076
while ( p ) {
02077 p->move( dy );
02079
if ( p->paragLayout().counter )
02080 p->paragLayout().counter->invalidate();
02082 p->invalidate( 0 );
02083
02084 p = p->next();
02085 }
02086
02087 c1.parag()->join( c2.parag() );
02088
02089
if ( didGoLeft )
02090 cursor->gotoNextLetter();
02091 }
02092
02093
void KoTextDocument::indentSelection(
int id )
02094 {
02095
QMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
02096
if ( it == selections.end() )
02097
return;
02098
02099 KoTextDocumentSelection sel = *it;
02100 KoTextParag *startParag = sel.startCursor.parag();
02101 KoTextParag *endParag = sel.endCursor.parag();
02102
if ( sel.endCursor.parag()->paragId() < sel.startCursor.parag()->paragId() ) {
02103 endParag = sel.startCursor.parag();
02104 startParag = sel.endCursor.parag();
02105 }
02106
02107 KoTextParag *p = startParag;
02108
while ( p && p != endParag ) {
02109 p->indent();
02110 p = p->next();
02111 }
02112 }
02113
02114
void KoTextDocument::addCommand( KoTextDocCommand *cmd )
02115 {
02116 commandHistory->addCommand( cmd );
02117 }
02118
02119 KoTextCursor *KoTextDocument::undo( KoTextCursor *c )
02120 {
02121
return commandHistory->undo( c );
02122 }
02123
02124 KoTextCursor *KoTextDocument::redo( KoTextCursor *c )
02125 {
02126
return commandHistory->redo( c );
02127 }
02128
02129
bool KoTextDocument::find(
const QString &expr,
bool cs,
bool wo,
bool forward,
02130
int *parag,
int *index, KoTextCursor *cursor )
02131 {
02132 KoTextParag *p = forward ? fParag : lParag;
02133
if ( parag )
02134 p = paragAt( *parag );
02135
else if ( cursor )
02136 p = cursor->parag();
02137
bool first = TRUE;
02138
02139
while ( p ) {
02140
QString s = p->string()->toString();
02141 s.remove( s.length() - 1, 1 );
02142
int start = forward ? 0 : s.length() - 1;
02143
if ( first && index )
02144 start = *index;
02145
else if ( first )
02146 start = cursor->index();
02147
if ( !forward && first ) {
02148 start -= expr.length() + 1;
02149
if ( start < 0 ) {
02150 first = FALSE;
02151 p = p->prev();
02152
continue;
02153 }
02154 }
02155 first = FALSE;
02156
02157
for ( ;; ) {
02158
int res = forward ? s.find( expr, start, cs ) : s.findRev( expr, start, cs );
02159
if ( res == -1 )
02160
break;
02161
02162
bool ok = TRUE;
02163
if ( wo ) {
02164
int end = res + expr.length();
02165
if ( ( res == 0 || s[ res - 1 ].isSpace() || s[ res - 1 ].isPunct() ) &&
02166 ( end == (
int)s.length() || s[ end ].isSpace() || s[ end ].isPunct() ) )
02167 ok = TRUE;
02168
else
02169 ok = FALSE;
02170 }
02171
if ( ok ) {
02172 cursor->setParag( p );
02173 cursor->setIndex( res );
02174 setSelectionStart( Standard, cursor );
02175 cursor->setIndex( res + expr.length() );
02176 setSelectionEnd( Standard, cursor );
02177
if ( parag )
02178 *parag = p->paragId();
02179
if ( index )
02180 *index = res;
02181
return TRUE;
02182 }
02183
if ( forward ) {
02184 start = res + 1;
02185 }
else {
02186
if ( res == 0 )
02187
break;
02188 start = res - 1;
02189 }
02190 }
02191 p = forward ? p->next() : p->prev();
02192 }
02193
02194
return FALSE;
02195 }
02196
02197
#if 0
02198
void KoTextDocument::setTextFormat( Qt::TextFormat f )
02199 {
02200 txtFormat = f;
02201 }
02202
02203 Qt::TextFormat KoTextDocument::textFormat()
const
02204
{
02205
return txtFormat;
02206 }
02207
#endif
02208
02209
bool KoTextDocument::inSelection(
int selId,
const QPoint &pos )
const
02210
{
02211
QMap<int, KoTextDocumentSelection>::ConstIterator it = selections.find( selId );
02212
if ( it == selections.end() )
02213
return FALSE;
02214
02215 KoTextDocumentSelection sel = *it;
02216 KoTextParag *startParag = sel.startCursor.parag();
02217 KoTextParag *endParag = sel.endCursor.parag();
02218
if ( sel.startCursor.parag() == sel.endCursor.parag() &&
02219 sel.startCursor.parag()->selectionStart( selId ) == sel.endCursor.parag()->selectionEnd( selId ) )
02220
return FALSE;
02221
if ( sel.endCursor.parag()->paragId() < sel.startCursor.parag()->paragId() ) {
02222 endParag = sel.startCursor.parag();
02223 startParag = sel.endCursor.parag();
02224 }
02225
02226 KoTextParag *p = startParag;
02227
while ( p ) {
02228
if ( p->rect().contains( pos ) ) {
02229
bool inSel = FALSE;
02230
int selStart = p->selectionStart( selId );
02231
int selEnd = p->selectionEnd( selId );
02232
int y = 0;
02233
int h = 0;
02234
for (
int i = 0; i < p->length(); ++i ) {
02235
if ( i == selStart )
02236 inSel = TRUE;
02237
if ( i == selEnd )
02238
break;
02239
if ( p->at( i )->lineStart ) {
02240 y = (*p->lineStarts.find( i ))->y;
02241 h = (*p->lineStarts.find( i ))->h;
02242 }
02243
if ( pos.y() - p->rect().y() >= y && pos.y() - p->rect().y() <= y + h ) {
02244
if ( inSel && pos.x() >= p->at( i )->x &&
02245 pos.x() <= p->at( i )->x + p->at( i )->width )
02246
return TRUE;
02247 }
02248 }
02249 }
02250
if ( pos.y() < p->rect().y() )
02251
break;
02252
if ( p == endParag )
02253
break;
02254 p = p->next();
02255 }
02256
02257
return FALSE;
02258 }
02259
02260
#if 0
02261
void KoTextDocument::doLayout(
QPainter *p,
int w )
02262 {
02263
if ( !is_printer( p ) )
02264 p = 0;
02265 withoutDoubleBuffer = ( p != 0 );
02266 flow_->setWidth( w );
02267 cw = w;
02268 vw = w;
02269 fCollection->setPainter( p );
02270 KoTextParag *parag = fParag;
02271
while ( parag ) {
02272 parag->invalidate( 0 );
02273 parag->setPainter( p, TRUE );
02274 parag->format();
02275 parag = parag->next();
02276 }
02277
02278 fCollection->setPainter( 0 );
02279 parag = fParag;
02280
while ( parag ) {
02281 parag->setPainter( 0, FALSE );
02282 parag = parag->next();
02283 }
02284 }
02285
#endif
02286
02287
QPixmap *KoTextDocument::bufferPixmap(
const QSize &s )
02288 {
02289
if ( !buf_pixmap ) {
02290
int w = QABS( s.width() );
02291
int h = QABS( s.height() );
02292 buf_pixmap =
new QPixmap( w, h );
02293 }
else {
02294
if ( buf_pixmap->width() < s.width() ||
02295 buf_pixmap->height() < s.height() ) {
02296 buf_pixmap->resize( QMAX( s.width(), buf_pixmap->width() ),
02297 QMAX( s.height(), buf_pixmap->height() ) );
02298 }
02299 }
02300
02301
return buf_pixmap;
02302 }
02303
02304
#if 0
02305
void KoTextDocument::draw(
QPainter *p,
const QRect &rect,
const QColorGroup &cg,
const QBrush *paper )
02306 {
02307
if ( !firstParag() )
02308
return;
02309
02310
QBrush bgBrush = paper ? *paper : cg.brush( QColorGroup::Base );
02311 {
02312 p->setBrushOrigin( -
int( p->translationX() ),
02313 -int( p->translationY() ) );
02314 p->fillRect( rect, bgBrush );
02315 }
02316
02317
#if 0 // strange code found in QRT - I don't want all my colors to go away !
02318
if ( formatCollection()->defaultFormat()->color() != cg.text() ) {
02319
QDict<KoTextFormat> formats = formatCollection()->dict();
02320
QDictIterator<KoTextFormat> it( formats );
02321
while ( it.current() ) {
02322
if ( it.current() == formatCollection()->defaultFormat() ) {
02323 ++it;
02324
continue;
02325 }
02326 it.current()->setColor( cg.text() );
02327 ++it;
02328 }
02329 formatCollection()->defaultFormat()->setColor( cg.text() );
02330 }
02331
#endif
02332
02333 KoTextParag *parag = firstParag();
02334
while ( parag ) {
02335
if ( !parag->isValid() )
02336 parag->format();
02337
int y = parag->rect().y();
02338
QRect pr( parag->rect() );
02339 pr.setX( 0 );
02340 pr.setWidth( QWIDGETSIZE_MAX );
02341
if ( !rect.isNull() && !rect.intersects( pr ) ) {
02342 parag = parag->next();
02343
continue;
02344 }
02345 p->
translate( 0, y );
02346
if ( rect.isValid() )
02347 parag->paint( *p, cg, 0, FALSE, rect.x(), rect.y(), rect.width(), rect.height() );
02348
else
02349 parag->paint( *p, cg, 0, FALSE );
02350 p->
translate( 0, -y );
02351 parag = parag->next();
02352
if ( !flow()->isEmpty() )
02353 flow()->drawFloatingItems( p, rect.x(), rect.y(), rect.width(), rect.height(), cg, FALSE );
02354 }
02355 }
02356
02357
void KoTextDocument::drawParag(
QPainter *p, KoTextParag *parag,
int cx,
int cy,
int cw,
int ch,
02358
QPixmap *&doubleBuffer,
const QColorGroup &cg,
02359
bool drawCursor, KoTextCursor *cursor,
bool resetChanged )
02360 {
02361
QPainter *painter = 0;
02362
if ( resetChanged )
02363 parag->setChanged( FALSE );
02364
QRect ir( parag->rect() );
02365
bool useDoubleBuffer =
true;
02366
02367
02368
02369
if ( p->device()->devType() == QInternal::Printer )
02370 useDoubleBuffer = FALSE;
02371
02372
if ( useDoubleBuffer ) {
02373
if ( cx >= 0 && cy >= 0 )
02374 {
02375 ir = ir.intersect(
QRect( cx, cy, cw, ch ) );
02376
if (ir.isEmpty())
02377 useDoubleBuffer = FALSE;
02378 }
02379 }
02380
02381
if ( useDoubleBuffer ) {
02382 painter =
new QPainter;
02383
if ( !doubleBuffer ||
02384 ir.width() > doubleBuffer->width() ||
02385 ir.height() > doubleBuffer->height() ) {
02386 doubleBuffer = bufferPixmap( ir.size() );
02387 painter->begin( doubleBuffer );
02388 }
else {
02389 painter->begin( doubleBuffer );
02390 }
02391 }
else {
02392 painter = p;
02393 painter->
translate( ir.x(), ir.y() );
02394 }
02395
02396 painter->setBrushOrigin( -ir.x(), -ir.y() );
02397
02398
if ( useDoubleBuffer || is_printer( painter ) ) {
02399
if ( !parag->backgroundColor() )
02400 painter->fillRect(
QRect( 0, 0, ir.width(), ir.height() ),
02401 cg.brush( QColorGroup::Base ) );
02402
else
02403 painter->fillRect(
QRect( 0, 0, ir.width(), ir.height() ),
02404 *parag->backgroundColor() );
02405 }
else {
02406
if ( cursor && cursor->parag() == parag ) {
02407
if ( !parag->backgroundColor() )
02408 painter->fillRect(
QRect( parag->at( cursor->index() )->x, 0, 2, ir.height() ),
02409 cg.brush( QColorGroup::Base ) );
02410
else
02411 painter->fillRect(
QRect( parag->at( cursor->index() )->x, 0, 2, ir.height() ),
02412 *parag->backgroundColor() );
02413 }
02414 }
02415
02416 painter->
translate( -( ir.x() - parag->rect().x() ),
02417 -( ir.y() - parag->rect().y() ) );
02418 parag->paint( *painter, cg, drawCursor ? cursor : 0, TRUE, cx, cy, cw, ch );
02419
if ( !flow()->isEmpty() ) {
02420 painter->
translate( 0, -parag->rect().y() );
02421
QRect cr( cx, cy, cw, ch );
02422 cr = cr.intersect(
QRect( 0, parag->rect().y(), parag->rect().width(), parag->rect().height() ) );
02423 flow()->drawFloatingItems( painter, cr.x(), cr.y(), cr.width(), cr.height(), cg, FALSE );
02424 painter->
translate( 0, +parag->rect().y() );
02425 }
02426
02427
if ( useDoubleBuffer ) {
02428
delete painter;
02429 painter = 0;
02430 p->drawPixmap( ir.topLeft(), *doubleBuffer,
QRect(
QPoint( 0, 0 ), ir.size() ) );
02431 }
else {
02432 painter->
translate( -ir.x(), -ir.y() );
02433 }
02434
02435
if ( useDoubleBuffer ) {
02436 QRect rect = parag->rect();
02437
if ( rect.x() + rect.width() < parag->document()->x() + parag->document()->width() ) {
02438 p->fillRect( rect.x() + rect.width(), rect.y(),
02439 ( parag->document()->x() + parag->document()->width() ) -
02440 ( rect.x() + rect.width() ),
02441 rect.height(), cg.brush( QColorGroup::Base ) );
02442 }
02443
02444
02445 }
02446
02447 KoTextParag *KoTextDocument::draw(
QPainter *p,
int cx,
int cy,
int cw,
int ch,
const QColorGroup &cg,
02448
bool onlyChanged,
bool drawCursor, KoTextCursor *cursor,
bool resetChanged )
02449 {
02450
if ( withoutDoubleBuffer || par && par->withoutDoubleBuffer ) {
02451 withoutDoubleBuffer = TRUE;
02452 QRect crect( cx, cy, cw, ch );
02453 draw( p, crect, cg );
02454
return 0;
02455 }
02456 withoutDoubleBuffer = FALSE;
02457
02458
if ( !firstParag() )
02459
return 0;
02460
02461
if ( drawCursor && cursor )
02462 tmpCursor = cursor;
02463
if ( cx < 0 && cy < 0 ) {
02464 cx = 0;
02465 cy = 0;
02466 cw = width();
02467 ch = height();
02468 }
02469
02470 KoTextParag *lastFormatted = 0;
02471 KoTextParag *parag = firstParag();
02472
02473
QPixmap *doubleBuffer = 0;
02474
QPainter painter;
02475 QRect crect( cx, cy, cw, ch );
02476
02477
02478
if ( isPageBreakEnabled() && parag && cy <= parag->rect().y() && parag->rect().y() > 0 ) {
02479 QRect r( 0, 0,
02480 parag->document()->x() + parag->document()->width(),
02481 parag->rect().y() );
02482 r &= crect;
02483
if ( !r.isEmpty() )
02484 p->fillRect( r, cg.brush( QColorGroup::Base ) );
02485 }
02486
02487
while ( parag ) {
02488 lastFormatted = parag;
02489
if ( !parag->isValid() )
02490 parag->format();
02491
02492 QRect ir = parag->rect();
02493
if ( isPageBreakEnabled() && parag->next() )
02494
if ( ir.y() + ir.height() < parag->next()->rect().y() ) {
02495 QRect r( 0, ir.y() + ir.height(),
02496 parag->document()->x() + parag->document()->width(),
02497 parag->next()->rect().y() - ( ir.y() + ir.height() ) );
02498 r &= crect;
02499
if ( !r.isEmpty() )
02500 p->fillRect( r, cg.brush( QColorGroup::Base ) );
02501 }
02502
02503
if ( !ir.intersects( crect ) ) {
02504 ir.setWidth( parag->document()->width() );
02505
if ( ir.intersects( crect ) )
02506 p->fillRect( ir.intersect( crect ), cg.brush( QColorGroup::Base ) );
02507
if ( ir.y() > cy + ch ) {
02508 tmpCursor = 0;
02509
if ( buf_pixmap && buf_pixmap->height() > 300 ) {
02510
delete buf_pixmap;
02511 buf_pixmap = 0;
02512 }
02513
return lastFormatted;
02514 }
02515 parag = parag->next();
02516
continue;
02517 }
02518
02519
if ( !parag->hasChanged() && onlyChanged ) {
02520 parag = parag->next();
02521
continue;
02522 }
02523
02524 drawParag( p, parag, cx, cy, cw, ch, doubleBuffer, cg, drawCursor, cursor, resetChanged );
02525 parag = parag->next();
02526 }
02527
02528 parag = lastParag();
02529
if ( parag->rect().y() + parag->rect().height() < parag->document()->height() ) {
02530
if ( !parag->document()->parent() ) {
02531 p->fillRect( 0, parag->rect().y() + parag->rect().height(), parag->document()->width(),
02532 parag->document()->height() - ( parag->rect().y() + parag->rect().height() ),
02533 cg.brush( QColorGroup::Base ) );
02534 }
02535
if ( !flow()->isEmpty() ) {
02536 QRect cr( cx, cy, cw, ch );
02537 cr = cr.intersect( QRect( 0, parag->rect().y() + parag->rect().height(), parag->document()->width(),
02538 parag->document()->height() - ( parag->rect().y() + parag->rect().height() ) ) );
02539 flow()->drawFloatingItems( p, cr.x(), cr.y(), cr.width(), cr.height(), cg, FALSE );
02540 }
02541 }
02542
02543
if ( buf_pixmap && buf_pixmap->height() > 300 ) {
02544
delete buf_pixmap;
02545 buf_pixmap = 0;
02546 }
02547
02548 tmpCursor = 0;
02549
return lastFormatted;
02550 }
02551
#endif
02552
02553
#if 0
02554
void KoTextDocument::setDefaultFont(
const QFont &f )
02555 {
02556 updateFontSizes( f.
pointSize() );
02557 }
02558
#endif
02559
02560
void KoTextDocument::registerCustomItem( KoTextCustomItem *i, KoTextParag *p )
02561 {
02562
if ( i && i->placement() != KoTextCustomItem::PlaceInline )
02563 flow_->registerFloatingItem( i );
02564 p->registerFloatingItem( i );
02565 i->setParagraph( p );
02566
02567 customItems.append( i );
02568 }
02569
02570
void KoTextDocument::unregisterCustomItem( KoTextCustomItem *i, KoTextParag *p )
02571 {
02572 flow_->unregisterFloatingItem( i );
02573 p->unregisterFloatingItem( i );
02574 i->setParagraph( 0 );
02575 customItems.removeRef( i );
02576 }
02577
02578
02579
#if 0
02580
bool KoTextDocument::hasFocusParagraph()
const
02581
{
02582
return !!focusIndicator.parag;
02583 }
02584
02585
QString KoTextDocument::focusHref()
const
02586
{
02587
return focusIndicator.href;
02588 }
02589
02590
bool KoTextDocument::focusNextPrevChild(
bool next )
02591 {
02592
if ( !focusIndicator.parag ) {
02593
if ( next ) {
02594 focusIndicator.parag = fParag;
02595 focusIndicator.start = 0;
02596 focusIndicator.len = 0;
02597 }
else {
02598 focusIndicator.parag = lParag;
02599 focusIndicator.start = lParag->length();
02600 focusIndicator.len = 0;
02601 }
02602 }
else {
02603 focusIndicator.parag->setChanged( TRUE );
02604 }
02605 focusIndicator.href = QString::null;
02606
02607
if ( next ) {
02608 KoTextParag *p = focusIndicator.parag;
02609
int index = focusIndicator.start + focusIndicator.len;
02610
while ( p ) {
02611
for (
int i = index; i < p->length(); ++i ) {
02612
if ( p->at( i )->isAnchor() ) {
02613 p->setChanged( TRUE );
02614 focusIndicator.parag = p;
02615 focusIndicator.start = i;
02616 focusIndicator.len = 0;
02617 focusIndicator.href = p->at( i )->format()->anchorHref();
02618
while ( i < p->length() ) {
02619
if ( !p->at( i )->format()->isAnchor() )
02620
return TRUE;
02621 focusIndicator.len++;
02622 i++;
02623 }
02624 }
else if ( p->at( i )->isCustom() ) {
02625
#ifdef QTEXTTABLE_AVAILABLE
02626
if ( p->at( i )->customItem()->isNested() ) {
02627 KoTextTable *t = (KoTextTable*)p->at( i )->customItem();
02628
QPtrList<KoTextTableCell> cells = t->tableCells();
02629
02630 KoTextTableCell *c;
02631
bool resetCells = TRUE;
02632
for ( c = cells.first(); c; c = cells.next() ) {
02633
if ( c->richText()->hasFocusParagraph() ) {
02634
if ( c->richText()->focusNextPrevChild( next ) ) {
02635 p->setChanged( TRUE );
02636 focusIndicator.parag = p;
02637 focusIndicator.start = i;
02638 focusIndicator.len = 0;
02639 focusIndicator.href = c->richText()->focusHref();
02640
return TRUE;
02641 }
else {
02642 resetCells = FALSE;
02643 c = cells.next();
02644
break;
02645 }
02646 }
02647 }
02648
02649
if ( resetCells )
02650 c = cells.first();
02651
for ( ; c; c = cells.next() ) {
02652
if ( c->richText()->focusNextPrevChild( next ) ) {
02653 p->setChanged( TRUE );
02654 focusIndicator.parag = p;
02655 focusIndicator.start = i;
02656 focusIndicator.len = 0;
02657 focusIndicator.href = c->richText()->focusHref();
02658
return TRUE;
02659 }
02660 }
02661 }
02662
#endif
02663
}
02664 }
02665 index = 0;
02666 p = p->next();
02667 }
02668 }
else {
02669 KoTextParag *p = focusIndicator.parag;
02670
int index = focusIndicator.start - 1;
02671
if ( focusIndicator.len == 0 && index < focusIndicator.parag->length() - 1 )
02672 index++;
02673
while ( p ) {
02674
for (
int i = index; i >= 0; --i ) {
02675
if ( p->at( i )->format()->isAnchor() ) {
02676 p->setChanged( TRUE );
02677 focusIndicator.parag = p;
02678 focusIndicator.start = i;
02679 focusIndicator.len = 0;
02680 focusIndicator.href = p->at( i )->format()->anchorHref();
02681
while ( i >= -1 ) {
02682
if ( i < 0 || !p->at( i )->format()->isAnchor() ) {
02683 focusIndicator.start++;
02684
return TRUE;
02685 }
02686
if ( i < 0 )
02687
break;
02688 focusIndicator.len++;
02689 focusIndicator.start--;
02690 i--;
02691 }
02692 }
else if ( p->at( i )->isCustom() ) {
02693
#ifdef QTEXTTABLE_AVAILABLE
02694
if ( p->at( i )->customItem()->isNested() ) {
02695 KoTextTable *t = (KoTextTable*)p->at( i )->customItem();
02696
QPtrList<KoTextTableCell> cells = t->tableCells();
02697
02698 KoTextTableCell *c;
02699
bool resetCells = TRUE;
02700
for ( c = cells.last(); c; c = cells.prev() ) {
02701
if ( c->richText()->hasFocusParagraph() ) {
02702
if ( c->richText()->focusNextPrevChild( next ) ) {
02703 p->setChanged( TRUE );
02704 focusIndicator.parag = p;
02705 focusIndicator.start = i;
02706 focusIndicator.len = 0;
02707 focusIndicator.href = c->richText()->focusHref();
02708
return TRUE;
02709 }
else {
02710 resetCells = FALSE;
02711 c = cells.prev();
02712
break;
02713 }
02714 }
02715
if ( cells.at() == 0 )
02716
break;
02717 }
02718
02719
if ( resetCells )
02720 c = cells.last();
02721
for ( ; c; c = cells.prev() ) {
02722
if ( c->richText()->focusNextPrevChild( next ) ) {
02723 p->setChanged( TRUE );
02724 focusIndicator.parag = p;
02725 focusIndicator.start = i;
02726 focusIndicator.len = 0;
02727 focusIndicator.href = c->richText()->focusHref();
02728
return TRUE;
02729 }
02730
if ( cells.at() == 0 )
02731
break;
02732 }
02733 }
02734
#endif
02735
}
02736 }
02737 p = p->prev();
02738
if ( p )
02739 index = p->length() - 1;
02740 }
02741 }
02742
02743 focusIndicator.parag = 0;
02744
02745
return FALSE;
02746 }
02747
#endif
02748
02749
int KoTextDocument::length()
const
02750
{
02751
int l = 0;
02752 KoTextParag *p = fParag;
02753
while ( p ) {
02754 l += p->length() - 1;
02755 p = p->next();
02756 }
02757
return l;
02758 }
02759
02760
02761
void KoTextCursor::fixCursorPosition()
02762 {
02763
02764
if ( string->string()->validCursorPosition( idx ) )
02765
return;
02766
02767
int lineIdx;
02768 KoTextStringChar *start = string->lineStartOfChar( idx, &lineIdx, 0 );
02769
int x = string->string()->at( idx ).x;
02770
int diff = QABS(start->x - x);
02771
int best = lineIdx;
02772
02773 KoTextStringChar *c = start;
02774 ++c;
02775
02776 KoTextStringChar *end = &string->string()->at( string->length()-1 );
02777
while ( c <= end && !c->lineStart ) {
02778
int xp = c->x;
02779
if ( c->rightToLeft )
02780 xp += c->pixelwidth;
02781
int ndiff = QABS(xp - x);
02782
if ( ndiff < diff && string->string()->validCursorPosition(lineIdx + (c-start)) ) {
02783 diff = ndiff;
02784 best = lineIdx + (c-start);
02785 }
02786 ++c;
02787 }
02788 idx = best;
02789 }
02790
02791
02792
02793 KoTextString::KoTextString()
02794 {
02795 bidiDirty = TRUE;
02796 bNeedsSpellCheck =
true;
02797 bidi = FALSE;
02798 rightToLeft = FALSE;
02799 dir = QChar::DirON;
02800 }
02801
02802 KoTextString::KoTextString(
const KoTextString &s )
02803 {
02804 bidiDirty = s.bidiDirty;
02805 bNeedsSpellCheck = s.bNeedsSpellCheck;
02806 bidi = s.bidi;
02807 rightToLeft = s.rightToLeft;
02808 dir = s.dir;
02809 data = s.data;
02810 data.detach();
02811
for (
int i = 0; i < (
int)data.size(); ++i ) {
02812
KoTextFormat *f = data[i].format();
02813
if ( f )
02814 f->
addRef();
02815 }
02816 }
02817
02818
void KoTextString::insert(
int index,
const QString &s,
KoTextFormat *f )
02819 {
02820
int os = data.size();
02821 data.resize( data.size() + s.length() );
02822
if ( index < os ) {
02823 memmove( data.data() + index + s.length(), data.data() + index,
02824
sizeof( KoTextStringChar ) * ( os - index ) );
02825 }
02826
for (
int i = 0; i < (
int)s.length(); ++i ) {
02827 KoTextStringChar &ch = data[ (
int)index + i ];
02828 ch.x = 0;
02829 ch.pixelxadj = 0;
02830 ch.pixelwidth = 0;
02831 ch.width = 0;
02832 ch.lineStart = 0;
02833 ch.d.format = 0;
02834 ch.type = KoTextStringChar::Regular;
02835 ch.rightToLeft = 0;
02836 ch.startOfRun = 0;
02837 ch.c = s[ i ];
02838
#ifdef DEBUG_COLLECTION
02839
kdDebug(32500) <<
"KoTextString::insert setting format " << f <<
" to character " << (
int)index+i << endl;
02840
#endif
02841
ch.setFormat( f );
02842 }
02843 bidiDirty = TRUE;
02844 bNeedsSpellCheck =
true;
02845 }
02846
02847 KoTextString::~KoTextString()
02848 {
02849 clear();
02850 }
02851
02852
void KoTextString::insert(
int index, KoTextStringChar *c )
02853 {
02854
int os = data.size();
02855 data.resize( data.size() + 1 );
02856
if ( index < os ) {
02857 memmove( data.data() + index + 1, data.data() + index,
02858
sizeof( KoTextStringChar ) * ( os - index ) );
02859 }
02860 KoTextStringChar &ch = data[ (
int)index ];
02861 ch.c = c->c;
02862 ch.x = 0;
02863 ch.pixelxadj = 0;
02864 ch.pixelwidth = 0;
02865 ch.width = 0;
02866 ch.lineStart = 0;
02867 ch.rightToLeft = 0;
02868 ch.d.format = 0;
02869 ch.type = KoTextStringChar::Regular;
02870 ch.setFormat( c->format() );
02871 bidiDirty = TRUE;
02872 bNeedsSpellCheck =
true;
02873 }
02874
02875
void KoTextString::truncate(
int index )
02876 {
02877 index = QMAX( index, 0 );
02878 index = QMIN( index, (
int)data.size() - 1 );
02879
if ( index < (
int)data.size() ) {
02880
for (
int i = index + 1; i < (
int)data.size(); ++i ) {
02881 KoTextStringChar &ch = data[ i ];
02882
if ( ch.isCustom() ) {
02883
delete ch.customItem();
02884
if ( ch.d.custom->format )
02885 ch.d.custom->format->removeRef();
02886
delete ch.d.custom;
02887 ch.d.custom = 0;
02888 }
else if ( ch.format() ) {
02889 ch.format()->removeRef();
02890 }
02891 }
02892 }
02893 data.truncate( index );
02894 bidiDirty = TRUE;
02895 bNeedsSpellCheck =
true;
02896 }
02897
02898
void KoTextString::remove(
int index,
int len )
02899 {
02900
for (
int i = index; i < (
int)data.size() && i - index < len; ++i ) {
02901 KoTextStringChar &ch = data[ i ];
02902
if ( ch.isCustom() ) {
02903
delete ch.customItem();
02904
if ( ch.d.custom->format )
02905 ch.d.custom->format->removeRef();
02906
delete ch.d.custom;
02907 ch.d.custom = 0;
02908 }
else if ( ch.format() ) {
02909 ch.format()->removeRef();
02910 }
02911 }
02912 memmove( data.data() + index, data.data() + index + len,
02913
sizeof( KoTextStringChar ) * ( data.size() - index - len ) );
02914 data.resize( data.size() - len, QGArray::SpeedOptim );
02915 bidiDirty = TRUE;
02916 bNeedsSpellCheck =
true;
02917 }
02918
02919
void KoTextString::clear()
02920 {
02921
for (
int i = 0; i < (
int)data.count(); ++i ) {
02922 KoTextStringChar &ch = data[ i ];
02923
if ( ch.isCustom() ) {
02924
delete ch.customItem();
02925
if ( ch.d.custom->format )
02926 ch.d.custom->format->removeRef();
02927
delete ch.d.custom;
02928 ch.d.custom = 0;
02929 }
else if ( ch.format() ) {
02930 ch.format()->removeRef();
02931 }
02932 }
02933 data.resize( 0 );
02934 }
02935
02936
void KoTextString::setFormat(
int index,
KoTextFormat *f,
bool useCollection )
02937 {
02938 KoTextStringChar &ch = data[ index ];
02939
02940
if ( useCollection && ch.format() )
02941 {
02942
02943 ch.format()->removeRef();
02944 }
02945 ch.setFormat( f );
02946 }
02947
02948
void KoTextString::checkBidi()
const
02949
{
02950 KoTextString *that = (KoTextString *)
this;
02951 that->bidiDirty = FALSE;
02952
int length = data.size();
02953
if ( !length ) {
02954 that->bidi = FALSE;
02955 that->rightToLeft = dir == QChar::DirR;
02956
return;
02957 }
02958
const KoTextStringChar *start = data.data();
02959
const KoTextStringChar *end = start + length;
02960
02961
02962 QTextEngine textEngine( toString(), 0 );
02963 textEngine.direction = (QChar::Direction) dir;
02964 textEngine.itemize(QTextEngine::SingleLine);
02965
const QCharAttributes *ca = textEngine.attributes() + length-1;
02966 KoTextStringChar *ch = (KoTextStringChar *)end - 1;
02967 QScriptItem *item = &textEngine.items[textEngine.items.size()-1];
02968
unsigned char bidiLevel = item->analysis.bidiLevel;
02969
if ( bidiLevel )
02970 that->bidi = TRUE;
02971
int pos = length-1;
02972
while ( ch >= start ) {
02973
if ( item->position > pos ) {
02974 --item;
02975 Q_ASSERT( item >= &textEngine.items[0] );
02976 Q_ASSERT( item < &textEngine.items[textEngine.items.size()] );
02977 bidiLevel = item->analysis.bidiLevel;
02978
if ( bidiLevel )
02979 that->bidi = TRUE;
02980 }
02981 ch->softBreak = ca->softBreak;
02982 ch->whiteSpace = ca->whiteSpace;
02983 ch->charStop = ca->charStop;
02984 ch->wordStop = ca->wordStop;
02985
02986 ch->rightToLeft = (bidiLevel%2);
02987 --ch;
02988 --ca;
02989 --pos;
02990 }
02991
02992
if ( dir == QChar::DirR ) {
02993 that->bidi = TRUE;
02994 that->rightToLeft = TRUE;
02995 }
else if ( dir == QChar::DirL ) {
02996 that->rightToLeft = FALSE;
02997 }
else {
02998 that->rightToLeft = (textEngine.direction == QChar::DirR);
02999 }
03000 }
03001
03002
QMemArray<KoTextStringChar> KoTextString::subString(
int start,
int len )
const
03003
{
03004
if ( len == 0xFFFFFF )
03005 len = data.size();
03006
QMemArray<KoTextStringChar> a;
03007 a.resize( len );
03008
for (
int i = 0; i < len; ++i ) {
03009 KoTextStringChar *c = &data[ i + start ];
03010 a[ i ].c = c->c;
03011 a[ i ].x = 0;
03012 a[ i ].pixelxadj = 0;
03013 a[ i ].pixelwidth = 0;
03014 a[ i ].width = 0;
03015 a[ i ].lineStart = 0;
03016 a[ i ].rightToLeft = 0;
03017 a[ i ].d.format = 0;
03018 a[ i ].type = KoTextStringChar::Regular;
03019 a[ i ].setFormat( c->format() );
03020
if ( c->format() )
03021 c->format()->addRef();
03022 }
03023
return a;
03024 }
03025
03026
QString KoTextString::mid(
int start,
int len )
const
03027
{
03028
if ( len == 0xFFFFFF )
03029 len = data.size();
03030
QString res;
03031 res.setLength( len );
03032
for (
int i = 0; i < len; ++i ) {
03033 KoTextStringChar *c = &data[ i + start ];
03034 res[ i ] = c->c;
03035 }
03036
return res;
03037 }
03038
03039
QString KoTextString::toString(
const QMemArray<KoTextStringChar> &data )
03040 {
03041
QString s;
03042
int l = data.size();
03043 s.setUnicode( 0, l );
03044 KoTextStringChar *c = data.data();
03045
QChar *uc = (
QChar *)s.unicode();
03046
while ( l-- ) {
03047 *uc = c->c;
03048 uc++;
03049 c++;
03050 }
03051
03052
return s;
03053 }
03054
03055
QString KoTextString::toReverseString()
const
03056
{
03057
QString s;
03058
int l = length();
03059 s.setUnicode(0, l);
03060 KoTextStringChar *c = data.data() + (l-1);
03061
QChar *uc = (
QChar *)s.unicode();
03062
while ( l-- ) {
03063 *uc = c->c;
03064 uc++;
03065 c--;
03066 }
03067
03068
return s;
03069 }
03070
03071
int KoTextString::nextCursorPosition(
int next )
03072 {
03073
if ( bidiDirty )
03074 checkBidi();
03075
03076
const KoTextStringChar *c = data.data();
03077
int len = length();
03078
03079
if ( next < len - 1 ) {
03080 next++;
03081
while ( next < len - 1 && !c[next].charStop )
03082 next++;
03083 }
03084
return next;
03085 }
03086
03087
int KoTextString::previousCursorPosition(
int prev )
03088 {
03089
if ( bidiDirty )
03090 checkBidi();
03091
03092
const KoTextStringChar *c = data.data();
03093
03094
if ( prev ) {
03095 prev--;
03096
while ( prev && !c[prev].charStop )
03097 prev--;
03098 }
03099
return prev;
03100 }
03101
03102
bool KoTextString::validCursorPosition(
int idx )
03103 {
03104
if ( bidiDirty )
03105 checkBidi();
03106
03107
return (at( idx ).charStop);
03108 }
03109
03111
03112
void KoTextStringChar::setFormat(
KoTextFormat *f )
03113 {
03114
if ( type == Regular ) {
03115 d.format = f;
03116 }
else {
03117
if ( !d.custom ) {
03118 d.custom =
new CustomData;
03119 d.custom->custom = 0;
03120 }
03121 d.custom->format = f;
03122
if ( d.custom->custom )
03123 d.custom->custom->setFormat( f );
03124 }
03125 }
03126
03127
void KoTextStringChar::setCustomItem( KoTextCustomItem *i )
03128 {
03129
if ( type == Regular ) {
03130
KoTextFormat *f = format();
03131 d.custom =
new CustomData;
03132 d.custom->format = f;
03133 type = Custom;
03134 }
else {
03135
delete d.custom->custom;
03136 }
03137 d.custom->custom = i;
03138 }
03139
03140
void KoTextStringChar::loseCustomItem()
03141 {
03142
if ( isCustom() ) {
03143
KoTextFormat *f = d.custom->format;
03144 d.custom->custom = 0;
03145
delete d.custom;
03146 type = Regular;
03147 d.format = f;
03148 }
03149 }
03150
03151 KoTextStringChar::~KoTextStringChar()
03152 {
03153
if ( format() )
03154 format()->
removeRef();
03155
switch ( type ) {
03156
case Custom:
03157
delete d.custom;
break;
03158
default:
03159
break;
03160 }
03161 }
03162
03163
int KoTextStringChar::height()
const
03164
{
03165
return !isCustom() ? format()->
height() : ( customItem()->placement() == KoTextCustomItem::PlaceInline ? customItem()->height : 0 );
03166 }
03167
03168
int KoTextStringChar::ascent()
const
03169
{
03170
return !isCustom() ? format()->
ascent() : ( customItem()->placement() == KoTextCustomItem::PlaceInline ? customItem()->ascent() : 0 );
03171 }
03172
03173
int KoTextStringChar::descent()
const
03174
{
03175
return !isCustom() ? format()->
descent() : 0;
03176 }
03177
03178
03179
03180 KoTextParag::KoTextParag( KoTextDocument *d, KoTextParag *pr, KoTextParag *nx,
bool updateIds )
03181 : invalid( 0 ), p( pr ), n( nx ), doc( d ),
03182 changed( FALSE ),
03183 fullWidth( TRUE ),
03184 newLinesAllowed( TRUE ),
03185 visible( TRUE ), breakable( TRUE ), movedDown( FALSE ),
03186 align( 0 ),
03187 m_lineChanged( -1 ),
03188 m_wused( 0 ),
03189 mSelections( 0 ),
03190 mFloatingItems( 0 ),
03191 tArray( 0 )
03192 {
03193 defFormat = formatCollection()->defaultFormat();
03194
03195
03196
03197
03198
#if defined(PARSER_DEBUG)
03199
kdDebug(32500) << debug_indent +
"new KoTextParag" << endl;
03200
#endif
03201
03202
if ( p ) {
03203 p->n =
this;
03204
#ifdef QTEXTTABLE_AVAILABLE
03205
if ( p->tc )
03206 tc = p->tc;
03207
#endif
03208
}
03209
if ( n ) {
03210 n->p =
this;
03211
#ifdef QTEXTTABLE_AVAILABLE
03212
if ( n->tc )
03213 tc = n->tc;
03214
#endif
03215
}
03216
03217
#ifdef QTEXTTABLE_AVAILABLE
03218
if ( !tc && d && d->tableCell() )
03219 tc = d->tableCell();
03220
#endif
03221
03222
if ( !p && doc )
03223 doc->setFirstParag(
this );
03224
if ( !n && doc )
03225 doc->setLastParag(
this );
03226
03227
03228
03229
03230
03231
03232
if ( p )
03233
id = p->id + 1;
03234
else
03235
id = 0;
03236
if ( n && updateIds ) {
03237 KoTextParag *s = n;
03238
while ( s ) {
03239 s->id = s->p->id + 1;
03240
03241 s = s->n;
03242 }
03243 }
03244
03245 str =
new KoTextString();
03246 str->insert( 0,
" ", formatCollection()->defaultFormat() );
03247 }
03248
03249 KoTextParag::~KoTextParag()
03250 {
03251
03252
delete str;
03253
03254
03255
03256
03257
if ( !doc ) {
03258
03259
03260 }
03261
delete [] tArray;
03262
03263
QMap<int, KoTextParagLineStart*>::Iterator it = lineStarts.begin();
03264
for ( ; it != lineStarts.end(); ++it )
03265
delete *it;
03266
if ( mSelections )
delete mSelections;
03267
if ( mFloatingItems )
delete mFloatingItems;
03268
03269
if (p)
03270 p->setNext(n);
03271
if (n)
03272 n->setPrev(p);
03273
03275
if ( doc && !doc->isDestroying() )
03276 {
03277 doc->informParagraphDeleted(
this );
03278 }
03279
03281 }
03282
03283
void KoTextParag::setNext( KoTextParag *s )
03284 {
03285 n = s;
03286
if ( !n && doc )
03287 doc->setLastParag(
this );
03288 }
03289
03290
void KoTextParag::setPrev( KoTextParag *s )
03291 {
03292 p = s;
03293
if ( !p && doc )
03294 doc->setFirstParag(
this );
03295 }
03296
03297
void KoTextParag::invalidate(
int chr )
03298 {
03299
if ( invalid < 0 )
03300 invalid = chr;
03301
else
03302 invalid = QMIN( invalid, chr );
03303
#if 0
03304
if ( mFloatingItems ) {
03305
for ( KoTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() )
03306 i->move( 0, -1 );
03307 }
03308
#endif
03309
03310 }
03311
03312
void KoTextParag::setChanged(
bool b,
bool )
03313 {
03314 changed = b;
03315 m_lineChanged = -1;
03316
03317
03318
03319
03320 }
03321
03322
void KoTextParag::setLineChanged(
short int line )
03323 {
03324
if ( m_lineChanged == -1 ) {
03325
if ( !changed )
03326 m_lineChanged = line;
03327 }
03328
else
03329 m_lineChanged = QMIN( m_lineChanged, line );
03330 changed =
true;
03331
03332 }
03333
03334
void KoTextParag::insert(
int index,
const QString &s )
03335 {
03336
#if 0
03337
if ( doc && !doc->useFormatCollection() && doc->preProcessor() )
03338 str->insert( index, s,
03339 doc->preProcessor()->format( KoTextPreProcessor::Standard ) );
03340
else
03341
#endif
03342
str->insert( index, s, formatCollection()->defaultFormat() );
03343 invalidate( index );
03344
03345 }
03346
03347
void KoTextParag::truncate(
int index )
03348 {
03349 str->truncate( index );
03350 insert( length(),
" " );
03351
03352 }
03353
03354
void KoTextParag::remove(
int index,
int len )
03355 {
03356
if ( index + len - str->length() > 0 )
03357
return;
03358
for (
int i = index; i < index + len; ++i ) {
03359 KoTextStringChar *c = at( i );
03360
if ( doc && c->isCustom() ) {
03361 doc->unregisterCustomItem( c->customItem(),
this );
03362
03363 }
03364 }
03365 str->remove( index, len );
03366 invalidate( 0 );
03367
03368 }
03369
03370
void KoTextParag::join( KoTextParag *s )
03371 {
03372
03373
int oh = r.height() + s->r.height();
03374 n = s->n;
03375
if ( n )
03376 n->p =
this;
03377
else if ( doc )
03378 doc->setLastParag(
this );
03379
03380
int start = str->length();
03381
if ( length() > 0 && at( length() - 1 )->c ==
' ' ) {
03382 remove( length() - 1, 1 );
03383 --start;
03384 }
03385 append( s->str->toString(), TRUE );
03386
03387
for (
int i = 0; i < s->length(); ++i ) {
03388
if ( !doc || doc->useFormatCollection() ) {
03389 s->str->at( i ).format()->addRef();
03390 str->setFormat( i + start, s->str->at( i ).format(), TRUE );
03391 }
03392
if ( s->str->at( i ).isCustom() ) {
03393 KoTextCustomItem * item = s->str->at( i ).customItem();
03394 str->at( i + start ).setCustomItem( item );
03395 s->str->at( i ).loseCustomItem();
03396 doc->unregisterCustomItem( item, s );
03397 doc->registerCustomItem( item,
this );
03398 }
03399 }
03400 Q_ASSERT(str->at(str->length()-1).c ==
' ');
03401
03402
03403
03404
03405
03406
03407
03408
delete s;
03409 invalidate( 0 );
03411 invalidateCounters();
03413 r.setHeight( oh );
03414
03415
if ( n ) {
03416 KoTextParag *s = n;
03417
while ( s ) {
03418 s->id = s->p->id + 1;
03419
03420
03421 s->changed = TRUE;
03422 s = s->n;
03423 }
03424 }
03425 format();
03426
03427 }
03428
03429
void KoTextParag::move(
int &dy )
03430 {
03431
03432
if ( dy == 0 )
03433
return;
03434 changed = TRUE;
03435 r.moveBy( 0, dy );
03436
if ( mFloatingItems ) {
03437
for ( KoTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() ) {
03438 i->finalize();
03439 }
03440 }
03441
03442
03443
03444 movedDown = FALSE;
03445
03446
03447
if ( doc && doc->isPageBreakEnabled() ) {
03448
int shift;
03449
if ( ( shift = doc->formatter()->formatVertically( doc,
this ) ) ) {
03450
if ( p )
03451 p->setChanged( TRUE );
03452 dy += shift;
03453 }
03454 }
03455 }
03456
03457
void KoTextParag::format(
int start,
bool doMove )
03458 {
03459
if ( !str || str->length() == 0 || !formatter() )
03460
return;
03461
03462
#if 0
03463
if ( doc &&
03464 doc->preProcessor() &&
03465 ( needPreProcess || state == -1 ) )
03466 doc->preProcessor()->process( doc,
this, invalid <= 0 ? 0 : invalid );
03467 needPreProcess = FALSE;
03468
#endif
03469
03470
if ( invalid == -1 )
03471
return;
03472
03473
03474
03475 r.moveTopLeft(
QPoint( documentX(), p ? p->r.y() + p->r.height() : documentY() ) );
03476
03477
03478
03479 movedDown = FALSE;
03480
bool formattedAgain = FALSE;
03481
03482 formatAgain:
03483 r.setWidth( documentWidth() );
03484
03485
03486
if ( doc && mFloatingItems ) {
03487
for ( KoTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() ) {
03488
if ( i->placement() == KoTextCustomItem::PlaceRight )
03489 i->move( r.x() + r.width() - i->width, r.y() );
03490
else
03491 i->move( i->x(), r.y() );
03492 }
03493 }
03494
QMap<int, KoTextParagLineStart*> oldLineStarts = lineStarts;
03495 lineStarts.clear();
03496
int y;
03497
bool formatterWorked = formatter()->format( doc,
this, start, oldLineStarts, y, m_wused );
03498
03499
03500
03501
03502
03503
QMap<int, KoTextParagLineStart*>::Iterator it = oldLineStarts.begin();
03504
03505
for ( ; it != oldLineStarts.end(); ++it )
03506
delete *it;
03507
03508
03511
03512
03513
03514
03515 {
03516
if ( lineStarts.count() == 1 ) {
03517
03518
03519
03520
03521 {
03522 r.setWidth( lineStarts[0]->w );
03523 }
03524 }
03525
if ( newLinesAllowed ) {
03526 it = lineStarts.begin();
03527
int usedw = 0;
int lineid = 0;
03528
for ( ; it != lineStarts.end(); ++it, ++lineid ) {
03529 usedw = QMAX( usedw, (*it)->w );
03530 }
03531
if ( r.width() <= 0 ) {
03532
03533
03534
03535 r.setWidth( usedw );
03536 }
else {
03537 r.setWidth( QMIN( usedw, r.width() ) );
03538 }
03539 }
03540 }
03541
03542
if ( y != r.height() )
03543 r.setHeight( y );
03544
03545
if ( !visible )
03546 r.setHeight( 0 );
03547
03548
03549
if ( doc && doc->isPageBreakEnabled() ) {
03550
int shift = doc->formatter()->formatVertically( doc,
this );
03551
03552
if ( shift && !formattedAgain ) {
03553 formattedAgain = TRUE;
03554
goto formatAgain;
03555 }
03556 }
03557
03558
if ( doc )
03559 doc->formatter()->postFormat(
this );
03560
03561
if ( n && doMove && n->invalid == -1 && r.y() + r.height() != n->r.y() ) {
03562
03563
int dy = ( r.y() + r.height() ) - n->r.y();
03564 KoTextParag *s = n;
03565
bool makeInvalid =
false;
03566
03567
while ( s && dy ) {
03568
if ( s->movedDown ) {
03569 s->invalidate( 0 );
03570
break;
03571 }
03572
if ( !s->isFullWidth() )
03573 makeInvalid = TRUE;
03574
if ( makeInvalid )
03575 s->invalidate( 0 );
03576 s->move( dy );
03577
03578
03579 s = s->n;
03580 }
03581 }
03582
03583
03584
if ( mFloatingItems ) {
03585
#ifdef DEBUG_CI_PLACEMENT
03586
kdDebug(32500) << lineStarts.count() <<
" lines" << endl;
03587
#endif
03588
03589
int len = length();
03590
int line = -1;
03591
int lineY = 0;
03592
int baseLine = 0;
03593
QMap<int, KoTextParagLineStart*>::Iterator it = lineStarts.begin();
03594
for (
int i = 0 ; i < len; ++i ) {
03595 KoTextStringChar *chr = &str->at( i );
03596
if ( chr->lineStart ) {
03597 ++line;
03598
if ( line > 0 )
03599 ++it;
03600 lineY = (*it)->y;
03601 baseLine = (*it)->baseLine;
03602
#ifdef DEBUG_CI_PLACEMENT
03603
kdDebug(32500) <<
"New line (" << line <<
"): lineStart=" << (*it) <<
" lineY=" << lineY <<
" baseLine=" << baseLine <<
" height=" << (*it)->h << endl;
03604
#endif
03605
}
03606
if ( chr->isCustom() ) {
03607
int x = chr->x;
03608 KoTextCustomItem* item = chr->customItem();
03609 Q_ASSERT( baseLine >= item->ascent() );
03610
int y = lineY + baseLine - item->ascent();
03611
#ifdef DEBUG_CI_PLACEMENT
03612
kdDebug(32500) <<
"Custom item: i=" << i <<
" x=" << x <<
" lineY=" << lineY <<
" baseLine=" << baseLine <<
" ascent=" << item->ascent() <<
" -> y=" << y << endl;
03613
#endif
03614
item->move( x, y );
03615 item->finalize();
03616 }
03617 }
03618 }
03619
03620
03621
if ( formatterWorked > 0 )
03622 {
03623 invalid = -1;
03624 }
03625 changed = TRUE;
03626
03627 }
03628
03629
int KoTextParag::lineHeightOfChar(
int i,
int *bl,
int *y )
const
03630
{
03631
if ( !isValid() )
03632 ( (KoTextParag*)
this )->format();
03633
03634
QMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.end();
03635 --it;
03636
for ( ;; ) {
03637
if ( i >= it.key() ) {
03638
if ( bl )
03639 *bl = ( *it )->baseLine;
03640
if ( y )
03641 *y = ( *it )->y;
03642
return ( *it )->h;
03643 }
03644
if ( it == lineStarts.begin() )
03645
break;
03646 --it;
03647 }
03648
03649 kdWarning(32500) <<
"KoTextParag::lineHeightOfChar: couldn't find lh for " << i << endl;
03650
return 15;
03651 }
03652
03653 KoTextStringChar *KoTextParag::lineStartOfChar(
int i,
int *index,
int *line )
const
03654
{
03655
if ( !isValid() )
03656 ( (KoTextParag*)
this )->format();
03657
03658
int l = (
int)lineStarts.count() - 1;
03659
QMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.end();
03660 --it;
03661
for ( ;; ) {
03662
if ( i >= it.key() ) {
03663
if ( index )
03664 *index = it.key();
03665
if ( line )
03666 *line = l;
03667
return &str->at( it.key() );
03668 }
03669
if ( it == lineStarts.begin() )
03670
break;
03671 --it;
03672 --l;
03673 }
03674
03675 kdWarning(32500) <<
"KoTextParag::lineStartOfChar: couldn't find " << i << endl;
03676
return 0;
03677 }
03678
03679
int KoTextParag::lines()
const
03680
{
03681
if ( !isValid() )
03682 ( (KoTextParag*)
this )->format();
03683
03684
return (
int)lineStarts.count();
03685 }
03686
03687 KoTextStringChar *KoTextParag::lineStartOfLine(
int line,
int *index )
const
03688
{
03689
if ( !isValid() )
03690 ( (KoTextParag*)
this )->format();
03691
03692
if ( line >= 0 && line < (
int)lineStarts.count() ) {
03693
QMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
03694
while ( line-- > 0 )
03695 ++it;
03696
int i = it.key();
03697
if ( index )
03698 *index = i;
03699
return &str->at( i );
03700 }
03701
03702 kdWarning(32500) <<
"KoTextParag::lineStartOfLine: couldn't find " << line << endl;
03703
return 0;
03704 }
03705
03706
int KoTextParag::leftGap()
const
03707
{
03708
if ( !isValid() )
03709 ( (KoTextParag*)
this )->format();
03710
03711
int line = 0;
03712
int x = str->at(0).x;
03713
if ( str->isBidi() ) {
03714
for (
int i = 1; i < str->length(); ++i )
03715 x = QMIN(x, str->at(i).x);
03716
return x;
03717 }
03718
03719
QMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
03720
while (line < (
int)lineStarts.count()) {
03721
int i = it.key();
03722 x = QMIN(x, str->at(i).x);
03723 ++it;
03724 ++line;
03725 }
03726
return x;
03727 }
03728
03729
void KoTextParag::setFormat(
int index,
int len,
const KoTextFormat *_f,
bool useCollection,
int flags )
03730 {
03731 Q_ASSERT( useCollection );
03732
if ( index < 0 )
03733 index = 0;
03734
if ( index > str->length() - 1 )
03735 index = str->length() - 1;
03736
if ( index + len >= str->length() )
03737 len = str->length() - index;
03738
03739 KoTextFormatCollection *fc = 0;
03740
if ( useCollection )
03741 fc = formatCollection();
03742
KoTextFormat *of;
03743
for (
int i = 0; i < len; ++i ) {
03744 of = str->at( i + index ).format();
03745
if ( !changed && _f->
key() != of->
key() )
03746 changed = TRUE;
03747
03748
03749
03750
if ( invalid == -1 &&
03751 ( _f->
font().family() != of->
font().family() ||
03752 _f->
pointSize() != of->
pointSize() ||
03753 _f->
font().
weight() != of->
font().
weight() ||
03754 _f->
font().
italic() != of->
font().
italic() ||
03755 _f->
vAlign() != of->
vAlign() ||
03756 _f->
relativeTextSize() != of->
relativeTextSize() ||
03757 _f->
offsetFromBaseLine() != of->
offsetFromBaseLine() ||
03758 _f->
wordByWord() != of->
wordByWord() ||
03759 _f->
attributeFont() != of->
attributeFont() ||
03760 _f->
language() != of->
language() ||
03761 _f->
hyphenation() != of->
hyphenation() ||
03762 _f->
shadowDistanceX() != of->
shadowDistanceX() ||
03763 _f->
shadowDistanceY() != of->
shadowDistanceY()
03764 ) ) {
03765 invalidate( 0 );
03766 }
03767
if ( flags == -1 || flags == KoTextFormat::Format || !fc ) {
03768
#ifdef DEBUG_COLLECTION
03769
kdDebug(32500) <<
" KoTextParag::setFormat, will use format(f) " << f <<
" " << _f->
key() << endl;
03770
#endif
03771
KoTextFormat* f = fc ? fc->format( _f ) : const_cast<
KoTextFormat *>( _f );
03772 str->setFormat( i + index, f, useCollection );
03773 }
else {
03774
#ifdef DEBUG_COLLECTION
03775
kdDebug(32500) <<
" KoTextParag::setFormat, will use format(of,f,flags) of=" << of <<
" " << of->
key() <<
", f=" << _f <<
" " << _f->
key() << endl;
03776
#endif
03777
KoTextFormat *fm = fc->format( of, _f, flags );
03778
#ifdef DEBUG_COLLECTION
03779
kdDebug(32500) <<
" KoTextParag::setFormat, format(of,f,flags) returned " << fm <<
" " << fm->
key() <<
" " << endl;
03780
#endif
03781
str->setFormat( i + index, fm, useCollection );
03782 }
03783 }
03784 }
03785
03786
void KoTextParag::indent(
int *oldIndent,
int *newIndent )
03787 {
03788
if ( !doc || !doc->indent() ) {
03789
if ( oldIndent )
03790 *oldIndent = 0;
03791
if ( newIndent )
03792 *newIndent = 0;
03793
if ( oldIndent && newIndent )
03794 *newIndent = *oldIndent;
03795
return;
03796 }
03797 doc->indent()->indent( doc,
this, oldIndent, newIndent );
03798 }
03799
03800
void KoTextParag::drawCursorDefault(
QPainter &painter, KoTextCursor *cursor,
int curx,
int cury,
int curh,
const QColorGroup &cg )
03801 {
03802 painter.fillRect( QRect( curx, cury, 1, curh ), cg.color( QColorGroup::Text ) );
03803 painter.save();
03804
if ( string()->isBidi() ) {
03805
const int d = 4;
03806
if ( at( cursor->index() )->rightToLeft ) {
03807 painter.setPen( Qt::black );
03808 painter.drawLine( curx, cury, curx - d / 2, cury + d / 2 );
03809 painter.drawLine( curx, cury + d, curx - d / 2, cury + d / 2 );
03810 }
else {
03811 painter.setPen( Qt::black );
03812 painter.drawLine( curx, cury, curx + d / 2, cury + d / 2 );
03813 painter.drawLine( curx, cury + d, curx + d / 2, cury + d / 2 );
03814 }
03815 }
03816 painter.restore();
03817 }
03818
03819
int *KoTextParag::tabArray()
const
03820
{
03821
int *ta = tArray;
03822
if ( !ta && doc )
03823 ta = doc->tabArray();
03824
return ta;
03825 }
03826
03827
int KoTextParag::nextTabDefault(
int,
int x )
03828 {
03829
int *ta = tArray;
03830
03831
if ( !ta )
03832 ta = doc->tabArray();
03833
int tabStopWidth = doc->tabStopWidth();
03834
03835
if ( tabStopWidth != 0 )
03836
return tabStopWidth*(x/tabStopWidth+1);
03837
else
03838
return x;
03839 }
03840
03841
03842
03843
03844
03845
03846
03847
03848
03849
03850 KoTextFormatCollection *KoTextParag::formatCollection()
const
03851
{
03852
if ( doc )
03853
return doc->formatCollection();
03854
03855
03856
03857
return 0L;
03858 }
03859
03860
QString KoTextParag::richText()
const
03861
{
03862
QString s;
03863
#if 0
03864
KoTextStringChar *formatChar = 0;
03865
QString spaces;
03866
for (
int i = 0; i < length()-1; ++i ) {
03867 KoTextStringChar *c = &str->at( i );
03868
#endif
03869
#if 0
03870
if ( c->isAnchor() && !c->anchorName().isEmpty() ) {
03871
if ( c->anchorName().contains(
'#' ) ) {
03872
QStringList l = QStringList::split(
'#', c->anchorName() );
03873
for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it )
03874 s +=
"<a name=\"" + *it +
"\"></a>";
03875 }
else {
03876 s +=
"<a name=\"" + c->anchorName() +
"\"></a>";
03877 }
03878 }
03879
#endif
03880
#if 0
03881
if ( !formatChar ) {
03882 s += c->format()->makeFormatChangeTags( 0, QString::null, QString::null );
03883 formatChar = c;
03884 }
else if ( ( formatChar->format()->key() != c->format()->key() && c->c !=
' ' )
03885
03886 ) {
03887 s += c->format()->makeFormatChangeTags( formatChar->format(), QString::null ,
03888 QString::null );
03889 formatChar = c;
03890 }
03891
03892
if ( c->c ==
' ' || c->c ==
'\t' ) {
03893 spaces += c->c;
03894
continue;
03895 }
else if ( !spaces.isEmpty() ) {
03896
if ( spaces.length() > 1 || spaces[0] ==
'\t' )
03897 s +=
"<wsp>" + spaces +
"</wsp>";
03898
else
03899 s += spaces;
03900 spaces = QString::null;
03901 }
03902
03903
if ( c->c ==
'<' ) {
03904 s +=
"<";
03905 }
else if ( c->c ==
'>' ) {
03906 s +=
">";
03907 }
else if ( c->isCustom() ) {
03908 s += c->customItem()->richText();
03909 }
else {
03910 s += c->c;
03911 }
03912 }
03913
if ( !spaces.isEmpty() ) {
03914
if ( spaces.length() > 1 || spaces[0] ==
'\t' )
03915 s +=
"<wsp>" + spaces +
"</wsp>";
03916
else
03917 s += spaces;
03918 }
03919
03920
if ( formatChar )
03921 s += formatChar->format()->makeFormatEndTags( QString::null );
03922
#endif
03923
return s;
03924 }
03925
03926
03927
03928
03929
03930
03931
03932
03933
03934
03935
03936
03937
03938
03939
03940
03941
03942
03943
03944
03945
03946
03947
03948
void KoTextParag::show()
03949 {
03950
if ( visible || !doc )
03951
return;
03952 visible = TRUE;
03953 }
03954
03955
void KoTextParag::hide()
03956 {
03957
if ( !visible || !doc )
03958
return;
03959 visible = FALSE;
03960 }
03961
03962
void KoTextParag::setDirection( QChar::Direction d )
03963 {
03964
if ( str && str->direction() != d ) {
03965 str->setDirection( d );
03966 invalidate( 0 );
03968 m_layout.
direction = d;
03969 invalidateCounters();
03971 }
03972 }
03973
03974 QChar::Direction KoTextParag::direction()
const
03975
{
03976
return (str ? str->direction() :
QChar::DirON );
03977 }
03978
03979
void KoTextParag::setSelection(
int id,
int start,
int end )
03980 {
03981
QMap<int, KoTextParagSelection>::ConstIterator it = selections().find(
id );
03982
if ( it != mSelections->end() ) {
03983
if ( start == ( *it ).start && end == ( *it ).end )
03984
return;
03985 }
03986
03987 KoTextParagSelection sel;
03988 sel.start = start;
03989 sel.end = end;
03990 (*mSelections)[
id ] = sel;
03991 setChanged( TRUE, TRUE );
03992 }
03993
03994
void KoTextParag::removeSelection(
int id )
03995 {
03996
if ( !hasSelection(
id ) )
03997
return;
03998
if ( mSelections )
03999 mSelections->remove(
id );
04000 setChanged( TRUE, TRUE );
04001 }
04002
04003
int KoTextParag::selectionStart(
int id )
const
04004
{
04005
if ( !mSelections )
04006
return -1;
04007
QMap<int, KoTextParagSelection>::ConstIterator it = mSelections->find(
id );
04008
if ( it == mSelections->end() )
04009
return -1;
04010
return ( *it ).start;
04011 }
04012
04013
int KoTextParag::selectionEnd(
int id )
const
04014
{
04015
if ( !mSelections )
04016
return -1;
04017
QMap<int, KoTextParagSelection>::ConstIterator it = mSelections->find(
id );
04018
if ( it == mSelections->end() )
04019
return -1;
04020
return ( *it ).end;
04021 }
04022
04023
bool KoTextParag::hasSelection(
int id )
const
04024
{
04025
if ( !mSelections )
04026
return FALSE;
04027
QMap<int, KoTextParagSelection>::ConstIterator it = mSelections->find(
id );
04028
if ( it == mSelections->end() )
04029
return FALSE;
04030
return ( *it ).start != ( *it ).end || length() == 1;
04031 }
04032
04033
bool KoTextParag::fullSelected(
int id )
const
04034
{
04035
if ( !mSelections )
04036
return FALSE;
04037
QMap<int, KoTextParagSelection>::ConstIterator it = mSelections->find(
id );
04038
if ( it == mSelections->end() )
04039
return FALSE;
04040
return ( *it ).start == 0 && ( *it ).end == str->length() - 1;
04041 }
04042
04043
int KoTextParag::lineY(
int l )
const
04044
{
04045
if ( l > (
int)lineStarts.count() - 1 ) {
04046 kdWarning(32500) <<
"KoTextParag::lineY: line " << l <<
" out of range!" << endl;
04047
return 0;
04048 }
04049
04050
if ( !isValid() )
04051 ( (KoTextParag*)
this )->format();
04052
04053
QMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
04054
while ( l-- > 0 )
04055 ++it;
04056
return ( *it )->y;
04057 }
04058
04059
int KoTextParag::lineBaseLine(
int l )
const
04060
{
04061
if ( l > (
int)lineStarts.count() - 1 ) {
04062 kdWarning(32500) <<
"KoTextParag::lineBaseLine: line " << l <<
" out of range!" << endl;
04063
return 10;
04064 }
04065
04066
if ( !isValid() )
04067 ( (KoTextParag*)
this )->format();
04068
04069
QMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
04070
while ( l-- > 0 )
04071 ++it;
04072
return ( *it )->baseLine;
04073 }
04074
04075
int KoTextParag::lineHeight(
int l )
const
04076
{
04077
if ( l > (
int)lineStarts.count() - 1 ) {
04078 kdWarning(32500) <<
"KoTextParag::lineHeight: line " << l <<
" out of range!" << endl;
04079
return 15;
04080 }
04081
04082
if ( !isValid() )
04083 ( (KoTextParag*)
this )->format();
04084
04085
QMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
04086
while ( l-- > 0 )
04087 ++it;
04088
return ( *it )->h;
04089 }
04090
04091
void KoTextParag::lineInfo(
int l,
int &y,
int &h,
int &bl )
const
04092
{
04093
if ( l > (
int)lineStarts.count() - 1 ) {
04094 kdWarning(32500) <<
"KoTextParag::lineInfo: line " << l <<
" out of range!" << endl;
04095 kdDebug(32500) << (
int)lineStarts.count() - 1 <<
" " << l << endl;
04096 y = 0;
04097 h = 15;
04098 bl = 10;
04099
return;
04100 }
04101
04102
if ( !isValid() )
04103 ( (KoTextParag*)
this )->format();
04104
04105
QMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
04106
while ( l-- > 0 )
04107 ++it;
04108 y = ( *it )->y;
04109 h = ( *it )->h;
04110 bl = ( *it )->baseLine;
04111 }
04112
04113 uint KoTextParag::alignment()
const
04114
{
04115
return align;
04116 }
04117
04118
void KoTextParag::setFormat(
KoTextFormat *fm )
04119 {
04120
#if 0
04121
bool doUpdate = FALSE;
04122
if (defFormat && (defFormat != formatCollection()->defaultFormat()))
04123 doUpdate = TRUE;
04124
#endif
04125
defFormat = formatCollection()->format( fm );
04126
#if 0
04127
if ( !doUpdate )
04128
return;
04129
for (
int i = 0; i < length(); ++i ) {
04130
if ( at( i )->format()->styleName() == defFormat->styleName() )
04131 at( i )->format()->updateStyle();
04132 }
04133
#endif
04134
}
04135
04136 KoTextFormatterBase *KoTextParag::formatter()
const
04137
{
04138
if ( doc )
04139
return doc->formatter();
04140
04141
04142
04143
return 0L;
04144 }
04145
04146
04147
04148
04149
04150
04151
04152
04153
04154
04155
04156
04157
04158
04159
int KoTextParag::widthUsed()
const
04160
{
04161
return m_wused;
04162 }
04163
04164
void KoTextParag::setTabArray(
int *a )
04165 {
04166
delete [] tArray;
04167 tArray = a;
04168 }
04169
04170
void KoTextParag::setTabStops(
int tw )
04171 {
04172
if ( doc )
04173 doc->setTabStops( tw );
04174
04175
04176 }
04177
04178
QMap<int, KoTextParagSelection> &KoTextParag::selections()
const
04179
{
04180
if ( !mSelections )
04181 ((KoTextParag *)
this)->mSelections =
new QMap<int, KoTextParagSelection>;
04182
return *mSelections;
04183 }
04184
04185
QPtrList<KoTextCustomItem> &KoTextParag::floatingItems()
const
04186
{
04187
if ( !mFloatingItems )
04188 ((KoTextParag *)
this)->mFloatingItems =
new QPtrList<KoTextCustomItem>;
04189
return *mFloatingItems;
04190 }
04191
04192
void KoTextCursor::setIndex(
int i,
bool restore )
04193 {
04194
if ( restore )
04195 restoreState();
04196
04197
04198
04199
04200
04201
if ( i < 0 || i > string->length() ) {
04202
#if defined(QT_CHECK_RANGE)
04203
kdWarning(32500) <<
"KoTextCursor::setIndex: " << i <<
" out of range" << endl;
04204
04205
#endif
04206
i = i < 0 ? 0 : string->length() - 1;
04207 }
04208
04209 tmpIndex = -1;
04210 idx = i;
04211 }
04212
04213
04214
04215 KoTextFormatterBase::KoTextFormatterBase()
04216 : wrapColumn( -1 ), wrapEnabled( TRUE ),
04217 m_bViewFormattingChars( false ),
04218 biw( true )
04219 {
04220 }
04221
04222
04223
#if 0
04224
KoTextParagLineStart *KoTextFormatterBase::formatLine( KoTextParag *parag, KoTextString *string, KoTextParagLineStart *line,
04225 KoTextStringChar *startChar, KoTextStringChar *lastChar,
int align,
int space )
04226 {
04227
#ifndef QT_NO_COMPLEXTEXT
04228
if( string->isBidi() )
04229
return bidiReorderLine( parag, string, line, startChar, lastChar, align, space );
04230
#endif
04231
space = QMAX( space, 0 );
04232
int start = (startChar - &string->at(0));
04233
int last = (lastChar - &string->at(0) );
04234
04235
if ( align & Qt::AlignHCenter || align & Qt::AlignRight ) {
04236
if ( align & Qt::AlignHCenter )
04237 space /= 2;
04238
for (
int j = start; j <= last; ++j )
04239 string->at( j ).x += space;
04240 }
else if ( align & AlignJustify ) {
04241
int numSpaces = 0;
04242
for (
int j = start; j < last; ++j ) {
04243
if( isBreakable( string, j ) ) {
04244 numSpaces++;
04245 }
04246 }
04247
int toAdd = 0;
04248
for (
int k = start + 1; k <= last; ++k ) {
04249
if( isBreakable( string, k ) && numSpaces ) {
04250
int s = space / numSpaces;
04251 toAdd += s;
04252 space -= s;
04253 numSpaces--;
04254 }
04255 string->at( k ).x += toAdd;
04256 }
04257 }
04258
04259
if ( last >= 0 && last < string->length() )
04260 line->w = string->at( last ).x + string->width( last );
04261
else
04262 line->w = 0;
04263
04264
return new KoTextParagLineStart();
04265 }
04266
#endif
04267
04268
#ifdef BIDI_DEBUG
04269
#include <iostream>
04270
#endif
04271
04272
04273 KoTextParagLineStart *KoTextFormatterBase::bidiReorderLine( KoTextParag * , KoTextString *text, KoTextParagLineStart *line,
04274 KoTextStringChar *startChar, KoTextStringChar *lastChar,
int align,
int space )
04275 {
04276
int start = (startChar - &text->at(0));
04277
int last = (lastChar - &text->at(0) );
04278
04279
04280 KoBidiControl *control =
new KoBidiControl( line->context(), line->status );
04281
QString str;
04282 str.setUnicode( 0, last - start + 1 );
04283
04284 KoTextStringChar *ch = startChar;
04285
QChar *qch = (
QChar *)str.unicode();
04286
while ( ch <= lastChar ) {
04287 *qch = ch->c;
04288 qch++;
04289 ch++;
04290 }
04291
int x = startChar->x;
04292
04293
QPtrList<KoTextRun> *runs;
04294 runs = KoComplexText::bidiReorderLine(control, str, 0, last - start + 1,
04295 (text->isRightToLeft() ? QChar::DirR : QChar::DirL) );
04296
04297
04298
04299
int numSpaces = 0;
04300
04301
if( align == Qt::AlignAuto ) {
04302
04303
if ( text->isRightToLeft() )
04304 align = Qt::AlignRight;
04305 }
04306
04307
if ( align & Qt::AlignHCenter )
04308 x += space/2;
04309
else if ( align & Qt::AlignRight )
04310 x += space;
04311
else if ( align & Qt::AlignJustify ) {
04312
for (
int j = start; j < last; ++j ) {
04313
if( isBreakable( text, j ) ) {
04314 numSpaces++;
04315 }
04316 }
04317 }
04318
int toAdd = 0;
04319
bool first = TRUE;
04320 KoTextRun *r = runs->first();
04321
int xmax = -0xffffff;
04322
while ( r ) {
04323
if(r->level %2) {
04324
04325
int pos = r->stop + start;
04326
while(pos >= r->start + start) {
04327 KoTextStringChar *c = &text->at(pos);
04328
if( numSpaces && !first && isBreakable( text, pos ) ) {
04329
int s = space / numSpaces;
04330 toAdd += s;
04331 space -= s;
04332 numSpaces--;
04333 }
else if ( first ) {
04334 first = FALSE;
04335
if ( c->c ==
' ' )
04336 x -= c->format()->width(
' ' );
04337 }
04338 c->x = x + toAdd;
04339 c->rightToLeft = TRUE;
04340 c->startOfRun = FALSE;
04341
int ww = 0;
04342
if ( c->c.unicode() >= 32 || c->c ==
'\t' || c->c ==
'\n' || c->isCustom() ) {
04343 ww = c->width;
04344 }
else {
04345 ww = c->format()->width(
' ' );
04346 }
04347
if ( xmax < x + toAdd + ww ) xmax = x + toAdd + ww;
04348 x += ww;
04349 pos--;
04350 }
04351 }
else {
04352
int pos = r->start + start;
04353
while(pos <= r->stop + start) {
04354 KoTextStringChar* c = &text->at(pos);
04355
if( numSpaces && !first && isBreakable( text, pos ) ) {
04356
int s = space / numSpaces;
04357 toAdd += s;
04358 space -= s;
04359 numSpaces--;
04360 }
else if ( first ) {
04361 first = FALSE;
04362
if ( c->c ==
' ' )
04363 x -= c->format()->width(
' ' );
04364 }
04365 c->x = x + toAdd;
04366 c->rightToLeft = FALSE;
04367 c->startOfRun = FALSE;
04368
int ww = 0;
04369
if ( c->c.unicode() >= 32 || c->c ==
'\t' || c->isCustom() ) {
04370 ww = c->width;
04371 }
else {
04372 ww = c->format()->width(
' ' );
04373 }
04374
04375
if ( xmax < x + toAdd + ww ) xmax = x + toAdd + ww;
04376 x += ww;
04377 pos++;
04378 }
04379 }
04380 text->at( r->start + start ).startOfRun = TRUE;
04381 r = runs->next();
04382 }
04383
04384 line->w = xmax + 10;
04385 KoTextParagLineStart *ls =
new KoTextParagLineStart( control->context, control->status );
04386
delete control;
04387
delete runs;
04388
return ls;
04389 }
04390
04391
bool KoTextFormatterBase::isStretchable( KoTextString *string,
int pos )
const
04392
{
04393
if ( string->at( pos ).c ==
QChar(160) )
04394
return true;
04395 KoTextStringChar& chr = string->at( pos );
04396
return chr.whiteSpace;
04397
04398 }
04399
04400
bool KoTextFormatterBase::isBreakable( KoTextString *string,
int pos )
const
04401
{
04402
04403
04404
return (pos < string->length()-1 && string->at(pos+1).softBreak);
04405
04406
#if 0
04407
const QChar &c = string->at(pos).c;
04408
if ( c.isSpace() && c.unicode() !=
'\n' && c.unicode() != 0x00a0U )
04409
return TRUE;
04410
if ( c ==
'-' || c.unicode() == 0xad )
04411
return TRUE;
04412
if ( !ch ) {
04413
04414 uchar row = c.row();
04415
if ( row == 0x0e ) {
04416
04417
if ( c.cell() < 0x80 ) {
04418
#ifdef HAVE_THAI_BREAKS
04419
04420
if( string != cachedString ) {
04421
04422
QTextCodec *thaiCodec = QTextCodec::codecForMib(2259);
04423
if ( !thaiCache )
04424 thaiCache =
new QCString;
04425
if ( !thaiIt )
04426 thaiIt = ThBreakIterator::createWordInstance();
04427 *thaiCache = thaiCodec->fromUnicode( s->string() );
04428 }
04429 thaiIt->setText(thaiCache->data());
04430
for(
int i = thaiIt->first(); i != thaiIt->DONE; i = thaiIt->next() ) {
04431
if( i == pos )
04432
return TRUE;
04433
if( i > pos )
04434
return FALSE;
04435 }
04436
return FALSE;
04437
#else
04438
04439
04440
return TRUE;
04441
#endif
04442
}
else
04443
return FALSE;
04444 }
04445
if ( row < 0x11 )
04446
return FALSE;
04447
if ( row > 0x2d && row < 0xfb || row == 0x11 )
04448
04449
04450
return TRUE;
04451 }
04452
return FALSE;
04453
#endif
04454
}
04455
04456
void KoTextParag::insertLineStart(
int index, KoTextParagLineStart *ls )
04457 {
04458
04459
04460
04461
04462
#ifndef NDEBUG
04463
QMap<int, KoTextParagLineStart*>::Iterator it;
04464
if ( ( it = lineStarts.find( index ) ) == lineStarts.end() ) {
04465 lineStarts.insert( index, ls );
04466 }
else {
04467 kdWarning(32500) <<
"insertLineStart: there's already a line for char index=" << index << endl;
04468
delete *it;
04469 lineStarts.remove( it );
04470 lineStarts.insert( index, ls );
04471 }
04472
#else // non-debug code, take the fast route
04473
lineStarts.insert( index, ls );
04474
#endif
04475
}
04476
04477
04478
04479
04480
04481
int KoTextFormatterBase::formatVertically( KoTextDocument* doc, KoTextParag* parag )
04482 {
04483
int oldHeight = parag->rect().height();
04484
QMap<int, KoTextParagLineStart*>& lineStarts = parag->lineStartList();
04485
QMap<int, KoTextParagLineStart*>::Iterator it = lineStarts.begin();
04486
int h = doc->addMargins() ? parag->topMargin() : 0;
04487
for ( ; it != lineStarts.end() ; ++it ) {
04488 KoTextParagLineStart * ls = it.data();
04489 ls->y = h;
04490 KoTextStringChar *c = ¶g->string()->at(it.key());
04491
if ( c && c->customItem() && c->customItem()->ownLine() ) {
04492
int h = c->customItem()->height;
04493 c->customItem()->pageBreak( parag->rect().y() + ls->y + ls->baseLine - h, doc->flow() );
04494
int delta = c->customItem()->height - h;
04495 ls->h += delta;
04496
if ( delta )
04497 parag->setMovedDown( TRUE );
04498 }
else {
04499
int shift = doc->flow()->adjustFlow( parag->rect().y() + ls->y, ls->w, ls->h );
04500 ls->y += shift;
04501
if ( shift )
04502 parag->setMovedDown( TRUE );
04503 }
04504 h = ls->y + ls->h;
04505 }
04506
int m = parag->bottomMargin();
04507
if ( parag->next() && doc && !doc->addMargins() )
04508 m = QMAX( m, parag->next()->topMargin() );
04509
04510
04511 h += m;
04512 parag->setHeight( h );
04513
return h - oldHeight;
04514 }
04515
04516
04517
04518 KoTextIndent::KoTextIndent()
04519 {
04520 }
04521
04522
04523
04524 KoTextCustomItem::KoTextCustomItem( KoTextDocument *p )
04525 : width(-1), height(0), parent(p), xpos(0), ypos(-1), parag(0)
04526 {
04527 m_deleted =
false;
04528 }
04529
04530 KoTextCustomItem::~KoTextCustomItem()
04531 {
04532 }
04533
04534 KoTextFlow::KoTextFlow()
04535 {
04536 w = 0;
04537 leftItems.setAutoDelete( FALSE );
04538 rightItems.setAutoDelete( FALSE );
04539 }
04540
04541 KoTextFlow::~KoTextFlow()
04542 {
04543 }
04544
04545
void KoTextFlow::clear()
04546 {
04547 leftItems.clear();
04548 rightItems.clear();
04549 }
04550
04551
04552
void KoTextFlow::setWidth(
int width )
04553 {
04554 w = width;
04555 }
04556
04557
void KoTextFlow::adjustMargins(
int,
int,
int,
int&,
int&,
int& pageWidth, KoTextParag* )
04558 {
04559 pageWidth = w;
04560 }
04561
04562
#if 0
04563
int KoTextFlow::adjustLMargin(
int yp,
int,
int margin,
int space, KoTextParag* )
04564 {
04565
for ( KoTextCustomItem* item = leftItems.first(); item; item = leftItems.next() ) {
04566
if ( item->y() == -1 )
04567
continue;
04568
if ( yp >= item->y() && yp < item->y() + item->height )
04569 margin = QMAX( margin, item->x() + item->width + space );
04570 }
04571
return margin;
04572 }
04573
04574
int KoTextFlow::adjustRMargin(
int yp,
int,
int margin,
int space, KoTextParag* )
04575 {
04576
for ( KoTextCustomItem* item = rightItems.first(); item; item = rightItems.next() ) {
04577
if ( item->y() == -1 )
04578
continue;
04579
if ( yp >= item->y() && yp < item->y() + item->height )
04580 margin = QMAX( margin, w - item->x() - space );
04581 }
04582
return margin;
04583 }
04584
#endif
04585
04586
int KoTextFlow::adjustFlow(
int ,
int,
int )
04587 {
04588
#if 0
04589
if ( pagesize > 0 ) {
04590
int yinpage = y % pagesize;
04591
if ( yinpage <= 2 )
04592
return 2 - yinpage;
04593
else
04594
if ( yinpage + h > pagesize - 2 )
04595
return ( pagesize - yinpage ) + 2;
04596 }
04597
#endif
04598
return 0;
04599 }
04600
04601
void KoTextFlow::unregisterFloatingItem( KoTextCustomItem* item )
04602 {
04603 leftItems.removeRef( item );
04604 rightItems.removeRef( item );
04605 }
04606
04607
void KoTextFlow::registerFloatingItem( KoTextCustomItem* item )
04608 {
04609
if ( item->placement() == KoTextCustomItem::PlaceRight ) {
04610
if ( !rightItems.contains( item ) )
04611 rightItems.append( item );
04612 }
else if ( item->placement() == KoTextCustomItem::PlaceLeft &&
04613 !leftItems.contains( item ) ) {
04614 leftItems.append( item );
04615 }
04616 }
04617
04618
#if 0
04619
QRect KoTextFlow::boundingRect()
const
04620
{
04621 QRect br;
04622
QPtrListIterator<KoTextCustomItem> l( leftItems );
04623
while( l.current() ) {
04624 br = br.unite( l.current()->geometry() );
04625 ++l;
04626 }
04627
QPtrListIterator<KoTextCustomItem> r( rightItems );
04628
while( r.current() ) {
04629 br = br.unite( r.current()->geometry() );
04630 ++r;
04631 }
04632
return br;
04633 }
04634
#endif
04635
04636
int KoTextFlow::availableHeight()
const
04637
{
04638
return -1;
04639 }
04640
04641
void KoTextFlow::drawFloatingItems(
QPainter* p,
int cx,
int cy,
int cw,
int ch,
const QColorGroup& cg,
bool selected )
04642 {
04643 KoTextCustomItem *item;
04644
for ( item = leftItems.first(); item; item = leftItems.next() ) {
04645
if ( item->x() == -1 || item->y() == -1 )
04646
continue;
04647 item->draw( p, item->x(), item->y(), cx, cy, cw, ch, cg, selected );
04648 }
04649
04650
for ( item = rightItems.first(); item; item = rightItems.next() ) {
04651
if ( item->x() == -1 || item->y() == -1 )
04652
continue;
04653 item->draw( p, item->x(), item->y(), cx, cy, cw, ch, cg, selected );
04654 }
04655 }
04656
04657
04658
bool KoTextFlow::isEmpty() {
return leftItems.isEmpty() && rightItems.isEmpty(); }
04659