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"
47#include <tdeversion.h>
50#include <tqtextengine_p.h>
59void KoTextDocCommandHistory::addCommand( KoTextDocCommand *cmd )
61 if ( current < (
int)history.count() - 1 ) {
62 TQPtrList<KoTextDocCommand> commands;
63 commands.setAutoDelete(
false );
65 for(
int i = 0; i <= current; ++i ) {
66 commands.insert( i, history.at( 0 ) );
70 commands.append( cmd );
73 history.setAutoDelete(
true );
75 history.append( cmd );
78 if ( (
int)history.count() > steps )
79 history.removeFirst();
84KoTextCursor *KoTextDocCommandHistory::undo( KoTextCursor *c )
87 KoTextCursor *c2 = history.at( current )->unexecute( c );
94KoTextCursor *KoTextDocCommandHistory::redo( KoTextCursor *c )
97 if ( current < (
int)history.count() - 1 ) {
99 return history.at( current )->execute( c );
102 if ( history.count() > 0 ) {
104 return history.at( current )->execute( c );
110bool KoTextDocCommandHistory::isUndoAvailable()
115bool KoTextDocCommandHistory::isRedoAvailable()
117 return current > -1 && current < (int)history.count() - 1 || current == -1 && history.count() > 0;
122KoTextDocDeleteCommand::KoTextDocDeleteCommand( KoTextDocument *d,
int i,
int idx,
const TQMemArray<KoTextStringChar> &str )
123 : KoTextDocCommand( d ), id( i ), index( idx ), parag( 0 ), text( str )
125 for (
int j = 0; j < (int)text.size(); ++j ) {
126 if ( text[ j ].format() )
127 text[ j ].format()->addRef();
140KoTextDocDeleteCommand::~KoTextDocDeleteCommand()
142 for (
int i = 0; i < (int)text.size(); ++i ) {
143 if ( text[ i ].format() )
144 text[ i ].format()->removeRef();
149KoTextCursor *KoTextDocDeleteCommand::execute( KoTextCursor *c )
151 KoTextParag *s = doc ? doc->paragAt(
id ) : parag;
154 kdWarning(32500) <<
"can't locate parag at " <<
id <<
", last parag: " << doc->lastParag()->paragId() << endl;
158 cursor.setParag( s );
159 cursor.setIndex( index );
160 int len = text.size();
164 doc->setSelectionStart( KoTextDocument::Temp, &cursor );
165 for (
int i = 0; i < len; ++i )
166 cursor.gotoNextLetter();
167 doc->setSelectionEnd( KoTextDocument::Temp, &cursor );
168 doc->removeSelectedText( KoTextDocument::Temp, &cursor );
172 s->remove( index, len );
178KoTextCursor *KoTextDocDeleteCommand::unexecute( KoTextCursor *c )
180 KoTextParag *s = doc ? doc->paragAt(
id ) : parag;
183 kdWarning(32500) <<
"can't locate parag at " <<
id <<
", last parag: " << doc->lastParag()->paragId() << endl;
187 cursor.setParag( s );
188 cursor.setIndex( index );
189 TQString str = KoTextString::toString( text );
190 cursor.insert( str,
true, &text );
191 cursor.setParag( s );
192 cursor.setIndex( index );
195 c->setIndex( index );
196 for (
int i = 0; i < (int)text.size(); ++i )
203 s->setChanged(
true );
204 if ( c && s == c->parag() )
212KoTextDocFormatCommand::KoTextDocFormatCommand( KoTextDocument *d,
int sid,
int sidx,
int eid,
int eidx,
213 const TQMemArray<KoTextStringChar> &old,
const KoTextFormat *f,
int fl )
214 : KoTextDocCommand( d ), startId( sid ), startIndex( sidx ), endId( eid ), endIndex( eidx ), oldFormats( old ), flags( fl )
216 format = d->formatCollection()->format( f );
217 for (
int j = 0; j < (int)oldFormats.size(); ++j ) {
218 if ( oldFormats[ j ].format() )
219 oldFormats[ j ].format()->addRef();
223KoTextDocFormatCommand::~KoTextDocFormatCommand()
226 for (
int j = 0; j < (int)oldFormats.size(); ++j ) {
227 if ( oldFormats[ j ].format() )
228 oldFormats[ j ].format()->removeRef();
232KoTextCursor *KoTextDocFormatCommand::execute( KoTextCursor *c )
234 KoTextParag *sp = doc->paragAt( startId );
235 KoTextParag *ep = doc->paragAt( endId );
239 KoTextCursor start( doc );
240 start.setParag( sp );
241 start.setIndex( startIndex );
242 KoTextCursor end( doc );
244 end.setIndex( endIndex );
246 doc->setSelectionStart( KoTextDocument::Temp, &start );
247 doc->setSelectionEnd( KoTextDocument::Temp, &end );
248 doc->setFormat( KoTextDocument::Temp, format, flags );
249 doc->removeSelection( KoTextDocument::Temp );
250 if ( endIndex == ep->length() )
256KoTextCursor *KoTextDocFormatCommand::unexecute( KoTextCursor *c )
258 KoTextParag *sp = doc->paragAt( startId );
259 KoTextParag *ep = doc->paragAt( endId );
263 int idx = startIndex;
265 if( !oldFormats.isEmpty())
268 if ( oldFormats.at( fIndex ).c ==
'\n' ) {
270 if ( idx < sp->length() && fIndex > 0 )
271 sp->setFormat( idx, 1, oldFormats.at( fIndex - 1 ).format() );
279 if ( oldFormats.at( fIndex ).format() )
280 sp->setFormat( idx, 1, oldFormats.at( fIndex ).format() );
283 if ( fIndex >= (
int)oldFormats.size() )
285 if ( idx >= sp->length() ) {
293 KoTextCursor end( doc );
295 end.setIndex( endIndex );
296 if ( endIndex == ep->length() )
302KoTextAlignmentCommand::KoTextAlignmentCommand( KoTextDocument *d,
int fParag,
int lParag,
int na,
const TQMemArray<int> &oa )
303 : KoTextDocCommand( d ), firstParag( fParag ), lastParag( lParag ), newAlign( na ), oldAligns( oa )
307KoTextCursor *KoTextAlignmentCommand::execute( KoTextCursor *c )
309 KoTextParag *p = doc->paragAt( firstParag );
313 p->setAlignment( newAlign );
314 if ( p->paragId() == lastParag )
321KoTextCursor *KoTextAlignmentCommand::unexecute( KoTextCursor *c )
323 KoTextParag *p = doc->paragAt( firstParag );
328 if ( i < (
int)oldAligns.size() )
329 p->setAlignment( oldAligns.at( i ) );
330 if ( p->paragId() == lastParag )
341KoTextCursor::KoTextCursor( KoTextDocument *d )
345 string = doc ? doc->firstParag() : 0;
349KoTextCursor::KoTextCursor()
353KoTextCursor::KoTextCursor(
const KoTextCursor &c )
358 tmpIndex = c.tmpIndex;
361KoTextCursor &KoTextCursor::operator=(
const KoTextCursor &c )
366 tmpIndex = c.tmpIndex;
371bool KoTextCursor::operator==(
const KoTextCursor &c )
const
373 return doc == c.doc &&
string == c.string && idx == c.idx;
376void KoTextCursor::insert(
const TQString &str,
bool checkNewLine, TQMemArray<KoTextStringChar> *formatting )
378 string->invalidate( idx );
380 bool justInsert =
true;
382#if defined(TQ_WS_WIN)
384 s = s.replace( TQRegExp(
"\\r" ),
"" );
387 justInsert = s.find(
'\n' ) == -1;
389 string->insert( idx, s );
391 for (
int i = 0; i < (int)s.length(); ++i ) {
392 if ( formatting->at( i ).format() ) {
393 formatting->at( i ).format()->addRef();
394 string->string()->setFormat( idx + i, formatting->at( i ).format(), true );
400 TQStringList lst = TQStringList::split(
'\n', s,
true );
401 TQStringList::Iterator it = lst.begin();
405 for ( ; it != lst.end(); ) {
406 if ( it != lst.begin() ) {
407 splitAndInsertEmptyParag(
false,
true );
410 string->prev()->format( -1,
false );
412 if ( lastFormat && formatting && string->prev() ) {
413 lastFormat->addRef();
414 string->prev()->string()->setFormat( string->prev()->length() - 1, lastFormat,
true );
421 string->insert( idx, s );
423 string->invalidate( 0 );
426 int len = s.length();
427 for (
int i = 0; i < len; ++i ) {
428 if ( formatting->at( i + lastIndex ).format() ) {
429 formatting->at( i + lastIndex ).format()->addRef();
430 string->string()->setFormat( i + idx, formatting->at( i + lastIndex ).format(),
true );
433 if ( it != lst.end() )
434 lastFormat = formatting->at( len + lastIndex ).format();
442 string->format( -1,
false );
443 int dy =
string->rect().y() +
string->rect().height() - y;
445 KoTextParag *p = string;
446 p->setParagId( p->prev()->paragId() + 1 );
449 p->setParagId( p->prev()->paragId() + 1 );
457 int h =
string->rect().height();
458 string->format( -1,
true );
463void KoTextCursor::gotoLeft()
465 if ( string->string()->isRightToLeft() )
468 gotoPreviousLetter();
471void KoTextCursor::gotoPreviousLetter()
476 idx =
string->string()->previousCursorPosition( idx );
477 }
else if ( string->prev() ) {
478 string =
string->prev();
479 while ( !string->isVisible() )
480 string =
string->prev();
481 idx =
string->length() - 1;
485bool KoTextCursor::place(
const TQPoint &p, KoTextParag *s,
bool link,
int *customItemIndex )
487 if ( customItemIndex )
488 *customItemIndex = -1;
491 if ( pos.y() < s->rect().y() )
492 pos.setY( s->rect().y() );
495 r.setWidth( doc ? doc->width() : TQWIDGETSIZE_MAX );
496 if ( !s->next() || ( pos.y() >= r.y() && pos.y() < s->next()->rect().y() ) )
504 setParag( s,
false );
505 int y = s->rect().y();
506 int lines = s->lines();
507 KoTextStringChar *chr = 0;
512 for ( ; i < lines; ++i ) {
513 chr = s->lineStartOfLine( i, &index );
518 if ( i < lines - 1 && pos.y() >= y + cy && pos.y() <= y + s->lineY( i+1 ) )
523 s->lineStartOfLine( i+1, &nextLine );
525 nextLine = s->length();
527 int x = s->rect().x();
531 int curpos = s->length()-1;
533 while ( i < nextLine ) {
535 int cpos = x + chr->x;
537 if ( chr->isCustom() ) {
538 if ( pos.x() >= cpos && pos.x() <= cpos + cw &&
539 pos.y() >= y + cy && pos.y() <= y + cy + chr->height() ) {
540 if ( customItemIndex )
541 *customItemIndex = i;
544 if( chr->rightToLeft )
546 int d = cpos - pos.x();
547 bool dm = d < 0 ? !chr->rightToLeft : chr->rightToLeft;
548 if ( (TQABS( d ) < dist || (dist == d && dm ==
true )) && string->string()->validCursorPosition( i ) ) {
550 if ( !link || pos.x() >= x + chr->x ) {
556 setIndex( curpos,
false );
561void KoTextCursor::gotoRight()
563 if ( string->string()->isRightToLeft() )
564 gotoPreviousLetter();
569void KoTextCursor::gotoNextLetter()
573 int len =
string->length() - 1;
575 idx =
string->string()->nextCursorPosition( idx );
576 }
else if ( string->next() ) {
577 string =
string->next();
578 while ( !string->isVisible() )
579 string =
string->next();
584void KoTextCursor::gotoUp()
586 int indexOfLineStart;
588 KoTextStringChar *c =
string->lineStartOfChar( idx, &indexOfLineStart, &line );
592 tmpIndex = TQMAX( tmpIndex, idx - indexOfLineStart );
593 if ( indexOfLineStart == 0 ) {
594 if ( !string->prev() ) {
597 string =
string->prev();
598 while ( !string->isVisible() )
599 string =
string->prev();
600 int lastLine =
string->lines() - 1;
601 if ( !string->lineStartOfLine( lastLine, &indexOfLineStart ) )
603 if ( indexOfLineStart + tmpIndex < string->length() )
604 idx = indexOfLineStart + tmpIndex;
606 idx =
string->length() - 1;
609 int oldIndexOfLineStart = indexOfLineStart;
610 if ( !string->lineStartOfLine( line, &indexOfLineStart ) )
612 if ( indexOfLineStart + tmpIndex < oldIndexOfLineStart )
613 idx = indexOfLineStart + tmpIndex;
615 idx = oldIndexOfLineStart - 1;
620void KoTextCursor::gotoDown()
622 int indexOfLineStart;
624 KoTextStringChar *c =
string->lineStartOfChar( idx, &indexOfLineStart, &line );
628 tmpIndex = TQMAX( tmpIndex, idx - indexOfLineStart );
629 if ( line == string->lines() - 1 ) {
630 if ( !string->next() ) {
633 string =
string->next();
634 while ( !string->isVisible() )
635 string =
string->next();
636 if ( !string->lineStartOfLine( 0, &indexOfLineStart ) )
639 if ( string->lines() == 1 )
640 end =
string->length();
642 string->lineStartOfLine( 1, &end );
643 if ( indexOfLineStart + tmpIndex < end )
644 idx = indexOfLineStart + tmpIndex;
650 if ( line == string->lines() - 1 )
651 end =
string->length();
653 string->lineStartOfLine( line + 1, &end );
654 if ( !string->lineStartOfLine( line, &indexOfLineStart ) )
656 if ( indexOfLineStart + tmpIndex < end )
657 idx = indexOfLineStart + tmpIndex;
664void KoTextCursor::gotoLineEnd()
667 int indexOfLineStart;
669 KoTextStringChar *c =
string->lineStartOfChar( idx, &indexOfLineStart, &line );
673 if ( line == string->lines() - 1 ) {
674 idx =
string->length() - 1;
676 c =
string->lineStartOfLine( ++line, &indexOfLineStart );
678 idx = indexOfLineStart;
682void KoTextCursor::gotoLineStart()
685 int indexOfLineStart;
687 KoTextStringChar *c =
string->lineStartOfChar( idx, &indexOfLineStart, &line );
691 idx = indexOfLineStart;
694void KoTextCursor::gotoHome()
698 string = doc->firstParag();
702void KoTextCursor::gotoEnd()
714 string = doc->lastParag();
715 idx =
string->length() - 1;
718void KoTextCursor::gotoPageUp(
int visibleHeight )
721 KoTextParag *s = string;
722 int h = visibleHeight;
723 int y = s->rect().y();
725 if ( y - s->rect().y() >= h )
731 s = doc->firstParag();
737void KoTextCursor::gotoPageDown(
int visibleHeight )
740 KoTextParag *s = string;
741 int h = visibleHeight;
742 int y = s->rect().y();
744 if ( s->rect().y() - y >= h )
750 s = doc->lastParag();
752 idx =
string->length() - 1;
763void KoTextCursor::gotoWordRight()
765 if ( string->string()->isRightToLeft() )
771void KoTextCursor::gotoWordLeft()
773 if ( string->string()->isRightToLeft() )
779void KoTextCursor::gotoPreviousWord()
781 gotoPreviousLetter();
783 KoTextString *s =
string->string();
784 bool allowSame =
false;
785 if ( idx == ( (
int)s->length()-1 ) )
787 for (
int i = idx; i >= 0; --i ) {
788 if ( s->at( i ).c.isSpace() || s->at( i ).c ==
'\t' || s->at( i ).c ==
'.' ||
789 s->at( i ).c ==
',' || s->at( i ).c ==
':' || s->at( i ).c ==
';' ) {
795 if ( !allowSame && !( s->at( i ).c.isSpace() || s->at( i ).c ==
'\t' || s->at( i ).c ==
'.' ||
796 s->at( i ).c ==
',' || s->at( i ).c ==
':' || s->at( i ).c ==
';' ) )
802void KoTextCursor::gotoNextWord()
805 KoTextString *s =
string->string();
806 bool allowSame =
false;
807 for (
int i = idx; i < (int)s->length(); ++i ) {
808 if ( ! ( s->at( i ).c.isSpace() || s->at( i ).c ==
'\t' || s->at( i ).c ==
'.' ||
809 s->at( i ).c ==
',' || s->at( i ).c ==
':' || s->at( i ).c ==
';' ) ) {
815 if ( !allowSame && ( s->at( i ).c.isSpace() || s->at( i ).c ==
'\t' || s->at( i ).c ==
'.' ||
816 s->at( i ).c ==
',' || s->at( i ).c ==
':' || s->at( i ).c ==
';' ) )
820 if ( idx < ((
int)s->length()-1) ) {
822 }
else if ( string->next() ) {
823 string =
string->next();
824 while ( !string->isVisible() )
825 string =
string->next();
832bool KoTextCursor::atParagStart()
const
837bool KoTextCursor::atParagEnd()
const
839 return idx ==
string->length() - 1;
842void KoTextCursor::splitAndInsertEmptyParag(
bool ind,
bool updateIds )
848 if ( doc->useFormatCollection() ) {
849 f =
string->at( idx )->format();
850 if ( idx == string->length() - 1 && idx > 0 )
851 f =
string->at( idx - 1 )->format();
852 if ( f->isMisspelled() ) {
854 fNoMisspelled.setMisspelled(
false );
855 f = doc->formatCollection()->format( &fNoMisspelled );
859 if ( atParagEnd() ) {
860 KoTextParag *n =
string->next();
861 KoTextParag *s = doc->createParag( doc,
string, n, updateIds );
863 s->setFormat( 0, 1, f,
true );
864 s->copyParagData(
string );
868 s->indent( &oi, &ni );
877 }
else if ( atParagStart() ) {
878 KoTextParag *p =
string->prev();
879 KoTextParag *s = doc->createParag( doc, p,
string, updateIds );
881 s->setFormat( 0, 1, f,
true );
882 s->copyParagData(
string );
890 TQString str =
string->string()->toString().mid( idx, 0xFFFFFF );
891 KoTextParag *n =
string->next();
892 KoTextParag *s = doc->createParag( doc,
string, n, updateIds );
893 s->copyParagData(
string );
895 s->append( str,
true );
896 for ( uint i = 0; i < str.length(); ++i ) {
897 KoTextStringChar* tsc =
string->at( idx + i );
898 s->setFormat( i, 1, tsc->format(),
true );
899 if ( tsc->isCustom() ) {
901 s->at( i )->setCustomItem( item );
902 tsc->loseCustomItem();
905 string->removeCustomItem();
907 doc->unregisterCustomItem( item,
string );
908 doc->registerCustomItem( item, s );
911 string->truncate( idx );
915 s->indent( &oi, &ni );
927bool KoTextCursor::removePreviousChar()
930 if ( !atParagStart() ) {
931 string->remove( idx-1, 1 );
935 string->format( -1,
true );
939 }
else if ( string->prev() ) {
940 string =
string->prev();
941 string->join( string->next() );
942 string->invalidateCounters();
948bool KoTextCursor::remove()
951 if ( !atParagEnd() ) {
952 int next =
string->string()->nextCursorPosition( idx );
953 string->remove( idx, next-idx );
954 string->format( -1,
true );
958 }
else if ( string->next() ) {
959 if ( string->length() == 1 ) {
960 string->next()->setPrev( string->prev() );
961 if ( string->prev() )
962 string->prev()->setNext( string->next() );
963 KoTextParag *p =
string->next();
966 string->invalidate( 0 );
968 string->invalidateCounters();
970 KoTextParag *s = string;
972 s->id = s->p ? s->p->id + 1 : 0;
980 string->join( string->next() );
987void KoTextCursor::killLine()
991 string->remove( idx, string->length() - idx - 1 );
992 string->format( -1,
true );
998void KoTextCursor::indent()
1001 string->indent( &oi, &ni );
1012void KoTextCursor::setDocument( KoTextDocument *d )
1015 string = d->firstParag();
1021int KoTextCursor::x()
const
1023 KoTextStringChar *c =
string->at( idx );
1025 if ( c->rightToLeft )
1030int KoTextCursor::y()
const
1033 string->lineStartOfChar( idx, &dummy, &line );
1034 return string->lineY( line );
1038void KoTextCursor::fixCursorPosition()
1041 if ( string->string()->validCursorPosition( idx ) )
1045 KoTextStringChar *start =
string->lineStartOfChar( idx, &lineIdx, 0 );
1046 int x =
string->string()->at( idx ).x;
1047 int diff = TQABS(start->x - x);
1050 KoTextStringChar *c = start;
1053 KoTextStringChar *end = &
string->string()->at( string->length()-1 );
1054 while ( c <= end && !c->lineStart ) {
1056 if ( c->rightToLeft )
1057 xp += c->pixelwidth;
1058 int ndiff = TQABS(xp - x);
1059 if ( ndiff < diff && string->
string()->validCursorPosition(lineIdx + (c-start)) ) {
1061 best = lineIdx + (c-start);
1070KoTextString::KoTextString()
1073 bNeedsSpellCheck =
true;
1075 rightToLeft =
false;
1076 dir = TQChar::DirON;
1079KoTextString::KoTextString(
const KoTextString &s )
1081 bidiDirty = s.bidiDirty;
1082 bNeedsSpellCheck = s.bNeedsSpellCheck;
1084 rightToLeft = s.rightToLeft;
1088 for (
int i = 0; i < (int)data.size(); ++i ) {
1095void KoTextString::insert(
int index,
const TQString &s,
KoTextFormat *f )
1097 int os = data.size();
1098 data.resize( data.size() + s.length() );
1100 memmove( data.data() + index + s.length(), data.data() + index,
1101 sizeof( KoTextStringChar ) * ( os - index ) );
1103 for (
int i = 0; i < (int)s.length(); ++i ) {
1104 KoTextStringChar &ch = data[ (int)index + i ];
1111 ch.type = KoTextStringChar::Regular;
1115#ifdef DEBUG_COLLECTION
1116 kdDebug(32500) <<
"KoTextString::insert setting format " << f <<
" to character " << (int)index+i << endl;
1121 bNeedsSpellCheck =
true;
1124KoTextString::~KoTextString()
1129void KoTextString::insert(
int index, KoTextStringChar *c )
1131 int os = data.size();
1132 data.resize( data.size() + 1 );
1134 memmove( data.data() + index + 1, data.data() + index,
1135 sizeof( KoTextStringChar ) * ( os - index ) );
1137 KoTextStringChar &ch = data[ (int)index ];
1146 ch.type = KoTextStringChar::Regular;
1147 ch.setFormat( c->format() );
1149 bNeedsSpellCheck =
true;
1152void KoTextString::truncate(
int index )
1154 index = TQMAX( index, 0 );
1155 index = TQMIN( index, (
int)data.size() - 1 );
1156 if ( index < (
int)data.size() ) {
1157 for (
int i = index + 1; i < (int)data.size(); ++i ) {
1158 KoTextStringChar &ch = data[ i ];
1159 if ( ch.isCustom() ) {
1160 delete ch.customItem();
1161 if ( ch.d.custom->format )
1162 ch.d.custom->format->removeRef();
1165 }
else if ( ch.format() ) {
1166 ch.format()->removeRef();
1170 data.truncate( index );
1172 bNeedsSpellCheck =
true;
1175void KoTextString::remove(
int index,
int len )
1177 for (
int i = index; i < (int)data.size() && i - index < len; ++i ) {
1178 KoTextStringChar &ch = data[ i ];
1179 if ( ch.isCustom() ) {
1180 delete ch.customItem();
1181 if ( ch.d.custom->format )
1182 ch.d.custom->format->removeRef();
1185 }
else if ( ch.format() ) {
1186 ch.format()->removeRef();
1189 memmove( data.data() + index, data.data() + index + len,
1190 sizeof( KoTextStringChar ) * ( data.size() - index - len ) );
1191 data.resize( data.size() - len, TQGArray::SpeedOptim );
1193 bNeedsSpellCheck =
true;
1196void KoTextString::clear()
1198 for (
int i = 0; i < (int)data.count(); ++i ) {
1199 KoTextStringChar &ch = data[ i ];
1200 if ( ch.isCustom() ) {
1207 delete ch.customItem();
1208 if ( ch.d.custom->format )
1209 ch.d.custom->format->removeRef();
1213 }
else if ( ch.format() ) {
1214 ch.format()->removeRef();
1220void KoTextString::setFormat(
int index,
KoTextFormat *f,
bool useCollection,
bool setFormatAgain )
1222 KoTextStringChar &ch = data[ index ];
1224 if ( useCollection && ch.format() )
1227 ch.format()->removeRef();
1229 ch.setFormat( f, setFormatAgain );
1232void KoTextString::checkBidi()
const
1234 KoTextString *that = (KoTextString *)
this;
1235 that->bidiDirty =
false;
1236 int length = data.size();
1239 that->rightToLeft = dir == TQChar::DirR;
1242 const KoTextStringChar *start = data.data();
1243 const KoTextStringChar *end = start + length;
1246 TQTextEngine textEngine( toString(), 0 );
1247 textEngine.direction = (TQChar::Direction) dir;
1248 textEngine.itemize(TQTextEngine::SingleLine);
1249 const TQCharAttributes *ca = textEngine.attributes() + length-1;
1250 KoTextStringChar *ch = (KoTextStringChar *)end - 1;
1251 TQScriptItem *item = &textEngine.items[textEngine.items.size()-1];
1252 unsigned char bidiLevel = item->analysis.bidiLevel;
1256 while ( ch >= start ) {
1257 if ( item->position > pos ) {
1259 Q_ASSERT( item >= &textEngine.items[0] );
1260 Q_ASSERT( item < &textEngine.items[textEngine.items.size()] );
1261 bidiLevel = item->analysis.bidiLevel;
1265 ch->softBreak = ca->softBreak;
1266 ch->whiteSpace = ca->whiteSpace;
1267 ch->charStop = ca->charStop;
1268 ch->wordStop = ca->wordStop;
1270 ch->rightToLeft = (bidiLevel%2);
1276 if ( dir == TQChar::DirR ) {
1278 that->rightToLeft =
true;
1279 }
else if ( dir == TQChar::DirL ) {
1280 that->rightToLeft =
false;
1282 that->rightToLeft = (textEngine.direction == TQChar::DirR);
1286TQMemArray<KoTextStringChar> KoTextString::subString(
int start,
int len )
const
1288 if ( len == 0xFFFFFF )
1290 TQMemArray<KoTextStringChar> a;
1292 for (
int i = 0; i < len; ++i ) {
1293 KoTextStringChar *c = &data[ i + start ];
1296 a[ i ].pixelxadj = 0;
1297 a[ i ].pixelwidth = 0;
1299 a[ i ].lineStart = 0;
1300 a[ i ].rightToLeft = 0;
1301 a[ i ].d.format = 0;
1302 a[ i ].type = KoTextStringChar::Regular;
1303 a[ i ].setFormat( c->format() );
1305 c->format()->addRef();
1310TQString KoTextString::mid(
int start,
int len )
const
1312 if ( len == 0xFFFFFF )
1315 res.setLength( len );
1316 for (
int i = 0; i < len; ++i ) {
1317 KoTextStringChar *c = &data[ i + start ];
1323TQString KoTextString::toString(
const TQMemArray<KoTextStringChar> &data )
1326 int l = data.size();
1327 s.setUnicode( 0, l );
1328 KoTextStringChar *c = data.data();
1329 TQChar *uc = (TQChar *)s.unicode();
1339TQString KoTextString::toReverseString()
const
1344 KoTextStringChar *c = data.data() + (l-1);
1345 TQChar *uc = (TQChar *)s.unicode();
1355TQString KoTextString::stringToSpellCheck()
1357 if ( !bNeedsSpellCheck )
1360 bNeedsSpellCheck =
false;
1361 if ( length() <= 1 )
1364 TQString str = toString();
1365 str.truncate( str.length() - 1 );
1369int KoTextString::nextCursorPosition(
int next )
1374 const KoTextStringChar *c = data.data();
1377 if ( next < len - 1 ) {
1379 while ( next < len - 1 && !c[next].charStop )
1385int KoTextString::previousCursorPosition(
int prev )
1390 const KoTextStringChar *c = data.data();
1394 while ( prev && !c[prev].charStop )
1400bool KoTextString::validCursorPosition(
int idx )
1405 return (at( idx ).charStop);
1410void KoTextStringChar::setFormat(
KoTextFormat *f,
bool setFormatAgain )
1412 if ( type == Regular ) {
1416 d.custom =
new CustomData;
1417 d.custom->custom = 0;
1419 d.custom->format = f;
1420 if ( d.custom->custom && setFormatAgain )
1421 d.custom->custom->setFormat( f );
1427 if ( type == Regular ) {
1429 d.custom =
new CustomData;
1430 d.custom->format = f;
1433 delete d.custom->custom;
1435 d.custom->custom = i;
1438void KoTextStringChar::loseCustomItem()
1442 d.custom->custom = 0;
1449KoTextStringChar::~KoTextStringChar()
1452 format()->removeRef();
1455 delete d.custom;
break;
1461int KoTextStringChar::height()
const
1463 return !isCustom() ? format()->height() : ( customItem()->placement() == KoTextCustomItem::PlaceInline ? customItem()->height : 0 );
1466int KoTextStringChar::ascent()
const
1468 return !isCustom() ? format()->ascent() : ( customItem()->placement() == KoTextCustomItem::PlaceInline ? customItem()->ascent() : 0 );
1471int KoTextStringChar::descent()
const
1473 return !isCustom() ? format()->descent() : 0;
1478KoTextFormatterBase::KoTextFormatterBase()
1480 m_bViewFormattingChars( false ),
1490KoTextParagLineStart *KoTextFormatterBase::bidiReorderLine( KoTextParag * , KoTextString *text, KoTextParagLineStart *line,
1491 KoTextStringChar *startChar, KoTextStringChar *lastChar,
int align,
int space )
1493 int start = (startChar - &text->at(0));
1494 int last = (lastChar - &text->at(0) );
1497 KoBidiControl *control =
new KoBidiControl( line->context(), line->status );
1499 str.setUnicode( 0, last - start + 1 );
1501 KoTextStringChar *ch = startChar;
1502 TQChar *qch = (TQChar *)str.unicode();
1503 while ( ch <= lastChar ) {
1508 int x = startChar->x;
1510 TQPtrList<KoTextRun> *runs;
1511 runs = KoComplexText::bidiReorderLine(control, str, 0, last - start + 1,
1512 (text->isRightToLeft() ? TQChar::DirR : TQChar::DirL) );
1518 if( align == TQt::AlignAuto ) {
1520 if ( text->isRightToLeft() )
1521 align = TQt::AlignRight;
1524 if ( align & TQt::AlignHCenter )
1526 else if ( align & TQt::AlignRight )
1528 else if ( align & TQt::AlignJustify ) {
1529 for (
int j = start; j < last; ++j ) {
1530 if( isBreakable( text, j ) ) {
1537 KoTextRun *r = runs->first();
1538 int xmax = -0xffffff;
1542 int pos = r->stop + start;
1543 while(pos >= r->start + start) {
1544 KoTextStringChar *c = &text->at(pos);
1545 if( numSpaces && !first && isBreakable( text, pos ) ) {
1546 int s = space / numSpaces;
1550 }
else if ( first ) {
1553 x -= c->format()->width(
' ' );
1556 c->rightToLeft =
true;
1557 c->startOfRun =
false;
1559 if ( c->c.unicode() >= 32 || c->c ==
'\t' || c->c ==
'\n' || c->isCustom() ) {
1562 ww = c->format()->width(
' ' );
1564 if ( xmax < x + toAdd + ww ) xmax = x + toAdd + ww;
1569 int pos = r->start + start;
1570 while(pos <= r->stop + start) {
1571 KoTextStringChar* c = &text->at(pos);
1572 if( numSpaces && !first && isBreakable( text, pos ) ) {
1573 int s = space / numSpaces;
1577 }
else if ( first ) {
1580 x -= c->format()->width(
' ' );
1583 c->rightToLeft =
false;
1584 c->startOfRun =
false;
1586 if ( c->c.unicode() >= 32 || c->c ==
'\t' || c->isCustom() ) {
1589 ww = c->format()->width(
' ' );
1592 if ( xmax < x + toAdd + ww ) xmax = x + toAdd + ww;
1597 text->at( r->start + start ).startOfRun =
true;
1601 line->w = xmax + 10;
1602 KoTextParagLineStart *ls =
new KoTextParagLineStart( control->context, control->status );
1608bool KoTextFormatterBase::isStretchable( KoTextString *
string,
int pos )
const
1610 if ( string->at( pos ).c == TQChar(160) )
1612 KoTextStringChar& chr =
string->at( pos );
1613 return chr.whiteSpace;
1617bool KoTextFormatterBase::isBreakable( KoTextString *
string,
int pos )
const
1621 return (pos < string->length()-1 && string->at(pos+1).softBreak);
1624void KoTextParag::insertLineStart(
int index, KoTextParagLineStart *ls )
1631 TQMap<int, KoTextParagLineStart*>::Iterator it;
1632 if ( ( it = lineStarts.find( index ) ) == lineStarts.end() ) {
1633 lineStarts.insert( index, ls );
1635 kdWarning(32500) <<
"insertLineStart: there's already a line for char index=" << index << endl;
1637 lineStarts.remove( it );
1638 lineStarts.insert( index, ls );
1641 lineStarts.insert( index, ls );
1649int KoTextFormatterBase::formatVertically( KoTextDocument* doc, KoTextParag* parag )
1651 int oldHeight = parag->rect().height();
1652 TQMap<int, KoTextParagLineStart*>& lineStarts = parag->lineStartList();
1653 TQMap<int, KoTextParagLineStart*>::Iterator it = lineStarts.begin();
1654 int h = doc->addMargins() ? parag->topMargin() : 0;
1655 for ( ; it != lineStarts.end() ; ++it ) {
1656 KoTextParagLineStart * ls = it.data();
1658 KoTextStringChar *c = ¶g->string()->at(it.key());
1659 if ( c && c->customItem() && c->customItem()->ownLine() ) {
1660 int h = c->customItem()->height;
1661 c->customItem()->pageBreak( parag->rect().y() + ls->y + ls->baseLine - h, doc->flow() );
1662 int delta = c->customItem()->height - h;
1665 parag->setMovedDown(
true );
1667 int shift = doc->flow()->adjustFlow( parag->rect().y() + ls->y, ls->w, ls->h );
1670 parag->setMovedDown(
true );
1674 int m = parag->bottomMargin();
1675 if ( parag->next() && doc && !doc->addMargins() )
1676 m = TQMAX( m, parag->next()->topMargin() );
1680 parag->setHeight( h );
1681 return h - oldHeight;
1686KoTextCustomItem::KoTextCustomItem( KoTextDocument *p )
1687 : width(-1), height(0), parent(p), xpos(0), ypos(-1), parag(0)
1692KoTextCustomItem::~KoTextCustomItem()
1696KoTextFlow::KoTextFlow()
1699 leftItems.setAutoDelete(
false );
1700 rightItems.setAutoDelete(
false );
1703KoTextFlow::~KoTextFlow()
1707void KoTextFlow::clear()
1714void KoTextFlow::setWidth(
int width )
1719void KoTextFlow::adjustMargins(
int,
int,
int,
int&,
int&,
int& pageWidth, KoTextParag* )
1725int KoTextFlow::adjustFlow(
int ,
int,
int )
1732 leftItems.removeRef( item );
1733 rightItems.removeRef( item );
1738 if ( item->placement() == KoTextCustomItem::PlaceRight ) {
1739 if ( !rightItems.contains( item ) )
1740 rightItems.append( item );
1741 }
else if ( item->placement() == KoTextCustomItem::PlaceLeft &&
1742 !leftItems.contains( item ) ) {
1743 leftItems.append( item );
1747int KoTextFlow::availableHeight()
const
1752void KoTextFlow::drawFloatingItems( TQPainter* p,
int cx,
int cy,
int cw,
int ch,
const TQColorGroup& cg,
bool selected )
1755 for ( item = leftItems.first(); item; item = leftItems.next() ) {
1756 if ( item->x() == -1 || item->y() == -1 )
1758 item->draw( p, item->x(), item->y(), cx, cy, cw, ch, cg, selected );
1761 for ( item = rightItems.first(); item; item = rightItems.next() ) {
1762 if ( item->x() == -1 || item->y() == -1 )
1764 item->draw( p, item->x(), item->y(), cx, cy, cw, ch, cg, selected );
1769bool 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...
TDEAction * next(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)
TDEAction * clear(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)