20#include "KoTextDocument.h"
21#include "KoTextParag.h"
22#include "KoTextZoomHandler.h"
23#include "KoTextFormatter.h"
24#include "KoTextFormat.h"
25#include "KoParagCounter.h"
26#include "KoTextCommand.h"
27#include "KoOasisContext.h"
28#include "KoVariable.h"
29#include <KoXmlWriter.h>
33#include <tqapplication.h>
41KoTextDocument::KoTextDocument(
KoTextZoomHandler *zoomHandler, KoTextFormatCollection *fc,
43 : m_zoomHandler( zoomHandler ),
44 m_bDestroying( false ),
45#ifdef TQTEXTTABLE_AVAILABLE
49 tArray( 0 ), tStopWidth( 0 )
57 setFormatter( formatter );
64 if ( !createInitialParag )
68void KoTextDocument::init()
74 m_pageBreakEnabled =
false;
76 align = TQt::AlignAuto;
87 withoutDoubleBuffer =
false;
89 lParag = fParag = createParag(
this, 0, 0 );
97 flow_ =
new KoTextFlow;
103 selectionColors[ Standard ] = TQApplication::palette().color( TQPalette::Active, TQColorGroup::Highlight );
104 selectionText[ Standard ] =
true;
105 assert( Standard < nSelections );
106 selectionText[ InputMethodPreedit ] =
false;
107 assert( InputMethodPreedit < nSelections );
108 commandHistory =
new KoTextDocCommandHistory( 100 );
109 tStopWidth = formatCollection()->defaultFormat()->width(
'x' ) * 8;
112KoTextDocument::~KoTextDocument()
117 m_bDestroying =
true;
120 delete commandHistory;
132void KoTextDocument::clear(
bool createEmptyParag )
137 KoTextParag *p = fParag->next();
138 fParag->string()->clear();
143 if ( createEmptyParag )
144 fParag = lParag = createParag(
this );
169int KoTextDocument::height()
const
173 h = lParag->rect().top() + lParag->rect().height() + 1;
180KoTextParag *KoTextDocument::createParag( KoTextDocument *d, KoTextParag *pr, KoTextParag *nx,
bool updateIds )
182 return new KoTextParag( d, pr, nx, updateIds );
185void KoTextDocument::setPlainText(
const TQString &text )
193 int nl = text.find(
'\n' );
195 lParag = createParag(
this, lParag, 0 );
199 if ( !s.isEmpty() ) {
200 if ( s[ (
int)s.length() - 1 ] ==
'\r' )
201 s.remove( s.length() - 1, 1 );
206 lParag = createParag(
this, lParag, 0 );
209 TQString s = text.mid( lastNl, nl - lastNl );
210 if ( !s.isEmpty() ) {
211 if ( s[ (
int)s.length() - 1 ] ==
'\r' )
212 s.remove( s.length() - 1, 1 );
215 if ( nl == 0xffffff )
218 nl = text.find(
'\n', nl + 1 );
224 lParag = fParag = createParag(
this, 0, 0 );
227void KoTextDocument::setText(
const TQString &text,
const TQString & )
230 setPlainText( text );
233TQString KoTextDocument::plainText()
const
237 KoTextParag *p = fParag;
239 s = p->string()->toString();
240 s.remove( s.length() - 1, 1 );
249void KoTextDocument::invalidate()
251 KoTextParag *s = fParag;
258void KoTextDocument::informParagraphDeleted( KoTextParag* parag )
260 TQMap<int, KoTextDocumentSelection>::Iterator it = selections.begin();
261 for ( ; it != selections.end(); ++it )
263 if ( (*it).startCursor.parag() == parag ) {
264 if ( parag->prev() ) {
265 KoTextParag* prevP = parag->prev();
266 (*it).startCursor.setParag( prevP );
267 (*it).startCursor.setIndex( prevP->length()-1 );
269 (*it).startCursor.setParag( parag->next() );
271 if ( (*it).endCursor.parag() == parag ) {
272 if ( parag->prev() ) {
273 KoTextParag* prevP = parag->prev();
274 (*it).endCursor.setParag( prevP );
275 (*it).endCursor.setIndex( prevP->length()-1 );
277 (*it).endCursor.setParag( parag->next() );
280 emit paragraphDeleted( parag );
283void KoTextDocument::selectionStart(
int id,
int ¶gId,
int &index )
285 TQMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
286 if ( it == selections.end() )
288 KoTextDocumentSelection &sel = *it;
289 paragId = !sel.swapped ? sel.startCursor.parag()->paragId() : sel.endCursor.parag()->paragId();
290 index = !sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
293KoTextCursor KoTextDocument::selectionStartCursor(
int id)
295 TQMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
296 if ( it == selections.end() )
297 return KoTextCursor(
this );
298 KoTextDocumentSelection &sel = *it;
300 return sel.endCursor;
301 return sel.startCursor;
304KoTextCursor KoTextDocument::selectionEndCursor(
int id)
306 TQMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
307 if ( it == selections.end() )
308 return KoTextCursor(
this );
309 KoTextDocumentSelection &sel = *it;
311 return sel.endCursor;
312 return sel.startCursor;
315void KoTextDocument::selectionEnd(
int id,
int ¶gId,
int &index )
317 TQMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
318 if ( it == selections.end() )
320 KoTextDocumentSelection &sel = *it;
321 paragId = sel.swapped ? sel.startCursor.parag()->paragId() : sel.endCursor.parag()->paragId();
322 index = sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
325bool KoTextDocument::isSelectionSwapped(
int id )
327 TQMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
328 if ( it == selections.end() )
330 KoTextDocumentSelection &sel = *it;
334KoTextParag *KoTextDocument::selectionStart(
int id )
336 TQMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
337 if ( it == selections.end() )
339 KoTextDocumentSelection &sel = *it;
340 if ( sel.startCursor.parag()->paragId() < sel.endCursor.parag()->paragId() )
341 return sel.startCursor.parag();
342 return sel.endCursor.parag();
345KoTextParag *KoTextDocument::selectionEnd(
int id )
347 TQMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
348 if ( it == selections.end() )
350 KoTextDocumentSelection &sel = *it;
351 if ( sel.startCursor.parag()->paragId() > sel.endCursor.parag()->paragId() )
352 return sel.startCursor.parag();
353 return sel.endCursor.parag();
356void KoTextDocument::addSelection(
int id )
358 nSelections = TQMAX( nSelections,
id + 1 );
361static void setSelectionEndHelper(
int id, KoTextDocumentSelection &sel, KoTextCursor &start, KoTextCursor &end )
363 KoTextCursor c1 = start;
364 KoTextCursor c2 = end;
370 c1.parag()->removeSelection(
id );
371 c2.parag()->removeSelection(
id );
372 if ( c1.parag() != c2.parag() ) {
373 c1.parag()->setSelection(
id, c1.index(), c1.parag()->length() - 1 );
374 c2.parag()->setSelection(
id, 0, c2.index() );
376 c1.parag()->setSelection(
id, TQMIN( c1.index(), c2.index() ), TQMAX( c1.index(), c2.index() ) );
379 sel.startCursor = start;
381 if ( sel.startCursor.parag() == sel.endCursor.parag() )
382 sel.swapped = sel.startCursor.index() > sel.endCursor.index();
385bool KoTextDocument::setSelectionEnd(
int id, KoTextCursor *cursor )
387 TQMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
388 if ( it == selections.end() )
390 KoTextDocumentSelection &sel = *it;
392 KoTextCursor start = sel.startCursor;
393 KoTextCursor end = *cursor;
395 if ( start == end ) {
396 removeSelection(
id );
397 setSelectionStart(
id, cursor );
401 if ( sel.endCursor.parag() == end.parag() ) {
402 setSelectionEndHelper(
id, sel, start, end );
406 bool inSelection =
false;
407 KoTextCursor c(
this );
408 KoTextCursor tmp = sel.startCursor;
411 KoTextCursor tmp2 = *cursor;
412 c.setParag( tmp.parag()->paragId() < tmp2.parag()->paragId() ? tmp.parag() : tmp2.parag() );
414 bool hadStart =
false;
416 bool hadStartParag =
false;
417 bool hadEndParag =
false;
418 bool hadOldStart =
false;
419 bool hadOldEnd =
false;
420 bool leftSelection =
false;
427 if ( c.parag() == start.parag() )
428 hadStartParag =
true;
429 if ( c.parag() == end.parag() )
431 if ( c == sel.startCursor )
433 if ( c == sel.endCursor )
437 ( hadEnd && !hadStart ||
438 hadEnd && hadStart && start.parag() == end.parag() && start.index() > end.index() ) )
441 if ( c == end && hadStartParag ||
442 c == start && hadEndParag ) {
443 KoTextCursor tmp = c;
444 if ( tmp.parag() != c.parag() ) {
445 int sstart = tmp.parag()->selectionStart(
id );
446 tmp.parag()->removeSelection(
id );
447 tmp.parag()->setSelection(
id, sstart, tmp.index() );
452 ( c == end && hadStart || c == start && hadEnd ) )
453 leftSelection =
true;
454 else if ( !leftSelection && !inSelection && ( hadStart || hadEnd ) )
457 bool noSelectionAnymore = hadOldStart && hadOldEnd && leftSelection && !inSelection && !c.parag()->hasSelection(
id ) && c.atParagEnd();
458 c.parag()->removeSelection(
id );
460 if ( c.parag() == start.parag() && start.parag() == end.parag() ) {
461 c.parag()->setSelection(
id, TQMIN( start.index(), end.index() ), TQMAX( start.index(), end.index() ) );
462 }
else if ( c.parag() == start.parag() && !hadEndParag ) {
463 c.parag()->setSelection(
id, start.index(), c.parag()->length() - 1 );
464 }
else if ( c.parag() == end.parag() && !hadStartParag ) {
465 c.parag()->setSelection(
id, end.index(), c.parag()->length() - 1 );
466 }
else if ( c.parag() == end.parag() && hadEndParag ) {
467 c.parag()->setSelection(
id, 0, end.index() );
468 }
else if ( c.parag() == start.parag() && hadStartParag ) {
469 c.parag()->setSelection(
id, 0, start.index() );
471 c.parag()->setSelection(
id, 0, c.parag()->length() - 1 );
480 if ( old == c || noSelectionAnymore )
485 sel.startCursor.parag()->setSelection(
id, sel.startCursor.index(), sel.startCursor.parag()->length() - 1 );
487 sel.startCursor = start;
489 if ( sel.startCursor.parag() == sel.endCursor.parag() )
490 sel.swapped = sel.startCursor.index() > sel.endCursor.index();
492 setSelectionEndHelper(
id, sel, start, end );
497void KoTextDocument::selectAll(
int id )
499 removeSelection(
id );
501 KoTextDocumentSelection sel;
503 KoTextCursor c(
this );
505 c.setParag( fParag );
509 c.setParag( lParag );
510 c.setIndex( lParag->length() - 1 );
513 KoTextParag *p = fParag;
515 p->setSelection(
id, 0, p->length() - 1 );
516#ifdef TQTEXTTABLE_AVAILABLE
517 for (
int i = 0; i < (int)p->length(); ++i ) {
518 if ( p->at( i )->isCustom() && p->at( i )->customItem()->isNested() ) {
519 KoTextTable *t = (KoTextTable*)p->at( i )->customItem();
520 TQPtrList<KoTextTableCell> tableCells = t->tableCells();
521 for ( KoTextTableCell *c = tableCells.first(); c; c = tableCells.next() )
522 c->richText()->selectAll(
id );
529 selections.insert(
id, sel );
532bool KoTextDocument::removeSelection(
int id )
534 TQMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
535 if ( it == selections.end() )
538 KoTextDocumentSelection &sel = *it;
540 KoTextCursor c(
this );
541 KoTextCursor tmp = sel.startCursor;
544 c.setParag( tmp.parag() );
546 bool hadStart =
false;
548 KoTextParag *lastParag = 0;
549 bool leftSelection =
false;
550 bool inSelection =
false;
553 if ( !hadStart && c.parag() == sel.startCursor.parag() )
555 if ( !hadEnd && c.parag() == sel.endCursor.parag() )
558 if ( !leftSelection && !inSelection && ( c.parag() == sel.startCursor.parag() || c.parag() == sel.endCursor.parag() ) )
562 ( c == sel.endCursor && hadStart || c == sel.startCursor && hadEnd ) ) {
563 leftSelection =
true;
567 bool noSelectionAnymore = leftSelection && !inSelection && !c.parag()->hasSelection(
id ) && c.atParagEnd();
569 if ( lastParag != c.parag() )
570 c.parag()->removeSelection(
id );
573 lastParag = c.parag();
575 if ( old == c || noSelectionAnymore )
579 selections.remove(
id );
583TQString KoTextDocument::selectedText(
int id,
bool withCustom )
const
586 TQMap<int, KoTextDocumentSelection>::ConstIterator it = selections.find(
id );
587 if ( it == selections.end() )
590 KoTextDocumentSelection sel = *it;
593 KoTextCursor c1 = sel.startCursor;
594 KoTextCursor c2 = sel.endCursor;
596 c2 = sel.startCursor;
600 if ( c1.parag() == c2.parag() ) {
602 KoTextParag *p = c1.parag();
603 int end = c2.index();
604 if ( p->at( TQMAX( 0, end - 1 ) )->isCustom() )
606 if ( !withCustom || !p->customItems() ) {
607 s += p->string()->toString().mid( c1.index(), end - c1.index() );
609 for (
int i = c1.index(); i < end; ++i ) {
610 if ( p->at( i )->isCustom() ) {
611#ifdef TQTEXTTABLE_AVAILABLE
612 if ( p->at( i )->customItem()->isNested() ) {
614 KoTextTable *t = (KoTextTable*)p->at( i )->customItem();
615 TQPtrList<KoTextTableCell> cells = t->tableCells();
616 for ( KoTextTableCell *c = cells.first(); c; c = cells.next() )
617 s += c->richText()->plainText() +
"\n";
631 KoTextParag *p = c1.parag();
632 int start = c1.index();
634 int end = p == c2.parag() ? c2.index() : p->length() - 1;
635 if ( p == c2.parag() && p->at( TQMAX( 0, end - 1 ) )->isCustom() )
637 if ( !withCustom || !p->customItems() ) {
638 s += p->string()->toString().mid( start, end - start );
639 if ( p != c2.parag() )
642 for (
int i = start; i < end; ++i ) {
643 if ( p->at( i )->isCustom() ) {
644#ifdef TQTEXTTABLE_AVAILABLE
645 if ( p->at( i )->customItem()->isNested() ) {
647 KoTextTable *t = (KoTextTable*)p->at( i )->customItem();
648 TQPtrList<KoTextTableCell> cells = t->tableCells();
649 for ( KoTextTableCell *c = cells.first(); c; c = cells.next() )
650 s += c->richText()->plainText() +
"\n";
661 if ( p == c2.parag() )
670 KoTextCursor c1 = selectionStartCursor( selectionId );
671 KoTextCursor c2 = selectionEndCursor( selectionId );
673 if ( c1.parag() == c2.parag() )
675 text = c1.parag()->toString( c1.index(), c2.index() - c1.index() );
677 c1.parag()->saveOasis( writer, context, c1.index(), c2.index()-1,
true );
681 text += c1.parag()->toString( c1.index() ) +
"\n";
683 c1.parag()->saveOasis( writer, context, c1.index(), c1.parag()->length()-2,
true );
684 KoTextParag *p = c1.parag()->next();
685 while ( p && p != c2.parag() ) {
686 text += p->toString() +
"\n";
687 p->saveOasis( writer, context, 0, p->length()-2,
true );
690 text += c2.parag()->toString( 0, c2.index() );
691 c2.parag()->saveOasis( writer, context, 0, c2.index() - 1,
true );
696void KoTextDocument::setFormat(
int id,
const KoTextFormat *f,
int flags )
698 TQMap<int, KoTextDocumentSelection>::ConstIterator it = selections.find(
id );
699 if ( it == selections.end() )
702 KoTextDocumentSelection sel = *it;
704 KoTextCursor c1 = sel.startCursor;
705 KoTextCursor c2 = sel.endCursor;
707 c2 = sel.startCursor;
711 if ( c1.parag() == c2.parag() ) {
712 c1.parag()->setFormat( c1.index(), c2.index() - c1.index(), f,
true, flags );
716 c1.parag()->setFormat( c1.index(), c1.parag()->length() - c1.index(), f,
true, flags );
717 KoTextParag *p = c1.parag()->next();
718 while ( p && p != c2.parag() ) {
719 p->setFormat( 0, p->length(), f,
true, flags );
722 c2.parag()->setFormat( 0, c2.index(), f,
true, flags );
735void KoTextDocument::removeSelectedText(
int id, KoTextCursor *cursor )
737 TQMap<int, KoTextDocumentSelection>::Iterator it = selections.find(
id );
738 if ( it == selections.end() )
741 KoTextDocumentSelection sel = *it;
743 KoTextCursor c1 = sel.startCursor;
744 KoTextCursor c2 = sel.endCursor;
746 c2 = sel.startCursor;
751 removeSelection(
id );
753 if ( c1.parag() == c2.parag() ) {
754 c1.parag()->remove( c1.index(), c2.index() - c1.index() );
760 if ( c1.parag() == fParag && c1.index() == 0 &&
761 c2.parag() == lParag && c2.index() == lParag->length() - 1 )
764 bool didGoLeft =
false;
765 if ( c1.index() == 0 && c1.parag() != fParag ) {
766 cursor->gotoPreviousLetter();
771 c1.parag()->remove( c1.index(), c1.parag()->length() - 1 - c1.index() );
772 KoTextParag *p = c1.parag()->next();
775 while ( p && p != c2.parag() ) {
777 dy -= p->rect().height();
782 c2.parag()->remove( 0, c2.index() );
786 if ( p->paragLayout().
counter )
794 c1.parag()->join( c2.parag() );
797 cursor->gotoNextLetter();
800void KoTextDocument::addCommand( KoTextDocCommand *cmd )
802 commandHistory->addCommand( cmd );
805KoTextCursor *KoTextDocument::undo( KoTextCursor *c )
807 return commandHistory->undo( c );
810KoTextCursor *KoTextDocument::redo( KoTextCursor *c )
812 return commandHistory->redo( c );
815bool KoTextDocument::find(
const TQString &expr,
bool cs,
bool wo,
bool forward,
816 int *parag,
int *index, KoTextCursor *cursor )
818 KoTextParag *p =
forward ? fParag : lParag;
820 p = paragAt( *parag );
826 TQString s = p->string()->toString();
827 s.remove( s.length() - 1, 1 );
828 int start =
forward ? 0 : s.length() - 1;
829 if ( first && index )
832 start = cursor->index();
833 if ( !forward && first ) {
834 start -= expr.length() + 1;
844 int res =
forward ? s.find( expr, start, cs ) : s.findRev( expr, start, cs );
850 int end = res + expr.length();
851 if ( ( res == 0 || s[ res - 1 ].isSpace() || s[ res - 1 ].isPunct() ) &&
852 ( end == (
int)s.length() || s[ end ].isSpace() || s[ end ].isPunct() ) )
858 cursor->setParag( p );
859 cursor->setIndex( res );
860 setSelectionStart( Standard, cursor );
861 cursor->setIndex( res + expr.length() );
862 setSelectionEnd( Standard, cursor );
864 *parag = p->paragId();
877 p =
forward ? p->next() : p->prev();
883bool KoTextDocument::inSelection(
int selId,
const TQPoint &pos )
const
885 TQMap<int, KoTextDocumentSelection>::ConstIterator it = selections.find( selId );
886 if ( it == selections.end() )
889 KoTextDocumentSelection sel = *it;
890 KoTextParag *startParag = sel.startCursor.parag();
891 KoTextParag *endParag = sel.endCursor.parag();
892 if ( sel.startCursor.parag() == sel.endCursor.parag() &&
893 sel.startCursor.parag()->selectionStart( selId ) == sel.endCursor.parag()->selectionEnd( selId ) )
895 if ( sel.endCursor.parag()->paragId() < sel.startCursor.parag()->paragId() ) {
896 endParag = sel.startCursor.parag();
897 startParag = sel.endCursor.parag();
900 KoTextParag *p = startParag;
902 if ( p->rect().contains( pos ) ) {
904 int selStart = p->selectionStart( selId );
905 int selEnd = p->selectionEnd( selId );
908 for (
int i = 0; i < p->length(); ++i ) {
913 if ( p->at( i )->lineStart ) {
914 y = (*p->lineStarts.find( i ))->y;
915 h = (*p->lineStarts.find( i ))->h;
917 if ( pos.y() - p->rect().y() >= y && pos.y() - p->rect().y() <= y + h ) {
918 if ( inSel && pos.x() >= p->at( i )->x &&
919 pos.x() <= p->at( i )->x + p->at( i )->width )
924 if ( pos.y() < p->rect().y() )
934TQPixmap *KoTextDocument::bufferPixmap(
const TQSize &s )
937 int w = TQABS( s.width() );
938 int h = TQABS( s.height() );
939 buf_pixmap =
new TQPixmap( w, h );
941 if ( buf_pixmap->width() < s.width() ||
942 buf_pixmap->height() < s.height() ) {
943 buf_pixmap->resize( TQMAX( s.width(), buf_pixmap->width() ),
944 TQMAX( s.height(), buf_pixmap->height() ) );
951void KoTextDocument::registerCustomItem(
KoTextCustomItem *i, KoTextParag *p )
953 if ( i && i->placement() != KoTextCustomItem::PlaceInline )
954 flow_->registerFloatingItem( i );
955 p->registerFloatingItem( i );
956 i->setParagraph( p );
958 customItems.append( i );
961void KoTextDocument::unregisterCustomItem(
KoTextCustomItem *i, KoTextParag *p )
963 flow_->unregisterFloatingItem( i );
964 p->unregisterFloatingItem( i );
965 i->setParagraph( 0 );
966 customItems.removeRef( i );
969int KoTextDocument::length()
const
972 KoTextParag *p = fParag;
974 l += p->length() - 1;
980bool KoTextDocument::visitSelection(
int selectionId,
KoParagVisitor* visitor,
bool forward )
982 KoTextCursor c1 = selectionStartCursor( selectionId );
983 KoTextCursor c2 = selectionEndCursor( selectionId );
986 return visitFromTo( c1.parag(), c1.index(), c2.parag(), c2.index(), visitor, forward );
989bool KoTextDocument::hasSelection(
int id,
bool visible )
const
991 return ( selections.find(
id ) != selections.end() &&
993 ( (KoTextDocument*)
this )->selectionStartCursor(
id ) !=
994 ( (KoTextDocument*)
this )->selectionEndCursor(
id ) ) );
997void KoTextDocument::setSelectionStart(
int id, KoTextCursor *cursor )
999 KoTextDocumentSelection sel;
1000 sel.startCursor = *cursor;
1001 sel.endCursor = *cursor;
1002 sel.swapped =
false;
1003 selections[ id ] = sel;
1006KoTextParag *KoTextDocument::paragAt(
int i )
const
1008 KoTextParag *s = fParag;
1010 if ( s->paragId() == i )
1017bool KoTextDocument::visitDocument(
KoParagVisitor *visitor,
bool forward )
1019 return visitFromTo( firstParag(), 0, lastParag(), lastParag()->length()-1, visitor, forward );
1022bool KoTextDocument::visitFromTo( KoTextParag *firstParag,
int firstIndex, KoTextParag* lastParag,
int lastIndex,
KoParagVisitor* visitor,
bool forw )
1024 if ( firstParag == lastParag )
1026 return visitor->
visit( firstParag, firstIndex, lastIndex );
1034 ret = visitor->
visit( firstParag, firstIndex, firstParag->length() - 1 );
1035 if (!ret)
return false;
1039 ret = visitor->
visit( lastParag, 0, lastIndex );
1040 if (!ret)
return false;
1043 KoTextParag* currentParag = forw ? firstParag->next() : lastParag->prev();
1044 KoTextParag * endParag = forw ? lastParag : firstParag;
1045 while ( currentParag && currentParag != endParag )
1047 ret = visitor->
visit( currentParag, 0, currentParag->length() - 1 );
1048 if (!ret)
return false;
1049 currentParag = forw ? currentParag->next() : currentParag->prev();
1051 Q_ASSERT( currentParag );
1052 Q_ASSERT( endParag == currentParag );
1054 ret = visitor->
visit( lastParag, 0, lastIndex );
1056 ret = visitor->
visit( currentParag, firstIndex, currentParag->length() - 1 );
1061static bool is_printer( TQPainter *p )
1063 return p && p->device() && p->device()->devType() == TQInternal::Printer;
1066KoTextParag *KoTextDocument::drawWYSIWYG( TQPainter *p,
int cx,
int cy,
int cw,
int ch,
const TQColorGroup &cg,
1068 bool drawCursor, KoTextCursor *cursor,
1069 bool resetChanged, uint drawingFlags )
1071 m_drawingFlags = drawingFlags;
1076 if ( is_printer( p ) || ( drawingFlags & TransparentBackground ) ) {
1081 TQRect crect( cx, cy, cw, ch );
1082 drawWithoutDoubleBuffer( p, crect, cg, zoomHandler );
1087 if ( !firstParag() )
1090 KoTextParag *lastFormatted = 0;
1091 KoTextParag *parag = firstParag();
1093 TQPixmap *doubleBuffer = 0;
1096 TQRect crect( cx, cy, cw, ch );
1098#ifdef DEBUG_PAINTING
1099 kdDebug(32500) <<
"\nKoTextDocument::drawWYSIWYG crect=" << crect << endl;
1103 TQRect pixelRect = parag->pixelRect( zoomHandler );
1104 if ( isPageBreakEnabled() && parag && cy <= pixelRect.y() && pixelRect.y() > 0 ) {
1106 zoomHandler->
layoutUnitToPixelX( parag->document()->x() + parag->document()->width() ),
1109 if ( !r.isEmpty() ) {
1110#ifdef DEBUG_PAINTING
1111 kdDebug(32500) <<
" drawWYSIWYG: space above first parag: " << r <<
" (pixels)" << endl;
1113 p->fillRect( r, cg.brush( TQColorGroup::Base ) );
1118 lastFormatted = parag;
1119 if ( !parag->isValid() )
1122 TQRect ir = parag->pixelRect( zoomHandler );
1123#ifdef DEBUG_PAINTING
1124 kdDebug(32500) <<
" drawWYSIWYG: ir=" << ir << endl;
1126 if ( isPageBreakEnabled() && parag->next() && ( drawingFlags & TransparentBackground ) == 0 )
1128 int nexty = parag->next()->pixelRect(zoomHandler).y();
1131 if ( ir.y() + ir.height() < nexty ) {
1132 TQRect r( 0, ir.y() + ir.height(),
1133 zoomHandler->
layoutUnitToPixelX( parag->document()->x() + parag->document()->width() ),
1134 nexty - ( ir.y() + ir.height() ) );
1138#ifdef DEBUG_PAINTING
1139 kdDebug(32500) <<
" drawWYSIWYG: space between parag " << parag->paragId() <<
" and " << parag->next()->paragId() <<
" : " << r <<
" (pixels)" << endl;
1141 p->fillRect( r, cg.brush( TQColorGroup::Base ) );
1146 if ( !ir.intersects( crect ) ) {
1149 if ( ir.intersects( crect ) && ( drawingFlags & TransparentBackground ) == 0 )
1150 p->fillRect( ir.intersect( crect ), cg.brush( TQColorGroup::Base ) );
1151 if ( ir.y() > cy + ch ) {
1155 else if ( parag->hasChanged() || !onlyChanged ) {
1159 if ( !onlyChanged && parag->lineChanged() > 0 )
1160 parag->setChanged(
false );
1161 drawParagWYSIWYG( p, parag, cx, cy, cw, ch, doubleBuffer, cg,
1162 zoomHandler, drawCursor, cursor, resetChanged, drawingFlags );
1164 parag = parag->next();
1167 parag = lastParag();
1170 pixelRect = parag->pixelRect(zoomHandler);
1171 int docheight = zoomHandler->layoutUnitToPixelY( parag->document()->height() );
1172 if ( pixelRect.y() + pixelRect.height() < docheight ) {
1174 if ( ( drawingFlags & TransparentBackground ) == 0 ) {
1175 p->fillRect( 0, pixelRect.y() + pixelRect.height(),
1176 docwidth, docheight - ( pixelRect.y() + pixelRect.height() ),
1177 cg.brush( TQColorGroup::Base ) );
1179 if ( !flow()->isEmpty() ) {
1180 TQRect cr( cx, cy, cw, ch );
1181 cr = cr.intersect( TQRect( 0, pixelRect.y() + pixelRect.height(), docwidth,
1182 docheight - ( pixelRect.y() + pixelRect.height() ) ) );
1183 flow()->drawFloatingItems( p, cr.x(), cr.y(), cr.width(), cr.height(), cg,
false );
1187 if ( buf_pixmap && buf_pixmap->height() > 300 ) {
1192 return lastFormatted;
1197void KoTextDocument::drawWithoutDoubleBuffer( TQPainter *p,
const TQRect &cr,
const TQColorGroup &cg,
1200 if ( !firstParag() )
1203 Q_ASSERT( (m_drawingFlags & DrawSelections) == 0 );
1204 if (m_drawingFlags & DrawSelections)
1205 kdDebug() << kdBacktrace();
1206 if ( paper && ( m_drawingFlags & TransparentBackground ) == 0 ) {
1207 p->setBrushOrigin( -(
int)p->translationX(), -(
int)p->translationY() );
1208 p->fillRect( cr, *paper );
1211 KoTextParag *parag = firstParag();
1213 if ( !parag->isValid() )
1216 TQRect pr( parag->pixelRect( zoomHandler ) );
1218 pr.setWidth( TQWIDGETSIZE_MAX );
1220 TQRect crect_lu( parag->rect() );
1222 if ( !cr.isNull() && !cr.intersects( pr ) ) {
1223 parag = parag->next();
1227 p->translate( 0, pr.y() );
1231 TQBrush brush = cg.brush( TQColorGroup::Base );;
1232 bool needBrush = brush.style() != TQt::NoBrush &&
1233 !(brush.style() == TQt::SolidPattern &&
1234 brush.color() == TQt::white &&
1236 if ( needBrush && ( m_drawingFlags & TransparentBackground ) == 0 )
1237 p->fillRect( TQRect( 0, 0, pr.width(), pr.height() ), brush );
1240 parag->paint( *p, cg, 0,
false,
1241 crect_lu.x(), crect_lu.y(),
1242 crect_lu.width(), crect_lu.height() );
1243 p->translate( 0, -pr.y() );
1245 parag = parag->next();
1251void KoTextDocument::drawParagWYSIWYG( TQPainter *p, KoTextParag *parag,
int cx,
int cy,
int cw,
int ch,
1252 TQPixmap *&doubleBuffer,
const TQColorGroup &cg,
1254 KoTextCursor *cursor,
bool resetChanged, uint drawingFlags )
1256 if ( cw <= 0 || ch <= 0 ) { Q_ASSERT( cw > 0 ); Q_ASSERT( ch > 0 );
return; }
1257#ifdef DEBUG_PAINTING
1258 kdDebug(32500) <<
"KoTextDocument::drawParagWYSIWYG " << (
void*)parag <<
" id:" << parag->paragId() << endl;
1260 m_drawingFlags = drawingFlags;
1261 TQPainter *painter = 0;
1263 TQRect rect = parag->pixelRect( zoomHandler );
1267 if ( parag->lineChanged() > -1 )
1269 offsetY = zoomHandler->layoutUnitToPixelY( parag->lineY( parag->lineChanged() ) - parag->topMargin() );
1270#ifdef DEBUG_PAINTING
1271 kdDebug(32500) <<
" Repainting from lineChanged=" << parag->lineChanged() <<
" -> adding " << offsetY <<
" to rect" << endl;
1274 rect.rTop() += offsetY;
1277 TQRect crect( cx, cy, cw, ch );
1280 TQBrush brush = cg.brush( TQColorGroup::Base );
1284 bool needBrush = brush.style() != TQt::NoBrush &&
1285 ( drawingFlags & TransparentBackground ) == 0 &&
1286 !(brush.style() == TQt::SolidPattern &&
1287 brush.color() == TQt::white &&
1290 bool useDoubleBuffer = !parag->document()->parent();
1291 if ( is_printer(p) )
1292 useDoubleBuffer =
false;
1297 TQWMatrix mat = p->worldMatrix();
1298 if ( ( mat.m11() != 1.0 || mat.m22() != 1.0 || mat.m12() != 0.0 || mat.m21() != 0.0 )
1299 && brush.style() != TQt::SolidPattern )
1300 useDoubleBuffer =
false;
1302#ifdef DEBUG_PAINTING
1303 kdDebug(32500) <<
"KoTextDocument::drawParagWYSIWYG parag->rect=" << parag->rect()
1304 <<
" pixelRect(ir)=" << ir
1305 <<
" crect (pixels)=" << crect
1306 <<
" useDoubleBuffer=" << useDoubleBuffer << endl;
1309 if ( useDoubleBuffer ) {
1310 painter =
new TQPainter;
1311 if ( cx >= 0 && cy >= 0 )
1312 ir = ir.intersect( crect );
1313 if ( !doubleBuffer ||
1314 ir.width() > doubleBuffer->width() ||
1315 ir.height() > doubleBuffer->height() )
1317 doubleBuffer = bufferPixmap( ir.size() );
1319 painter->begin( doubleBuffer );
1324 painter->translate( ir.x(), ir.y() );
1333 if ( useDoubleBuffer || is_printer( painter ) ) {
1335 if ( brush.style() != TQt::SolidPattern ) {
1336 bitBlt( doubleBuffer, 0, 0, p->device(),
1337 ir.x() + (
int)p->translationX(), ir.y() + (
int)p->translationY(),
1338 ir.width(), ir.height() );
1343 painter->fillRect( TQRect( 0, 0, ir.width(), ir.height() ), brush );
1346 painter->translate( rect.x() - ir.x(), rect.y() - ir.y() );
1347#ifdef DEBUG_PAINTING
1348 kdDebug(32500) <<
"KoTextDocument::drawParagWYSIWYG translate " << rect.x() - ir.x() <<
"," << rect.y() - ir.y() << endl;
1353 TQRect crect_lu( zoomHandler->pixelToLayoutUnit( crect ) );
1354#ifdef DEBUG_PAINTING
1355 kdDebug(32500) <<
"KoTextDocument::drawParagWYSIWYG crect_lu=" << crect_lu << endl;
1361 painter->translate( 0, -offsetY );
1363 parag->paint( *painter, cg, drawCursor ? cursor : 0, (m_drawingFlags & DrawSelections),
1364 crect_lu.x(), crect_lu.y(), crect_lu.width(), crect_lu.height() );
1367 if ( useDoubleBuffer ) {
1370 p->drawPixmap( ir.topLeft(), *doubleBuffer, TQRect( TQPoint( 0, 0 ), ir.size() ) );
1373 p->setPen( TQt::blue );
1374 p->drawRect( ir.x(), ir.y(), ir.width(), ir.height() );
1386 int docright = zoomHandler->
layoutUnitToPixelX( parag->document()->x() + parag->document()->width() );
1387#ifdef DEBUG_PAINTING
1390 if ( rect.x() + rect.width() < docright ) {
1391#ifdef DEBUG_PAINTING
1392 kdDebug(32500) <<
"KoTextDocument::drawParagWYSIWYG rect doesn't go up to docright=" << docright << endl;
1394 p->fillRect( rect.x() + rect.width(), rect.y(),
1395 docright - ( rect.x() + rect.width() ),
1396 rect.height(), cg.brush( TQColorGroup::Base ) );
1401 parag->setChanged(
false );
1405KoTextDocCommand *KoTextDocument::deleteTextCommand( KoTextDocument *textdoc,
int id,
int index,
const TQMemArray<KoTextStringChar> & str,
const CustomItemsMap & customItemsMap,
const TQValueList<KoParagLayout> & oldParagLayouts )
1407 return new KoTextDeleteCommand( textdoc,
id, index, str, customItemsMap, oldParagLayouts );
1410KoTextParag* KoTextDocument::loadOasisText(
const TQDomElement& bodyElem,
KoOasisContext& context, KoTextParag* lastParagraph,
KoStyleCollection* styleColl, KoTextParag* nextParagraph )
1414 forEachElement( tag, bodyElem )
1416 context.styleStack().save();
1417 const TQString localName = tag.localName();
1418 const bool isTextNS = tag.namespaceURI() == KoXmlNS::text;
1420 if ( isTextNS && localName ==
"p" ) {
1421 context.fillStyleStack( tag, KoXmlNS::text,
"style-name",
"paragraph" );
1423 KoTextParag *parag = createParag(
this, lastParagraph, nextParagraph );
1424 parag->loadOasis( tag, context, styleColl, pos );
1425 if ( !lastParagraph )
1426 setFirstParag( parag );
1427 lastParagraph = parag;
1429 else if ( isTextNS && localName ==
"h" )
1432 context.fillStyleStack( tag, KoXmlNS::text,
"style-name",
"paragraph" );
1433 int level = tag.attributeNS( KoXmlNS::text,
"outline-level", TQString() ).toInt();
1434 bool listOK =
false;
1445 listOK = context.pushOutlineListLevelStyle( level );
1446 int restartNumbering = -1;
1447 if ( tag.hasAttributeNS( KoXmlNS::text,
"start-value" ) )
1449 restartNumbering = tag.attributeNS( KoXmlNS::text,
"start-value", TQString() ).toInt();
1451 KoTextParag *parag = createParag(
this, lastParagraph, nextParagraph );
1452 parag->loadOasis( tag, context, styleColl, pos );
1453 if ( !lastParagraph )
1454 setFirstParag( parag );
1455 lastParagraph = parag;
1457 parag->applyListStyle( context, restartNumbering,
true ,
true , level );
1458 context.listStyleStack().pop();
1461 else if ( isTextNS &&
1462 ( localName ==
"unordered-list" || localName ==
"ordered-list"
1463 || localName ==
"list" || localName ==
"numbered-paragraph" ) )
1465 lastParagraph = loadList( tag, context, lastParagraph, styleColl, nextParagraph );
1467 else if ( isTextNS && localName ==
"section" )
1469 kdDebug(32500) <<
"Section found!" << endl;
1470 context.fillStyleStack( tag, KoXmlNS::text,
"style-name",
"section" );
1471 lastParagraph = loadOasisText( tag, context, lastParagraph, styleColl, nextParagraph );
1473 else if ( isTextNS && localName ==
"variable-decls" )
1478 else if ( isTextNS && localName ==
"user-field-decls" )
1481 forEachElement( fd, tag )
1483 if ( fd.namespaceURI() == KoXmlNS::text && fd.localName() ==
"user-field-decl" )
1485 const TQString
name = fd.attributeNS( KoXmlNS::text,
"name", TQString() );
1486 const TQString value = fd.attributeNS( KoXmlNS::office,
"value", TQString() );
1487 if ( !
name.isEmpty() )
1488 context.variableCollection().setVariableValue( name, value );
1492 else if ( isTextNS && localName ==
"number" )
1497 else if ( !loadOasisBodyTag( tag, context, lastParagraph, styleColl, nextParagraph ) )
1499 kdWarning(32500) <<
"Unsupported body element '" << localName <<
"'" << endl;
1502 context.styleStack().restore();
1506 return lastParagraph;
1509KoTextParag* KoTextDocument::loadList(
const TQDomElement& list,
KoOasisContext& context, KoTextParag* lastParagraph,
KoStyleCollection * styleColl, KoTextParag* nextParagraph )
1513 const TQString oldListStyleName = context.currentListStyleName();
1514 if ( list.hasAttributeNS( KoXmlNS::text,
"style-name" ) )
1515 context.setCurrentListStyleName( list.attributeNS( KoXmlNS::text,
"style-name", TQString() ) );
1516 bool listOK = !context.currentListStyleName().isEmpty();
1518 if ( list.localName() ==
"numbered-paragraph" )
1519 level = list.attributeNS( KoXmlNS::text,
"level",
"1" ).toInt();
1521 level = context.listStyleStack().level() + 1;
1523 listOK = context.pushListLevelStyle( context.currentListStyleName(), level );
1525 const TQDomElement listStyle = context.listStyleStack().currentListStyle();
1527 const bool orderedList = listStyle.localName() ==
"list-level-style-number";
1529 if ( list.localName() ==
"numbered-paragraph" )
1532 int restartNumbering = -1;
1533 if ( list.hasAttributeNS( KoXmlNS::text,
"start-value" ) )
1534 restartNumbering = list.attributeNS( KoXmlNS::text,
"start-value", TQString() ).toInt();
1535 KoTextParag* oldLast = lastParagraph;
1536 lastParagraph = loadOasisText( list, context, lastParagraph, styleColl, nextParagraph );
1537 KoTextParag* firstListItem = oldLast ? oldLast->next() : firstParag();
1540 bool isOutline = firstListItem->counter() && firstListItem->counter()->
numbering() == KoParagCounter::NUM_CHAPTER;
1541 firstListItem->applyListStyle( context, restartNumbering, orderedList,
1547 for ( TQDomNode n = list.firstChild(); !n.isNull(); n = n.nextSibling() )
1549 TQDomElement listItem = n.toElement();
1550 int restartNumbering = -1;
1551 if ( listItem.hasAttributeNS( KoXmlNS::text,
"start-value" ) )
1552 restartNumbering = listItem.attributeNS( KoXmlNS::text,
"start-value", TQString() ).toInt();
1553 bool isListHeader = listItem.localName() ==
"list-header" || listItem.attributeNS( KoXmlNS::text,
"is-list-header", TQString() ) ==
"is-list-header";
1554 KoTextParag* oldLast = lastParagraph;
1555 lastParagraph = loadOasisText( listItem, context, lastParagraph, styleColl, nextParagraph );
1556 KoTextParag* firstListItem = oldLast ? oldLast->next() : firstParag();
1557 KoTextParag* p = firstListItem;
1559 if ( !isListHeader && firstListItem ) {
1561 bool isOutline = firstListItem->counter() && firstListItem->counter()->
numbering() == KoParagCounter::NUM_CHAPTER;
1562 firstListItem->applyListStyle( context, restartNumbering, orderedList, isOutline, level );
1566 while ( p && p != lastParagraph->next() ) {
1568 p->counter()->setNumbering( KoParagCounter::NUM_NONE );
1574 context.listStyleStack().pop();
1575 context.setCurrentListStyleName( oldListStyleName );
1576 return lastParagraph;
1583 KoTextParag* parag = firstParag();
1586 parag->saveOasis( writer, context, 0, parag->lastCharPos() );
1587 parag = parag->next();
1591#include "KoTextDocument.moc"
A CustomItemsMap associates a custom item to an index Used in the undo/redo info for insert/delete te...
Used during loading of Oasis format (and discarded at the end of the loading).
void invalidate()
Invalidate the internal cache.
Numbering numbering() const
Numbering type and style.
KoParagCounter * counter
can be 0 if no counter set
Base class for "visitors".
virtual bool visit(KoTextParag *parag, int start, int end)=0
Visit the paragraph parag, from index start to index end.
Used during saving to Oasis format (and discarded at the end of the saving).
TODO rename to KoParagStyleCollection - or should char styles be part of it too?
KoTextCustomItem is the base class for custom items (i.e.
Each character (KoTextStringChar) points to a KoTextFormat that defines the formatting of that charac...
We implement our own text formatter to implement WYSIWYG: It is heavily based on KoTextFormatterBaseB...
This class extends KoZoomHandler to add support for WYSIWYG text layouting.
int layoutUnitToPixelX(int lupix) const
The "layout unit pixel" -> "[zoomed] view pixel" conversions.
A class for writing out XML (to any TQIODevice), with a special attention on performance.
TDEAction * forward(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)
const char * name(StdAction id)