36#include "KoRichText.h"
37#include "KoTextFormat.h"
38#include "KoTextParag.h"
40#include <tqpaintdevicemetrics.h>
41#include "tqdrawutil.h"
44#include "KoParagCounter.h"
45#include "KoTextDocument.h"
49#include <tqtextengine_p.h>
58void KoTextDocCommandHistory::addCommand( KoTextDocCommand *cmd )
60 if ( current < (
int)history.count() - 1 ) {
61 TQPtrList<KoTextDocCommand> commands;
62 commands.setAutoDelete(
false );
64 for(
int i = 0; i <= current; ++i ) {
65 commands.insert( i, history.at( 0 ) );
69 commands.append( cmd );
72 history.setAutoDelete(
true );
74 history.append( cmd );
77 if ( (
int)history.count() > steps )
78 history.removeFirst();
83KoTextCursor *KoTextDocCommandHistory::undo( KoTextCursor *c )
86 KoTextCursor *c2 = history.at( current )->unexecute( c );
93KoTextCursor *KoTextDocCommandHistory::redo( KoTextCursor *c )
96 if ( current < (
int)history.count() - 1 ) {
98 return history.at( current )->execute( c );
101 if ( history.count() > 0 ) {
103 return history.at( current )->execute( c );
109bool KoTextDocCommandHistory::isUndoAvailable()
114bool KoTextDocCommandHistory::isRedoAvailable()
116 return current > -1 && current < (int)history.count() - 1 || current == -1 && history.count() > 0;
121KoTextDocDeleteCommand::KoTextDocDeleteCommand( KoTextDocument *d,
int i,
int idx,
const TQMemArray<KoTextStringChar> &str )
122 : KoTextDocCommand( d ), id( i ), index( idx ), parag( 0 ), text( str )
124 for (
int j = 0; j < (int)text.size(); ++j ) {
125 if ( text[ j ].format() )
126 text[ j ].format()->addRef();
139KoTextDocDeleteCommand::~KoTextDocDeleteCommand()
141 for (
int i = 0; i < (int)text.size(); ++i ) {
142 if ( text[ i ].format() )
143 text[ i ].format()->removeRef();
148KoTextCursor *KoTextDocDeleteCommand::execute( KoTextCursor *c )
150 KoTextParag *s = doc ? doc->paragAt(
id ) : parag;
153 kdWarning(32500) <<
"can't locate parag at " <<
id <<
", last parag: " << doc->lastParag()->paragId() << endl;
157 cursor.setParag( s );
158 cursor.setIndex( index );
159 int len = text.size();
163 doc->setSelectionStart( KoTextDocument::Temp, &cursor );
164 for (
int i = 0; i < len; ++i )
165 cursor.gotoNextLetter();
166 doc->setSelectionEnd( KoTextDocument::Temp, &cursor );
167 doc->removeSelectedText( KoTextDocument::Temp, &cursor );
171 s->remove( index, len );
177KoTextCursor *KoTextDocDeleteCommand::unexecute( KoTextCursor *c )
179 KoTextParag *s = doc ? doc->paragAt(
id ) : parag;
182 kdWarning(32500) <<
"can't locate parag at " <<
id <<
", last parag: " << doc->lastParag()->paragId() << endl;
186 cursor.setParag( s );
187 cursor.setIndex( index );
188 TQString str = KoTextString::toString( text );
189 cursor.insert( str,
true, &text );
190 cursor.setParag( s );
191 cursor.setIndex( index );
194 c->setIndex( index );
195 for (
int i = 0; i < (int)text.size(); ++i )
202 s->setChanged(
true );
203 if ( c && s == c->parag() )
211KoTextDocFormatCommand::KoTextDocFormatCommand( KoTextDocument *d,
int sid,
int sidx,
int eid,
int eidx,
212 const TQMemArray<KoTextStringChar> &old,
const KoTextFormat *f,
int fl )
213 : KoTextDocCommand( d ), startId( sid ), startIndex( sidx ), endId( eid ), endIndex( eidx ), oldFormats( old ), flags( fl )
215 format = d->formatCollection()->format( f );
216 for (
int j = 0; j < (int)oldFormats.size(); ++j ) {
217 if ( oldFormats[ j ].format() )
218 oldFormats[ j ].format()->addRef();
222KoTextDocFormatCommand::~KoTextDocFormatCommand()
225 for (
int j = 0; j < (int)oldFormats.size(); ++j ) {
226 if ( oldFormats[ j ].format() )
227 oldFormats[ j ].format()->removeRef();
231KoTextCursor *KoTextDocFormatCommand::execute( KoTextCursor *c )
233 KoTextParag *sp = doc->paragAt( startId );
234 KoTextParag *ep = doc->paragAt( endId );
238 KoTextCursor start( doc );
239 start.setParag( sp );
240 start.setIndex( startIndex );
241 KoTextCursor end( doc );
243 end.setIndex( endIndex );
245 doc->setSelectionStart( KoTextDocument::Temp, &start );
246 doc->setSelectionEnd( KoTextDocument::Temp, &end );
247 doc->setFormat( KoTextDocument::Temp, format, flags );
248 doc->removeSelection( KoTextDocument::Temp );
249 if ( endIndex == ep->length() )
255KoTextCursor *KoTextDocFormatCommand::unexecute( KoTextCursor *c )
257 KoTextParag *sp = doc->paragAt( startId );
258 KoTextParag *ep = doc->paragAt( endId );
262 int idx = startIndex;
264 if( !oldFormats.isEmpty())
267 if ( oldFormats.at( fIndex ).c ==
'\n' ) {
269 if ( idx < sp->length() && fIndex > 0 )
270 sp->setFormat( idx, 1, oldFormats.at( fIndex - 1 ).format() );
278 if ( oldFormats.at( fIndex ).format() )
279 sp->setFormat( idx, 1, oldFormats.at( fIndex ).format() );
282 if ( fIndex >= (
int)oldFormats.size() )
284 if ( idx >= sp->length() ) {
292 KoTextCursor end( doc );
294 end.setIndex( endIndex );
295 if ( endIndex == ep->length() )
301KoTextAlignmentCommand::KoTextAlignmentCommand( KoTextDocument *d,
int fParag,
int lParag,
int na,
const TQMemArray<int> &oa )
302 : KoTextDocCommand( d ), firstParag( fParag ), lastParag( lParag ), newAlign( na ), oldAligns( oa )
306KoTextCursor *KoTextAlignmentCommand::execute( KoTextCursor *c )
308 KoTextParag *p = doc->paragAt( firstParag );
312 p->setAlignment( newAlign );
313 if ( p->paragId() == lastParag )
320KoTextCursor *KoTextAlignmentCommand::unexecute( KoTextCursor *c )
322 KoTextParag *p = doc->paragAt( firstParag );
327 if ( i < (
int)oldAligns.size() )
328 p->setAlignment( oldAligns.at( i ) );
329 if ( p->paragId() == lastParag )
340KoTextCursor::KoTextCursor( KoTextDocument *d )
344 string = doc ? doc->firstParag() : 0;
348KoTextCursor::KoTextCursor()
352KoTextCursor::KoTextCursor(
const KoTextCursor &c )
357 tmpIndex = c.tmpIndex;
360KoTextCursor &KoTextCursor::operator=(
const KoTextCursor &c )
365 tmpIndex = c.tmpIndex;
370bool KoTextCursor::operator==(
const KoTextCursor &c )
const
372 return doc == c.doc &&
string == c.string && idx == c.idx;
375void KoTextCursor::insert(
const TQString &str,
bool checkNewLine, TQMemArray<KoTextStringChar> *formatting )
377 string->invalidate( idx );
379 bool justInsert =
true;
381#if defined(TQ_WS_WIN)
383 s = s.replace( TQRegExp(
"\\r" ),
"" );
386 justInsert = s.find(
'\n' ) == -1;
388 string->insert( idx, s );
390 for (
int i = 0; i < (int)s.length(); ++i ) {
391 if ( formatting->at( i ).format() ) {
392 formatting->at( i ).format()->addRef();
393 string->string()->setFormat( idx + i, formatting->at( i ).format(),
true );
399 TQStringList lst = TQStringList::split(
'\n', s,
true );
400 TQStringList::Iterator it = lst.begin();
403 KoTextFormat *lastFormat = 0;
404 for ( ; it != lst.end(); ) {
405 if ( it != lst.begin() ) {
406 splitAndInsertEmptyParag(
false,
true );
409 string->prev()->format( -1,
false );
411 if ( lastFormat && formatting && string->prev() ) {
412 lastFormat->addRef();
413 string->prev()->string()->setFormat( string->prev()->length() - 1, lastFormat,
true );
420 string->insert( idx, s );
422 string->invalidate( 0 );
425 int len = s.length();
426 for (
int i = 0; i < len; ++i ) {
427 if ( formatting->at( i + lastIndex ).format() ) {
428 formatting->at( i + lastIndex ).format()->addRef();
429 string->string()->setFormat( i + idx, formatting->at( i + lastIndex ).format(),
true );
432 if ( it != lst.end() )
433 lastFormat = formatting->at( len + lastIndex ).format();
441 string->format( -1,
false );
442 int dy =
string->rect().y() +
string->rect().height() - y;
444 KoTextParag *p = string;
445 p->setParagId( p->prev()->paragId() + 1 );
448 p->setParagId( p->prev()->paragId() + 1 );
456 int h =
string->rect().height();
457 string->format( -1,
true );
462void KoTextCursor::gotoLeft()
464 if ( string->string()->isRightToLeft() )
467 gotoPreviousLetter();
470void KoTextCursor::gotoPreviousLetter()
475 idx =
string->string()->previousCursorPosition( idx );
476 }
else if ( string->prev() ) {
477 string =
string->prev();
478 while ( !string->isVisible() )
479 string =
string->prev();
480 idx =
string->length() - 1;
484bool KoTextCursor::place(
const TQPoint &p, KoTextParag *s,
bool link,
int *customItemIndex )
486 if ( customItemIndex )
487 *customItemIndex = -1;
490 if ( pos.y() < s->rect().y() )
491 pos.setY( s->rect().y() );
494 r.setWidth( doc ? doc->width() : TQWIDGETSIZE_MAX );
495 if ( !s->next() || ( pos.y() >= r.y() && pos.y() < s->next()->rect().y() ) )
503 setParag( s,
false );
504 int y = s->rect().y();
505 int lines = s->lines();
506 KoTextStringChar *chr = 0;
511 for ( ; i < lines; ++i ) {
512 chr = s->lineStartOfLine( i, &index );
517 if ( i < lines - 1 && pos.y() >= y + cy && pos.y() <= y + s->lineY( i+1 ) )
522 s->lineStartOfLine( i+1, &nextLine );
524 nextLine = s->length();
526 int x = s->rect().x();
530 int curpos = s->length()-1;
532 while ( i < nextLine ) {
534 int cpos = x + chr->x;
536 if ( chr->isCustom() ) {
537 if ( pos.x() >= cpos && pos.x() <= cpos + cw &&
538 pos.y() >= y + cy && pos.y() <= y + cy + chr->height() ) {
539 if ( customItemIndex )
540 *customItemIndex = i;
543 if( chr->rightToLeft )
545 int d = cpos - pos.x();
546 bool dm = d < 0 ? !chr->rightToLeft : chr->rightToLeft;
547 if ( (TQABS( d ) < dist || (dist == d && dm ==
true )) && string->string()->validCursorPosition( i ) ) {
549 if ( !link || pos.x() >= x + chr->x ) {
555 setIndex( curpos,
false );
560void KoTextCursor::gotoRight()
562 if ( string->string()->isRightToLeft() )
563 gotoPreviousLetter();
568void KoTextCursor::gotoNextLetter()
572 int len =
string->length() - 1;
574 idx =
string->string()->nextCursorPosition( idx );
575 }
else if ( string->next() ) {
576 string =
string->next();
577 while ( !string->isVisible() )
578 string =
string->next();
583void KoTextCursor::gotoUp()
585 int indexOfLineStart;
587 KoTextStringChar *c =
string->lineStartOfChar( idx, &indexOfLineStart, &line );
591 tmpIndex = TQMAX( tmpIndex, idx - indexOfLineStart );
592 if ( indexOfLineStart == 0 ) {
593 if ( !string->prev() ) {
596 string =
string->prev();
597 while ( !string->isVisible() )
598 string =
string->prev();
599 int lastLine =
string->lines() - 1;
600 if ( !string->lineStartOfLine( lastLine, &indexOfLineStart ) )
602 if ( indexOfLineStart + tmpIndex < string->length() )
603 idx = indexOfLineStart + tmpIndex;
605 idx =
string->length() - 1;
608 int oldIndexOfLineStart = indexOfLineStart;
609 if ( !string->lineStartOfLine( line, &indexOfLineStart ) )
611 if ( indexOfLineStart + tmpIndex < oldIndexOfLineStart )
612 idx = indexOfLineStart + tmpIndex;
614 idx = oldIndexOfLineStart - 1;
619void KoTextCursor::gotoDown()
621 int indexOfLineStart;
623 KoTextStringChar *c =
string->lineStartOfChar( idx, &indexOfLineStart, &line );
627 tmpIndex = TQMAX( tmpIndex, idx - indexOfLineStart );
628 if ( line == string->lines() - 1 ) {
629 if ( !string->next() ) {
632 string =
string->next();
633 while ( !string->isVisible() )
634 string =
string->next();
635 if ( !string->lineStartOfLine( 0, &indexOfLineStart ) )
638 if ( string->lines() == 1 )
639 end =
string->length();
641 string->lineStartOfLine( 1, &end );
642 if ( indexOfLineStart + tmpIndex < end )
643 idx = indexOfLineStart + tmpIndex;
649 if ( line == string->lines() - 1 )
650 end =
string->length();
652 string->lineStartOfLine( line + 1, &end );
653 if ( !string->lineStartOfLine( line, &indexOfLineStart ) )
655 if ( indexOfLineStart + tmpIndex < end )
656 idx = indexOfLineStart + tmpIndex;
663void KoTextCursor::gotoLineEnd()
666 int indexOfLineStart;
668 KoTextStringChar *c =
string->lineStartOfChar( idx, &indexOfLineStart, &line );
672 if ( line == string->lines() - 1 ) {
673 idx =
string->length() - 1;
675 c =
string->lineStartOfLine( ++line, &indexOfLineStart );
677 idx = indexOfLineStart;
681void KoTextCursor::gotoLineStart()
684 int indexOfLineStart;
686 KoTextStringChar *c =
string->lineStartOfChar( idx, &indexOfLineStart, &line );
690 idx = indexOfLineStart;
693void KoTextCursor::gotoHome()
697 string = doc->firstParag();
701void KoTextCursor::gotoEnd()
713 string = doc->lastParag();
714 idx =
string->length() - 1;
717void KoTextCursor::gotoPageUp(
int visibleHeight )
720 KoTextParag *s = string;
721 int h = visibleHeight;
722 int y = s->rect().y();
724 if ( y - s->rect().y() >= h )
730 s = doc->firstParag();
736void KoTextCursor::gotoPageDown(
int visibleHeight )
739 KoTextParag *s = string;
740 int h = visibleHeight;
741 int y = s->rect().y();
743 if ( s->rect().y() - y >= h )
749 s = doc->lastParag();
751 idx =
string->length() - 1;
762void KoTextCursor::gotoWordRight()
764 if ( string->string()->isRightToLeft() )
770void KoTextCursor::gotoWordLeft()
772 if ( string->string()->isRightToLeft() )
778void KoTextCursor::gotoPreviousWord()
780 gotoPreviousLetter();
782 KoTextString *s =
string->string();
783 bool allowSame =
false;
784 if ( idx == ( (
int)s->length()-1 ) )
786 for (
int i = idx; i >= 0; --i ) {
787 if ( s->at( i ).c.isSpace() || s->at( i ).c ==
'\t' || s->at( i ).c ==
'.' ||
788 s->at( i ).c ==
',' || s->at( i ).c ==
':' || s->at( i ).c ==
';' ) {
794 if ( !allowSame && !( s->at( i ).c.isSpace() || s->at( i ).c ==
'\t' || s->at( i ).c ==
'.' ||
795 s->at( i ).c ==
',' || s->at( i ).c ==
':' || s->at( i ).c ==
';' ) )
801void KoTextCursor::gotoNextWord()
804 KoTextString *s =
string->string();
805 bool allowSame =
false;
806 for (
int i = idx; i < (int)s->length(); ++i ) {
807 if ( ! ( s->at( i ).c.isSpace() || s->at( i ).c ==
'\t' || s->at( i ).c ==
'.' ||
808 s->at( i ).c ==
',' || s->at( i ).c ==
':' || s->at( i ).c ==
';' ) ) {
814 if ( !allowSame && ( s->at( i ).c.isSpace() || s->at( i ).c ==
'\t' || s->at( i ).c ==
'.' ||
815 s->at( i ).c ==
',' || s->at( i ).c ==
':' || s->at( i ).c ==
';' ) )
819 if ( idx < ((
int)s->length()-1) ) {
821 }
else if ( string->next() ) {
822 string =
string->next();
823 while ( !string->isVisible() )
824 string =
string->next();
831bool KoTextCursor::atParagStart()
const
836bool KoTextCursor::atParagEnd()
const
838 return idx ==
string->length() - 1;
841void KoTextCursor::splitAndInsertEmptyParag(
bool ind,
bool updateIds )
847 if ( doc->useFormatCollection() ) {
848 f =
string->at( idx )->format();
849 if ( idx == string->length() - 1 && idx > 0 )
850 f =
string->at( idx - 1 )->format();
851 if ( f->isMisspelled() ) {
852 KoTextFormat fNoMisspelled( *f );
853 fNoMisspelled.setMisspelled(
false );
854 f = doc->formatCollection()->format( &fNoMisspelled );
858 if ( atParagEnd() ) {
859 KoTextParag *n =
string->next();
860 KoTextParag *s = doc->createParag( doc,
string, n, updateIds );
862 s->setFormat( 0, 1, f,
true );
863 s->copyParagData(
string );
867 s->indent( &oi, &ni );
876 }
else if ( atParagStart() ) {
877 KoTextParag *p =
string->prev();
878 KoTextParag *s = doc->createParag( doc, p,
string, updateIds );
880 s->setFormat( 0, 1, f,
true );
881 s->copyParagData(
string );
889 TQString str =
string->string()->toString().mid( idx, 0xFFFFFF );
890 KoTextParag *n =
string->next();
891 KoTextParag *s = doc->createParag( doc,
string, n, updateIds );
892 s->copyParagData(
string );
894 s->append( str,
true );
895 for ( uint i = 0; i < str.length(); ++i ) {
896 KoTextStringChar* tsc =
string->at( idx + i );
897 s->setFormat( i, 1, tsc->format(),
true );
898 if ( tsc->isCustom() ) {
899 KoTextCustomItem * item = tsc->customItem();
900 s->at( i )->setCustomItem( item );
901 tsc->loseCustomItem();
904 string->removeCustomItem();
906 doc->unregisterCustomItem( item,
string );
907 doc->registerCustomItem( item, s );
910 string->truncate( idx );
914 s->indent( &oi, &ni );
926bool KoTextCursor::removePreviousChar()
929 if ( !atParagStart() ) {
930 string->remove( idx-1, 1 );
934 string->format( -1,
true );
938 }
else if ( string->prev() ) {
939 string =
string->prev();
940 string->join( string->next() );
941 string->invalidateCounters();
947bool KoTextCursor::remove()
950 if ( !atParagEnd() ) {
951 int next =
string->string()->nextCursorPosition( idx );
952 string->remove( idx, next-idx );
953 string->format( -1,
true );
957 }
else if ( string->next() ) {
958 if ( string->length() == 1 ) {
959 string->next()->setPrev( string->prev() );
960 if ( string->prev() )
961 string->prev()->setNext( string->next() );
962 KoTextParag *p =
string->next();
965 string->invalidate( 0 );
967 string->invalidateCounters();
969 KoTextParag *s = string;
971 s->id = s->p ? s->p->id + 1 : 0;
979 string->join( string->next() );
986void KoTextCursor::killLine()
990 string->remove( idx, string->length() - idx - 1 );
991 string->format( -1,
true );
997void KoTextCursor::indent()
1000 string->indent( &oi, &ni );
1011void KoTextCursor::setDocument( KoTextDocument *d )
1014 string = d->firstParag();
1020int KoTextCursor::x()
const
1022 KoTextStringChar *c =
string->at( idx );
1024 if ( c->rightToLeft )
1029int KoTextCursor::y()
const
1032 string->lineStartOfChar( idx, &dummy, &line );
1033 return string->lineY( line );
1037void KoTextCursor::fixCursorPosition()
1040 if ( string->string()->validCursorPosition( idx ) )
1044 KoTextStringChar *start =
string->lineStartOfChar( idx, &lineIdx, 0 );
1045 int x =
string->string()->at( idx ).x;
1046 int diff = TQABS(start->x - x);
1049 KoTextStringChar *c = start;
1052 KoTextStringChar *end = &
string->string()->at( string->length()-1 );
1053 while ( c <= end && !c->lineStart ) {
1055 if ( c->rightToLeft )
1056 xp += c->pixelwidth;
1057 int ndiff = TQABS(xp - x);
1058 if ( ndiff < diff && string->
string()->validCursorPosition(lineIdx + (c-start)) ) {
1060 best = lineIdx + (c-start);
1069KoTextString::KoTextString()
1072 bNeedsSpellCheck =
true;
1074 rightToLeft =
false;
1075 dir = TQChar::DirON;
1078KoTextString::KoTextString(
const KoTextString &s )
1080 bidiDirty = s.bidiDirty;
1081 bNeedsSpellCheck = s.bNeedsSpellCheck;
1083 rightToLeft = s.rightToLeft;
1087 for (
int i = 0; i < (int)data.size(); ++i ) {
1088 KoTextFormat *f = data[i].format();
1094void KoTextString::insert(
int index,
const TQString &s,
KoTextFormat *f )
1096 int os = data.size();
1097 data.resize( data.size() + s.length() );
1099 memmove( data.data() + index + s.length(), data.data() + index,
1100 sizeof( KoTextStringChar ) * ( os - index ) );
1102 for (
int i = 0; i < (int)s.length(); ++i ) {
1103 KoTextStringChar &ch = data[ (int)index + i ];
1110 ch.type = KoTextStringChar::Regular;
1114#ifdef DEBUG_COLLECTION
1115 kdDebug(32500) <<
"KoTextString::insert setting format " << f <<
" to character " << (int)index+i << endl;
1120 bNeedsSpellCheck =
true;
1123KoTextString::~KoTextString()
1128void KoTextString::insert(
int index, KoTextStringChar *c )
1130 int os = data.size();
1131 data.resize( data.size() + 1 );
1133 memmove( data.data() + index + 1, data.data() + index,
1134 sizeof( KoTextStringChar ) * ( os - index ) );
1136 KoTextStringChar &ch = data[ (int)index ];
1145 ch.type = KoTextStringChar::Regular;
1146 ch.setFormat( c->format() );
1148 bNeedsSpellCheck =
true;
1151void KoTextString::truncate(
int index )
1153 index = TQMAX( index, 0 );
1154 index = TQMIN( index, (
int)data.size() - 1 );
1155 if ( index < (
int)data.size() ) {
1156 for (
int i = index + 1; i < (int)data.size(); ++i ) {
1157 KoTextStringChar &ch = data[ i ];
1158 if ( ch.isCustom() ) {
1159 delete ch.customItem();
1160 if ( ch.d.custom->format )
1161 ch.d.custom->format->removeRef();
1164 }
else if ( ch.format() ) {
1165 ch.format()->removeRef();
1169 data.truncate( index );
1171 bNeedsSpellCheck =
true;
1174void KoTextString::remove(
int index,
int len )
1176 for (
int i = index; i < (int)data.size() && i - index < len; ++i ) {
1177 KoTextStringChar &ch = data[ i ];
1178 if ( ch.isCustom() ) {
1179 delete ch.customItem();
1180 if ( ch.d.custom->format )
1181 ch.d.custom->format->removeRef();
1184 }
else if ( ch.format() ) {
1185 ch.format()->removeRef();
1188 memmove( data.data() + index, data.data() + index + len,
1189 sizeof( KoTextStringChar ) * ( data.size() - index - len ) );
1190 data.resize( data.size() - len, TQGArray::SpeedOptim );
1192 bNeedsSpellCheck =
true;
1195void KoTextString::clear()
1197 for (
int i = 0; i < (int)data.count(); ++i ) {
1198 KoTextStringChar &ch = data[ i ];
1199 if ( ch.isCustom() ) {
1206 delete ch.customItem();
1207 if ( ch.d.custom->format )
1208 ch.d.custom->format->removeRef();
1212 }
else if ( ch.format() ) {
1213 ch.format()->removeRef();
1219void KoTextString::setFormat(
int index,
KoTextFormat *f,
bool useCollection,
bool setFormatAgain )
1221 KoTextStringChar &ch = data[ index ];
1223 if ( useCollection && ch.format() )
1226 ch.format()->removeRef();
1228 ch.setFormat( f, setFormatAgain );
1231void KoTextString::checkBidi()
const
1233 KoTextString *that = (KoTextString *)
this;
1234 that->bidiDirty =
false;
1235 int length = data.size();
1238 that->rightToLeft = dir == TQChar::DirR;
1241 const KoTextStringChar *start = data.data();
1242 const KoTextStringChar *end = start + length;
1245 TQTextEngine textEngine( toString(), 0 );
1246 textEngine.direction = (TQChar::Direction) dir;
1247 textEngine.itemize(TQTextEngine::SingleLine);
1248 const TQCharAttributes *ca = textEngine.attributes() + length-1;
1249 KoTextStringChar *ch = (KoTextStringChar *)end - 1;
1250 TQScriptItem *item = &textEngine.items[textEngine.items.size()-1];
1251 unsigned char bidiLevel = item->analysis.bidiLevel;
1255 while ( ch >= start ) {
1256 if ( item->position > pos ) {
1258 Q_ASSERT( item >= &textEngine.items[0] );
1259 Q_ASSERT( item < &textEngine.items[textEngine.items.size()] );
1260 bidiLevel = item->analysis.bidiLevel;
1264 ch->softBreak = ca->softBreak;
1265 ch->whiteSpace = ca->whiteSpace;
1266 ch->charStop = ca->charStop;
1267 ch->wordStop = ca->wordStop;
1269 ch->rightToLeft = (bidiLevel%2);
1275 if ( dir == TQChar::DirR ) {
1277 that->rightToLeft =
true;
1278 }
else if ( dir == TQChar::DirL ) {
1279 that->rightToLeft =
false;
1281 that->rightToLeft = (textEngine.direction == TQChar::DirR);
1285TQMemArray<KoTextStringChar> KoTextString::subString(
int start,
int len )
const
1287 if ( len == 0xFFFFFF )
1289 TQMemArray<KoTextStringChar> a;
1291 for (
int i = 0; i < len; ++i ) {
1292 KoTextStringChar *c = &data[ i + start ];
1295 a[ i ].pixelxadj = 0;
1296 a[ i ].pixelwidth = 0;
1298 a[ i ].lineStart = 0;
1299 a[ i ].rightToLeft = 0;
1300 a[ i ].d.format = 0;
1301 a[ i ].type = KoTextStringChar::Regular;
1302 a[ i ].setFormat( c->format() );
1304 c->format()->addRef();
1309TQString KoTextString::mid(
int start,
int len )
const
1311 if ( len == 0xFFFFFF )
1314 res.setLength( len );
1315 for (
int i = 0; i < len; ++i ) {
1316 KoTextStringChar *c = &data[ i + start ];
1322TQString KoTextString::toString(
const TQMemArray<KoTextStringChar> &data )
1325 int l = data.size();
1326 s.setUnicode( 0, l );
1327 KoTextStringChar *c = data.data();
1328 TQChar *uc = (TQChar *)s.unicode();
1338TQString KoTextString::toReverseString()
const
1343 KoTextStringChar *c = data.data() + (l-1);
1344 TQChar *uc = (TQChar *)s.unicode();
1354TQString KoTextString::stringToSpellCheck()
1356 if ( !bNeedsSpellCheck )
1359 bNeedsSpellCheck =
false;
1360 if ( length() <= 1 )
1363 TQString str = toString();
1364 str.truncate( str.length() - 1 );
1368int KoTextString::nextCursorPosition(
int next )
1373 const KoTextStringChar *c = data.data();
1376 if ( next < len - 1 ) {
1378 while ( next < len - 1 && !c[next].charStop )
1384int KoTextString::previousCursorPosition(
int prev )
1389 const KoTextStringChar *c = data.data();
1393 while ( prev && !c[prev].charStop )
1399bool KoTextString::validCursorPosition(
int idx )
1404 return (at( idx ).charStop);
1409void KoTextStringChar::setFormat(
KoTextFormat *f,
bool setFormatAgain )
1411 if ( type == Regular ) {
1415 d.custom =
new CustomData;
1416 d.custom->custom = 0;
1418 d.custom->format = f;
1419 if ( d.custom->custom && setFormatAgain )
1420 d.custom->custom->setFormat( f );
1426 if ( type == Regular ) {
1427 KoTextFormat *f = format();
1428 d.custom =
new CustomData;
1429 d.custom->format = f;
1432 delete d.custom->custom;
1434 d.custom->custom = i;
1437void KoTextStringChar::loseCustomItem()
1440 KoTextFormat *f = d.custom->format;
1441 d.custom->custom = 0;
1448KoTextStringChar::~KoTextStringChar()
1451 format()->removeRef();
1454 delete d.custom;
break;
1460int KoTextStringChar::height()
const
1462 return !isCustom() ? format()->height() : ( customItem()->placement() == KoTextCustomItem::PlaceInline ? customItem()->height : 0 );
1465int KoTextStringChar::ascent()
const
1467 return !isCustom() ? format()->ascent() : ( customItem()->placement() == KoTextCustomItem::PlaceInline ? customItem()->ascent() : 0 );
1470int KoTextStringChar::descent()
const
1472 return !isCustom() ? format()->descent() : 0;
1477KoTextFormatterBase::KoTextFormatterBase()
1479 m_bViewFormattingChars( false ),
1489KoTextParagLineStart *KoTextFormatterBase::bidiReorderLine( KoTextParag * , KoTextString *text, KoTextParagLineStart *line,
1490 KoTextStringChar *startChar, KoTextStringChar *lastChar,
int align,
int space )
1492 int start = (startChar - &text->at(0));
1493 int last = (lastChar - &text->at(0) );
1496 KoBidiControl *control =
new KoBidiControl( line->context(), line->status );
1498 str.setUnicode( 0, last - start + 1 );
1500 KoTextStringChar *ch = startChar;
1501 TQChar *qch = (TQChar *)str.unicode();
1502 while ( ch <= lastChar ) {
1507 int x = startChar->x;
1509 TQPtrList<KoTextRun> *runs;
1510 runs = KoComplexText::bidiReorderLine(control, str, 0, last - start + 1,
1511 (text->isRightToLeft() ? TQChar::DirR : TQChar::DirL) );
1517 if( align == TQt::AlignAuto ) {
1519 if ( text->isRightToLeft() )
1520 align = TQt::AlignRight;
1523 if ( align & TQt::AlignHCenter )
1525 else if ( align & TQt::AlignRight )
1527 else if ( align & TQt::AlignJustify ) {
1528 for (
int j = start; j < last; ++j ) {
1529 if( isBreakable( text, j ) ) {
1536 KoTextRun *r = runs->first();
1537 int xmax = -0xffffff;
1541 int pos = r->stop + start;
1542 while(pos >= r->start + start) {
1543 KoTextStringChar *c = &text->at(pos);
1544 if( numSpaces && !first && isBreakable( text, pos ) ) {
1545 int s = space / numSpaces;
1549 }
else if ( first ) {
1552 x -= c->format()->
width(
' ' );
1555 c->rightToLeft =
true;
1556 c->startOfRun =
false;
1558 if ( c->c.unicode() >= 32 || c->c ==
'\t' || c->c ==
'\n' || c->isCustom() ) {
1561 ww = c->format()->
width(
' ' );
1563 if ( xmax < x + toAdd + ww ) xmax = x + toAdd + ww;
1568 int pos = r->start + start;
1569 while(pos <= r->stop + start) {
1570 KoTextStringChar* c = &text->at(pos);
1571 if( numSpaces && !first && isBreakable( text, pos ) ) {
1572 int s = space / numSpaces;
1576 }
else if ( first ) {
1579 x -= c->format()->
width(
' ' );
1582 c->rightToLeft =
false;
1583 c->startOfRun =
false;
1585 if ( c->c.unicode() >= 32 || c->c ==
'\t' || c->isCustom() ) {
1588 ww = c->format()->
width(
' ' );
1591 if ( xmax < x + toAdd + ww ) xmax = x + toAdd + ww;
1596 text->at( r->start + start ).startOfRun =
true;
1600 line->w = xmax + 10;
1601 KoTextParagLineStart *ls =
new KoTextParagLineStart( control->context, control->status );
1607bool KoTextFormatterBase::isStretchable( KoTextString *
string,
int pos )
const
1609 if ( string->at( pos ).c == TQChar(160) )
1611 KoTextStringChar& chr =
string->at( pos );
1612 return chr.whiteSpace;
1616bool KoTextFormatterBase::isBreakable( KoTextString *
string,
int pos )
const
1620 return (pos < string->length()-1 && string->at(pos+1).softBreak);
1623void KoTextParag::insertLineStart(
int index, KoTextParagLineStart *ls )
1630 TQMap<int, KoTextParagLineStart*>::Iterator it;
1631 if ( ( it = lineStarts.find( index ) ) == lineStarts.end() ) {
1632 lineStarts.insert( index, ls );
1634 kdWarning(32500) <<
"insertLineStart: there's already a line for char index=" << index << endl;
1636 lineStarts.remove( it );
1637 lineStarts.insert( index, ls );
1640 lineStarts.insert( index, ls );
1648int KoTextFormatterBase::formatVertically( KoTextDocument* doc, KoTextParag* parag )
1650 int oldHeight = parag->rect().height();
1651 TQMap<int, KoTextParagLineStart*>& lineStarts = parag->lineStartList();
1652 TQMap<int, KoTextParagLineStart*>::Iterator it = lineStarts.begin();
1653 int h = doc->addMargins() ? parag->topMargin() : 0;
1654 for ( ; it != lineStarts.end() ; ++it ) {
1655 KoTextParagLineStart * ls = it.data();
1657 KoTextStringChar *c = ¶g->string()->at(it.key());
1658 if ( c && c->customItem() && c->customItem()->ownLine() ) {
1659 int h = c->customItem()->height;
1660 c->customItem()->pageBreak( parag->rect().y() + ls->y + ls->baseLine - h, doc->flow() );
1661 int delta = c->customItem()->height - h;
1664 parag->setMovedDown(
true );
1666 int shift = doc->flow()->adjustFlow( parag->rect().y() + ls->y, ls->w, ls->h );
1669 parag->setMovedDown(
true );
1673 int m = parag->bottomMargin();
1674 if ( parag->next() && doc && !doc->addMargins() )
1675 m = TQMAX( m, parag->next()->topMargin() );
1679 parag->setHeight( h );
1680 return h - oldHeight;
1685KoTextCustomItem::KoTextCustomItem( KoTextDocument *p )
1686 : width(-1), height(0), parent(p), xpos(0), ypos(-1), parag(0)
1691KoTextCustomItem::~KoTextCustomItem()
1695KoTextFlow::KoTextFlow()
1698 leftItems.setAutoDelete(
false );
1699 rightItems.setAutoDelete(
false );
1702KoTextFlow::~KoTextFlow()
1706void KoTextFlow::clear()
1713void KoTextFlow::setWidth(
int width )
1718void KoTextFlow::adjustMargins(
int,
int,
int,
int&,
int&,
int& pageWidth, KoTextParag* )
1724int KoTextFlow::adjustFlow(
int ,
int,
int )
1731 leftItems.removeRef( item );
1732 rightItems.removeRef( item );
1737 if ( item->placement() == KoTextCustomItem::PlaceRight ) {
1738 if ( !rightItems.contains( item ) )
1739 rightItems.append( item );
1740 }
else if ( item->placement() == KoTextCustomItem::PlaceLeft &&
1741 !leftItems.contains( item ) ) {
1742 leftItems.append( item );
1746int KoTextFlow::availableHeight()
const
1751void KoTextFlow::drawFloatingItems( TQPainter* p,
int cx,
int cy,
int cw,
int ch,
const TQColorGroup& cg,
bool selected )
1753 KoTextCustomItem *item;
1754 for ( item = leftItems.first(); item; item = leftItems.next() ) {
1755 if ( item->x() == -1 || item->y() == -1 )
1757 item->draw( p, item->x(), item->y(), cx, cy, cw, ch, cg, selected );
1760 for ( item = rightItems.first(); item; item = rightItems.next() ) {
1761 if ( item->x() == -1 || item->y() == -1 )
1763 item->draw( p, item->x(), item->y(), cx, cy, cw, ch, cg, selected );
1768bool KoTextFlow::isEmpty() {
return leftItems.isEmpty() && rightItems.isEmpty(); }
KoTextCustomItem is the base class for custom items (i.e.
Each character (KoTextStringChar) points to a KoTextFormat that defines the formatting of that charac...
int width(const TQChar &c) const
Return the width of one char (from a string, not necessarily from a paragraph) in LU pixels.
TDEAction * next(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)