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