21#include "KoTextParag.h"
22#include "KoTextDocument.h"
23#include "KoParagCounter.h"
24#include "KoTextZoomHandler.h"
25#include "KoStyleCollection.h"
26#include "KoVariable.h"
27#include <KoOasisContext.h>
28#include <KoXmlWriter.h>
29#include <KoGenStyles.h>
35#include <tdeglobalsettings.h>
40KoTextParag::KoTextParag( KoTextDocument *d, KoTextParag *pr, KoTextParag *nx,
bool updateIds )
41 : p( pr ), n( nx ), doc( d ),
45 newLinesAllowed( true ),
56 defFormat = formatCollection()->defaultFormat();
70 doc->setFirstParag(
this );
72 doc->setLastParag(
this );
83 if ( n && updateIds ) {
92 str =
new KoTextString();
93 str->insert( 0,
" ", formatCollection()->defaultFormat() );
94 setJoinBorder(
true );
97KoTextParag::~KoTextParag()
102 const int len = str->length();
103 for (
int i = 0; i < len; ++i ) {
104 KoTextStringChar *c = at( i );
105 if ( doc && c->isCustom() ) {
106 doc->unregisterCustomItem( c->customItem(),
this );
123 TQMap<int, KoTextParagLineStart*>::Iterator it = lineStarts.begin();
124 for ( ; it != lineStarts.end(); ++it )
126 if ( mSelections )
delete mSelections;
127 if ( mFloatingItems )
delete mFloatingItems;
135 if ( doc && !doc->isDestroying() )
137 doc->informParagraphDeleted(
this );
143void KoTextParag::setNext( KoTextParag *s )
147 doc->setLastParag(
this );
150void KoTextParag::setPrev( KoTextParag *s )
154 doc->setFirstParag(
this );
157void KoTextParag::invalidate(
int )
164 invalid = TQMIN( invalid, chr );
168void KoTextParag::setChanged(
bool b,
bool )
174void KoTextParag::setLineChanged(
short int line )
176 if ( m_lineChanged == -1 ) {
178 m_lineChanged = line;
181 m_lineChanged = TQMIN( m_lineChanged, line );
186void KoTextParag::insert(
int index,
const TQString &s )
188 str->insert( index, s, formatCollection()->defaultFormat() );
193void KoTextParag::truncate(
int index )
195 str->truncate( index );
196 insert( length(),
" " );
200void KoTextParag::remove(
int index,
int len )
202 if ( index + len - str->length() > 0 )
204 for (
int i = index; i < index + len; ++i ) {
205 KoTextStringChar *c = at( i );
206 if ( doc && c->isCustom() ) {
207 doc->unregisterCustomItem( c->customItem(),
this );
211 str->remove( index, len );
216void KoTextParag::join( KoTextParag *s )
219 int oh = r.height() + s->r.height();
224 doc->setLastParag(
this );
226 int start = str->length();
227 if ( length() > 0 && at( length() - 1 )->c ==
' ' ) {
228 remove( length() - 1, 1 );
231 append( s->str->toString(),
true );
233 for (
int i = 0; i < s->length(); ++i ) {
234 if ( doc->useFormatCollection() ) {
235 s->str->at( i ).format()->addRef();
236 str->setFormat( i + start, s->str->at( i ).format(),
true );
238 if ( s->str->at( i ).isCustom() ) {
239 KoTextCustomItem * item = s->str->at( i ).customItem();
240 str->at( i + start ).setCustomItem( item );
241 s->str->at( i ).loseCustomItem();
242 doc->unregisterCustomItem( item, s );
243 doc->registerCustomItem( item,
this );
246 Q_ASSERT(str->at(str->length()-1).c ==
' ');
257 invalidateCounters();
264 s->id = s->p->id + 1;
275void KoTextParag::move(
int &dy )
282 if ( mFloatingItems ) {
283 for ( KoTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() ) {
293 if ( doc && doc->isPageBreakEnabled() ) {
295 if ( ( shift = doc->formatter()->formatVertically( doc,
this ) ) ) {
297 p->setChanged(
true );
303void KoTextParag::format(
int start,
bool doMove )
305 if ( !str || str->length() == 0 || !formatter() )
313 r.moveTopLeft( TQPoint( documentX(), p ? p->r.y() + p->r.height() : documentY() ) );
318 bool formattedAgain =
false;
321 r.setWidth( documentWidth() );
324 if ( doc && mFloatingItems ) {
325 for ( KoTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() ) {
326 if ( i->placement() == KoTextCustomItem::PlaceRight )
327 i->move( r.x() + r.width() - i->width, r.y() );
329 i->move( i->x(), r.y() );
332 TQMap<int, KoTextParagLineStart*> oldLineStarts = lineStarts;
335 bool formatterWorked = formatter()->format( doc,
this, start, oldLineStarts, y, m_wused );
341 TQMap<int, KoTextParagLineStart*>::Iterator it = oldLineStarts.begin();
343 for ( ; it != oldLineStarts.end(); ++it )
350 setWidth( textDocument()->width() - 1 );
354 if ( lineStarts.count() == 1 ) {
360 r.setWidth( lineStarts[0]->w );
363 if ( newLinesAllowed ) {
364 it = lineStarts.begin();
365 int usedw = 0;
int lineid = 0;
366 for ( ; it != lineStarts.end(); ++it, ++lineid ) {
367 usedw = TQMAX( usedw, (*it)->w );
369 if ( r.width() <= 0 ) {
375 r.setWidth( TQMIN( usedw, r.width() ) );
380 if ( y != r.height() )
387 if ( doc && doc->isPageBreakEnabled() ) {
388 int shift = doc->formatter()->formatVertically( doc,
this );
390 if ( shift && !formattedAgain ) {
391 formattedAgain =
true;
397 doc->formatter()->postFormat(
this );
399 if ( n && doMove && n->isValid() && r.y() + r.height() != n->r.y() ) {
401 int dy = ( r.y() + r.height() ) - n->r.y();
403 bool makeInvalid =
false;
406 if ( s->movedDown ) {
410 if ( !s->isFullWidth() )
422 if ( mFloatingItems ) {
423#ifdef DEBUG_CI_PLACEMENT
424 kdDebug(32500) << lineStarts.count() <<
" lines" << endl;
431 TQMap<int, KoTextParagLineStart*>::Iterator it = lineStarts.begin();
432 for (
int i = 0 ; i < len; ++i ) {
433 KoTextStringChar *chr = &str->at( i );
434 if ( chr->lineStart ) {
439 baseLine = (*it)->baseLine;
440#ifdef DEBUG_CI_PLACEMENT
441 kdDebug(32500) <<
"New line (" << line <<
"): lineStart=" << (*it) <<
" lineY=" << lineY <<
" baseLine=" << baseLine <<
" height=" << (*it)->h << endl;
444 if ( chr->isCustom() ) {
446 KoTextCustomItem* item = chr->customItem();
447 Q_ASSERT( baseLine >= item->ascent() );
448 int y = lineY + baseLine - item->ascent();
449#ifdef DEBUG_CI_PLACEMENT
450 kdDebug(32500) <<
"Custom item: i=" << i <<
" x=" << x <<
" lineY=" << lineY <<
" baseLine=" << baseLine <<
" ascent=" << item->ascent() <<
" -> y=" << y << endl;
459 if ( formatterWorked )
467int KoTextParag::lineHeightOfChar(
int i,
int *bl,
int *y )
const
470 ( (KoTextParag*)
this )->format();
472 TQMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.end();
475 if ( i >= it.key() ) {
477 *bl = ( *it )->baseLine;
482 if ( it == lineStarts.begin() )
487 kdWarning(32500) <<
"KoTextParag::lineHeightOfChar: couldn't find lh for " << i << endl;
491KoTextStringChar *KoTextParag::lineStartOfChar(
int i,
int *index,
int *line )
const
494 ( (KoTextParag*)
this )->format();
496 int l = (int)lineStarts.count() - 1;
497 TQMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.end();
500 if ( i >= it.key() ) {
505 return &str->at( it.key() );
507 if ( it == lineStarts.begin() )
513 kdWarning(32500) <<
"KoTextParag::lineStartOfChar: couldn't find " << i << endl;
517int KoTextParag::lines()
const
520 ( (KoTextParag*)
this )->format();
522 return (
int)lineStarts.count();
525KoTextStringChar *KoTextParag::lineStartOfLine(
int line,
int *index )
const
528 ( (KoTextParag*)
this )->format();
530 if ( line >= 0 && line < (
int)lineStarts.count() ) {
531 TQMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
537 return &str->at( i );
540 kdWarning(32500) <<
"KoTextParag::lineStartOfLine: couldn't find " << line << endl;
544int KoTextParag::leftGap()
const
547 ( (KoTextParag*)
this )->format();
550 int x = str->at(0).x;
551 if ( str->isBidi() ) {
552 for (
int i = 1; i < str->length(); ++i )
553 x = TQMIN(x, str->at(i).x);
557 TQMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
558 while (line < (
int)lineStarts.count()) {
560 x = TQMIN(x, str->at(i).x);
567void KoTextParag::setFormat(
int index,
int len,
const KoTextFormat *_f,
bool useCollection,
int flags )
569 Q_ASSERT( useCollection );
572 if ( index > str->length() - 1 )
573 index = str->length() - 1;
574 if ( index + len >= str->length() )
575 len = str->length() - index;
577 KoTextFormatCollection *fc = 0;
579 fc = formatCollection();
581 for (
int i = 0; i < len; ++i ) {
582 of = str->at( i + index ).format();
583 if ( !changed && _f->key() != of->key() )
588 if ( m_invalid ==
false &&
589 ( _f->font().family() != of->font().family() ||
590 _f->pointSize() != of->pointSize() ||
591 _f->font().weight() != of->font().weight() ||
592 _f->font().italic() != of->font().italic() ||
593 _f->vAlign() != of->vAlign() ||
594 _f->relativeTextSize() != of->relativeTextSize() ||
595 _f->offsetFromBaseLine() != of->offsetFromBaseLine() ||
596 _f->wordByWord() != of->wordByWord() ||
597 _f->attributeFont() != of->attributeFont() ||
598 _f->language() != of->language() ||
599 _f->hyphenation() != of->hyphenation() ||
600 _f->shadowDistanceX() != of->shadowDistanceX() ||
601 _f->shadowDistanceY() != of->shadowDistanceY()
605 if ( flags == -1 || flags == KoTextFormat::Format || !fc ) {
606#ifdef DEBUG_COLLECTION
607 kdDebug(32500) <<
" KoTextParag::setFormat, will use format(f) " << f <<
" " << _f->key() << endl;
609 KoTextFormat* f = fc ? fc->format( _f ) :
const_cast<KoTextFormat *
>( _f );
610 str->setFormat( i + index, f, useCollection,
true );
612#ifdef DEBUG_COLLECTION
613 kdDebug(32500) <<
" KoTextParag::setFormat, will use format(of,f,flags) of=" << of <<
" " << of->key() <<
", f=" << _f <<
" " << _f->key() << endl;
615 KoTextFormat *fm = fc->format( of, _f, flags );
616#ifdef DEBUG_COLLECTION
617 kdDebug(32500) <<
" KoTextParag::setFormat, format(of,f,flags) returned " << fm <<
" " << fm->key() <<
" " << endl;
619 str->setFormat( i + index, fm, useCollection );
624void KoTextParag::drawCursorDefault( TQPainter &painter, KoTextCursor *cursor,
int curx,
int cury,
int curh,
const TQColorGroup &cg )
626 painter.fillRect( TQRect( curx, cury, 1, curh ), cg.color( TQColorGroup::Text ) );
628 if ( str->isBidi() ) {
630 if ( at( cursor->index() )->rightToLeft ) {
631 painter.setPen( TQt::black );
632 painter.drawLine( curx, cury, curx - d / 2, cury + d / 2 );
633 painter.drawLine( curx, cury + d, curx - d / 2, cury + d / 2 );
635 painter.setPen( TQt::black );
636 painter.drawLine( curx, cury, curx + d / 2, cury + d / 2 );
637 painter.drawLine( curx, cury + d, curx + d / 2, cury + d / 2 );
643int *KoTextParag::tabArray()
const
647 ta = doc->tabArray();
651int KoTextParag::nextTabDefault(
int,
int x )
656 ta = doc->tabArray();
657 int tabStopWidth = doc->tabStopWidth();
659 if ( tabStopWidth != 0 )
660 return tabStopWidth*(x/tabStopWidth+1);
665KoTextFormatCollection *KoTextParag::formatCollection()
const
668 return doc->formatCollection();
675void KoTextParag::show()
677 if ( visible || !doc )
682void KoTextParag::hide()
684 if ( !visible || !doc )
689void KoTextParag::setDirection( TQChar::Direction d )
691 if ( str && str->direction() != d ) {
692 str->setDirection( d );
695 m_layout.direction = d;
696 invalidateCounters();
701TQChar::Direction KoTextParag::direction()
const
703 return (str ? str->direction() : TQChar::DirON );
706void KoTextParag::setSelection(
int id,
int start,
int end )
708 TQMap<int, KoTextParagSelection>::ConstIterator it = selections().find(
id );
709 if ( it != mSelections->end() ) {
710 if ( start == ( *it ).start && end == ( *it ).end )
714 KoTextParagSelection sel;
717 (*mSelections)[ id ] = sel;
718 setChanged(
true,
true );
721void KoTextParag::removeSelection(
int id )
723 if ( !hasSelection(
id ) )
726 mSelections->remove(
id );
727 setChanged(
true,
true );
730int KoTextParag::selectionStart(
int id )
const
734 TQMap<int, KoTextParagSelection>::ConstIterator it = mSelections->find(
id );
735 if ( it == mSelections->end() )
737 return ( *it ).start;
740int KoTextParag::selectionEnd(
int id )
const
744 TQMap<int, KoTextParagSelection>::ConstIterator it = mSelections->find(
id );
745 if ( it == mSelections->end() )
750bool KoTextParag::hasSelection(
int id )
const
754 TQMap<int, KoTextParagSelection>::ConstIterator it = mSelections->find(
id );
755 if ( it == mSelections->end() )
757 return ( *it ).start != ( *it ).end || length() == 1;
760bool KoTextParag::fullSelected(
int id )
const
764 TQMap<int, KoTextParagSelection>::ConstIterator it = mSelections->find(
id );
765 if ( it == mSelections->end() )
767 return ( *it ).start == 0 && ( *it ).end == str->length() - 1;
770int KoTextParag::lineY(
int l )
const
772 if ( l > (
int)lineStarts.count() - 1 ) {
773 kdWarning(32500) <<
"KoTextParag::lineY: line " << l <<
" out of range!" << endl;
778 ( (KoTextParag*)
this )->format();
780 TQMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
786int KoTextParag::lineBaseLine(
int l )
const
788 if ( l > (
int)lineStarts.count() - 1 ) {
789 kdWarning(32500) <<
"KoTextParag::lineBaseLine: line " << l <<
" out of range!" << endl;
794 ( (KoTextParag*)
this )->format();
796 TQMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
799 return ( *it )->baseLine;
802int KoTextParag::lineHeight(
int l )
const
804 if ( l > (
int)lineStarts.count() - 1 ) {
805 kdWarning(32500) <<
"KoTextParag::lineHeight: line " << l <<
" out of range!" << endl;
810 ( (KoTextParag*)
this )->format();
812 TQMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
818void KoTextParag::lineInfo(
int l,
int &y,
int &h,
int &bl )
const
820 if ( l > (
int)lineStarts.count() - 1 ) {
821 kdWarning(32500) <<
"KoTextParag::lineInfo: line " << l <<
" out of range!" << endl;
822 kdDebug(32500) << (int)lineStarts.count() - 1 <<
" " << l << endl;
830 ( (KoTextParag*)
this )->format();
832 TQMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
837 bl = ( *it )->baseLine;
840uint KoTextParag::alignment()
const
848 bool doUpdate =
false;
849 if (defFormat && (defFormat != formatCollection()->defaultFormat()))
852 defFormat = formatCollection()->format( fm );
856 for (
int i = 0; i < length(); ++i ) {
857 if ( at( i )->format()->styleName() == defFormat->styleName() )
858 at( i )->format()->updateStyle();
863KoTextFormatterBase *KoTextParag::formatter()
const
866 return doc->formatter();
876int KoTextParag::widthUsed()
const
881void KoTextParag::setTabArray(
int *a )
887void KoTextParag::setTabStops(
int tw )
890 doc->setTabStops( tw );
895TQMap<int, KoTextParagSelection> &KoTextParag::selections()
const
898 ((KoTextParag *)
this)->mSelections =
new TQMap<int, KoTextParagSelection>;
902TQPtrList<KoTextCustomItem> &KoTextParag::floatingItems()
const
904 if ( !mFloatingItems )
905 ((KoTextParag *)
this)->mFloatingItems =
new TQPtrList<KoTextCustomItem>;
906 return *mFloatingItems;
909void KoTextCursor::setIndex(
int i,
bool )
916 if ( i < 0 || i > string->length() ) {
917#if defined(TQT_CHECK_RANGE)
918 kdWarning(32500) <<
"KoTextCursor::setIndex: " << i <<
" out of range" << endl;
921 i = i < 0 ? 0 :
string->length() - 1;
933 if ( !m_layout.counter )
937 if ( m_layout.counter->numbering() == KoParagCounter::NUM_NONE
939 && ( !m_layout.style || !m_layout.style->isOutline() ) )
941 return m_layout.counter;
944void KoTextParag::setMargin( TQStyleSheetItem::Margin m,
double _i )
947 m_layout.margins[m] = _i;
948 if ( m == TQStyleSheetItem::MarginTop && prev() )
949 prev()->invalidate(0);
953void KoTextParag::setMargins(
const double * margins )
955 for (
int i = 0 ; i < 5 ; ++i )
956 m_layout.margins[i] = margins[i];
960void KoTextParag::setAlign(
int align )
962 Q_ASSERT( align <= TQt::AlignJustify );
963 align &= TQt::AlignHorizontal_Mask;
964 setAlignment( align );
965 m_layout.alignment = align;
968int KoTextParag::resolveAlignment()
const
970 if ( (
int)m_layout.alignment == TQt::AlignAuto )
971 return str->isRightToLeft() ? TQt::AlignRight : TQt::AlignLeft;
972 return m_layout.alignment;
975void KoTextParag::setLineSpacing(
double _i )
977 m_layout.setLineSpacingValue(_i);
983 m_layout.lineSpacingType = _type;
987void KoTextParag::setTopBorder(
const KoBorder & _brd )
989 m_layout.topBorder = _brd;
993void KoTextParag::setBottomBorder(
const KoBorder & _brd )
995 m_layout.bottomBorder = _brd;
999void KoTextParag::setJoinBorder(
bool join )
1001 m_layout.joinBorder = join;
1005void KoTextParag::setBackgroundColor (
const TQColor& color )
1007 m_layout.backgroundColor = color;
1011void KoTextParag::setNoCounter()
1013 delete m_layout.counter;
1014 m_layout.counter = 0L;
1015 invalidateCounters();
1021 const bool isFootNote = m_layout.counter &&
1022 m_layout.counter->numbering() == KoParagCounter::NUM_FOOTNOTE;
1024 const TQString footNotePrefix = m_layout.counter->prefix();
1025 delete m_layout.counter;
1026 m_layout.counter = pCounter ?
new KoParagCounter( *pCounter ) : new KoParagCounter();
1027 m_layout.counter->setNumbering( KoParagCounter::NUM_FOOTNOTE );
1028 m_layout.counter->setStyle( KoParagCounter::STYLE_NONE );
1029 m_layout.counter->setPrefix( footNotePrefix );
1030 m_layout.counter->setSuffix( TQString() );
1031 invalidateCounters();
1034 setCounter( *pCounter );
1043 if ( counter.numbering() == KoParagCounter::NUM_NONE
1045 && ( !m_layout.style || !m_layout.style->isOutline() ) )
1051 delete m_layout.counter;
1052 m_layout.counter =
new KoParagCounter( counter );
1055 invalidateCounters();
1059void KoTextParag::invalidateCounters()
1064 if ( m_layout.counter )
1065 m_layout.counter->invalidate();
1066 KoTextParag *s = next();
1078int KoTextParag::counterWidth()
const
1080 if ( !m_layout.counter )
1083 return m_layout.counter->width(
this );
1088void KoTextParag::drawLabel( TQPainter* p,
int xLU,
int yLU,
int ,
int ,
int baseLU,
const TQColorGroup& )
1090 if ( !m_layout.counter )
1093 if ( m_layout.counter->numbering() == KoParagCounter::NUM_NONE )
1096 int counterWidthLU = m_layout.counter->width(
this );
1099 KoTextFormat counterFormat( *KoParagCounter::counterFormat(
this ) );
1100 if ( !m_layout.style || !m_layout.style->isOutline() )
1104 counterFormat.setBold(
false );
1105 counterFormat.setItalic(
false );
1107 KoTextFormat* format = &counterFormat;
1110 TQColor textColor( format->color() );
1111 if ( !textColor.isValid() )
1113 p->setPen( TQPen( textColor ) );
1115 KoTextZoomHandler * zh = textDocument()->paintingZoomHandler();
1119 bool rtl = str->isRightToLeft();
1121 int y = zh->layoutUnitToPixelY( yLU );
1123 int base = zh->layoutUnitToPixelY( yLU, baseLU );
1125 int height = zh->layoutUnitToPixelY( yLU, format->height() );
1127 TQFont font( format->screenFont( zh ) );
1129 if ( m_layout.counter->numbering() == KoParagCounter::NUM_FOOTNOTE )
1131 int pointSize = ( ( font.pointSize() * 2 ) / 3 );
1132 font.setPointSize( pointSize );
1133 y -= ( height - TQFontMetrics(font).height() );
1138 if ( m_layout.counter->isBullet() )
1149 TQString prefix = m_layout.counter->prefix();
1150 if ( !prefix.isEmpty() )
1153 prefix.prepend(
' ' );
1154 KoTextParag::drawFontEffects( p, format, zh, format->screenFont( zh ), textColor, xLeft, base, width, y, height, prefix[0] );
1156 int posY =y + base - format->offsetFromBaseLine();
1159 int sy = format->shadowY( zh );
1163 p->drawText( xLeft, posY, prefix );
1166 TQRect er( xBullet + (rtl ? width : 0), y + height / 2 - width / 2, width, width );
1169 switch ( m_layout.counter->style() )
1171 case KoParagCounter::STYLE_DISCBULLET:
1172 p->setBrush( TQBrush(textColor) );
1173 p->drawEllipse( er );
1174 p->setBrush( TQt::NoBrush );
1176 case KoParagCounter::STYLE_SQUAREBULLET:
1177 p->fillRect( er, TQBrush(textColor) );
1179 case KoParagCounter::STYLE_BOXBULLET:
1182 case KoParagCounter::STYLE_CIRCLEBULLET:
1183 p->drawEllipse( er );
1185 case KoParagCounter::STYLE_CUSTOMBULLET:
1189 if ( !m_layout.counter->customBulletFont().isEmpty() )
1191 TQFont bulletFont( p->font() );
1192 bulletFont.setFamily( m_layout.counter->customBulletFont() );
1193 p->setFont( bulletFont );
1195 KoTextParag::drawFontEffects( p, format, zh, format->screenFont( zh ), textColor, xBullet, base, width, y, height,
' ' );
1197 posY = y + base- format->offsetFromBaseLine();
1200 int sy = format->shadowY( zh );
1204 p->drawText( xBullet, posY, TQString(m_layout.counter->customBulletCharacter()) );
1211 TQString suffix = m_layout.counter->suffix();
1212 if ( !suffix.isEmpty() )
1217 KoTextParag::drawFontEffects( p, format, zh, format->screenFont( zh ), textColor, xBullet + width, base, counterWidth, y,height, suffix[0] );
1219 int posY =y + base- format->offsetFromBaseLine();
1222 int sy = format->shadowY( zh );
1226 p->drawText( xBullet + width, posY, suffix, -1 );
1231 TQString counterText = m_layout.counter->text(
this );
1234 if ( !counterText.isEmpty() )
1236 KoTextParag::drawFontEffects( p, format, zh, format->screenFont( zh ), textColor, xLeft, base, counterWidth, y, height, counterText[0] );
1238 counterText +=
' ' ;
1240 int posY =y + base - format->offsetFromBaseLine();
1243 int sy = format->shadowY( zh );
1247 p->drawText( xLeft, posY , counterText, -1 );
1253int KoTextParag::breakableTopMargin()
const
1255 KoTextZoomHandler * zh = textDocument()->formattingZoomHandler();
1256 return zh->ptToLayoutUnitPixY(
1257 m_layout.margins[ TQStyleSheetItem::MarginTop ] );
1260int KoTextParag::topMargin()
const
1262 KoTextZoomHandler * zh = textDocument()->formattingZoomHandler();
1263 return zh->ptToLayoutUnitPixY(
1264 m_layout.margins[ TQStyleSheetItem::MarginTop ]
1265 + ( ( prev() && prev()->joinBorder() && prev()->bottomBorder() == m_layout.bottomBorder &&
1266 prev()->topBorder() == m_layout.topBorder && prev()->leftBorder() == m_layout.leftBorder &&
1267 prev()->rightBorder() == m_layout.rightBorder) ? 0 : m_layout.topBorder.width() ) );
1270int KoTextParag::bottomMargin()
const
1272 KoTextZoomHandler * zh = textDocument()->formattingZoomHandler();
1273 return zh->ptToLayoutUnitPixY(
1274 m_layout.margins[ TQStyleSheetItem::MarginBottom ]
1275 + ( ( joinBorder() && next() && next()->bottomBorder() == m_layout.bottomBorder &&
1276 next()->topBorder() == m_layout.topBorder && next()->leftBorder() == m_layout.leftBorder &&
1277 next()->rightBorder() == m_layout.rightBorder) ? 0 : m_layout.bottomBorder.width() ) );
1280int KoTextParag::leftMargin()
const
1282 KoTextZoomHandler * zh = textDocument()->formattingZoomHandler();
1284 m_layout.margins[ TQStyleSheetItem::MarginLeft ]
1285 + m_layout.leftBorder.width() );
1288int KoTextParag::rightMargin()
const
1290 KoTextZoomHandler * zh = textDocument()->formattingZoomHandler();
1292 if( m_layout.counter && str->isRightToLeft() &&
1293 (( m_layout.counter->alignment() == TQt::AlignRight ) || ( m_layout.counter->alignment() == TQt::AlignAuto )))
1294 cw = counterWidth();
1297 m_layout.margins[ TQStyleSheetItem::MarginRight ]
1298 + m_layout.rightBorder.width() )
1302int KoTextParag::firstLineMargin()
const
1304 KoTextZoomHandler * zh = textDocument()->formattingZoomHandler();
1305 return zh->ptToLayoutUnitPixY(
1306 m_layout.margins[ TQStyleSheetItem::MarginFirstLine ] );
1309int KoTextParag::lineSpacing(
int line )
const
1311 Q_ASSERT( isValid() );
1312 if ( m_layout.lineSpacingType == KoParagLayout::LS_SINGLE )
1315 if( line >= (
int)lineStarts.count() )
1317 kdError() <<
"KoTextParag::lineSpacing assert(line<lines) failed: line=" << line <<
" lines=" << lineStarts.count() << endl;
1320 TQMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
1321 while ( line-- > 0 )
1323 return (*it)->lineSpacing;
1328int KoTextParag::calculateLineSpacing(
int line,
int startChar,
int lastChar )
const
1330 KoTextZoomHandler * zh = textDocument()->formattingZoomHandler();
1333 if ( m_layout.lineSpacingType == KoParagLayout::LS_SINGLE )
1335 else if ( m_layout.lineSpacingType == KoParagLayout::LS_CUSTOM )
1336 return zh->ptToLayoutUnitPixY( m_layout.lineSpacingValue() ) + shadow;
1338 if( line >= (
int)lineStarts.count() )
1340 kdError() <<
"KoTextParag::lineSpacing assert(line<lines) failed: line=" << line <<
" lines=" << lineStarts.count() << endl;
1343 TQMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
1344 while ( line-- > 0 )
1348 switch ( m_layout.lineSpacingType )
1350 case KoParagLayout::LS_MULTIPLE:
1352 double n = m_layout.lineSpacingValue() - 1.0;
1353 return shadow + tqRound( n * heightForLineSpacing( startChar, lastChar ) );
1355 case KoParagLayout::LS_ONEANDHALF:
1358 return shadow + heightForLineSpacing( startChar, lastChar ) / 2;
1360 case KoParagLayout::LS_DOUBLE:
1363 return shadow + heightForLineSpacing( startChar, lastChar );
1365 case KoParagLayout::LS_AT_LEAST:
1367 int atLeast = zh->ptToLayoutUnitPixY( m_layout.lineSpacingValue() );
1368 const int lineHeight = ( *it )->h;
1369 int h = TQMAX( lineHeight, atLeast );
1371 return shadow + h - lineHeight;
1373 case KoParagLayout::LS_FIXED:
1375 const int lineHeight = ( *it )->h;
1376 return shadow + zh->ptToLayoutUnitPixY( m_layout.lineSpacingValue() ) - lineHeight;
1379 case KoParagLayout::LS_SINGLE:
1380 case KoParagLayout::LS_CUSTOM:
1384 kdWarning() <<
"Unhandled linespacing type : " << m_layout.lineSpacingType << endl;
1390 TQRect rct( zh->layoutUnitToPixel( rect() ) );
1397 TQRect prevRect( zh->layoutUnitToPixel( prev()->rect() ) );
1398 if ( rct.top() < prevRect.bottom() + 1 )
1401 rct.setTop( prevRect.bottom() + 1 );
1409void KoTextParag::paint( TQPainter &painter,
const TQColorGroup &cg, KoTextCursor *cursor,
bool drawSelections,
1410 int clipx,
int clipy,
int clipw,
int cliph )
1413 kdDebug(32500) <<
"KoTextParag::paint ===== id=" << paragId() <<
" clipx=" << clipx <<
" clipy=" << clipy <<
" clipw=" << clipw <<
" cliph=" << cliph << endl;
1414 kdDebug(32500) <<
" clipw in pix (approx) : " << textDocument()->paintingZoomHandler()->layoutUnitToPixelX( clipw ) <<
" cliph in pix (approx) : " << textDocument()->paintingZoomHandler()->layoutUnitToPixelX( cliph ) << endl;
1417 KoTextZoomHandler * zh = textDocument()->paintingZoomHandler();
1420 TQRect paraRect = pixelRect( zh );
1428 int leftExtent = TQMIN ( leftMarginPix, leftMarginPix + firstLineOffset );
1432 if ( backgroundColor().isValid() )
1436 int backgroundWidth = rightExtent - leftExtent + 1;
1437 int backgroundHeight = pixelRect( zh ).height();
1438 painter.fillRect( leftExtent, 0,
1439 backgroundWidth, backgroundHeight,
1440 backgroundColor() );
1444 if ( m_layout.counter && m_layout.counter->numbering() != KoParagCounter::NUM_NONE && m_lineChanged <= 0 )
1446 int cy, h, baseLine;
1447 lineInfo( 0, cy, h, baseLine );
1448 int xLabel = at(0)->x;
1449 if ( str->isRightToLeft() )
1450 xLabel += at(0)->width;
1451 drawLabel( &painter, xLabel, cy, 0, 0, baseLine, cg );
1454 paintLines( painter, cg, cursor, drawSelections, clipx, clipy, clipw, cliph );
1457 if ( m_layout.hasBorder() )
1459 bool const drawTopBorder = !prev() || !prev()->joinBorder() || prev()->bottomBorder() != bottomBorder() || prev()->topBorder() != topBorder() || prev()->leftBorder() != leftBorder() || prev()->rightBorder() != rightBorder();
1460 bool const drawBottomBorder = !joinBorder() || !next() || next()->bottomBorder() != bottomBorder() || next()->topBorder() != topBorder() || next()->leftBorder() != leftBorder() || next()->rightBorder() != rightBorder();
1471 r.setLeft( leftExtent );
1472 r.setRight( rightExtent );
1473 r.setTop( zh->layoutUnitToPixelY(lineY( 0 )) );
1475 int lastLine = lines() - 1;
1478 int paragBottom = pixelRect(zh).height()-1;
1481 if ( m_layout.bottomBorder.width() > 0 && drawBottomBorder)
1482 paragBottom -= zh->layoutUnitToPixelY( lineSpacing( lastLine ) );
1483 paragBottom -= KoBorder::zoomWidthY( m_layout.bottomBorder.width(), zh, 0 );
1486 r.setBottom( paragBottom );
1489 KoBorder::drawBorders( painter, zh, r,
1490 m_layout.leftBorder, m_layout.rightBorder, m_layout.topBorder, m_layout.bottomBorder,
1491 0, TQPen(), drawTopBorder, drawBottomBorder );
1496void KoTextParag::paintLines( TQPainter &painter,
const TQColorGroup &cg, KoTextCursor *cursor,
bool drawSelections,
1497 int clipx,
int clipy,
int clipw,
int cliph )
1506#define CHECK_PIXELXADJ
1508 int curx = -1, cury = 0, curh = 0, curline = 0;
1509 int xstart, xend = 0;
1511 TQString qstr = str->toString();
1512 qstr.replace( TQChar(0x00a0U),
' ' );
1514 const int nSels = doc ? doc->numSelections() : 1;
1515 TQMemArray<int> selectionStarts( nSels );
1516 TQMemArray<int> selectionEnds( nSels );
1517 if ( drawSelections ) {
1518 bool hasASelection =
false;
1519 for (
int i = 0; i < nSels; ++i ) {
1520 if ( !hasSelection( i ) ) {
1521 selectionStarts[ i ] = -1;
1522 selectionEnds[ i ] = -1;
1524 hasASelection =
true;
1525 selectionStarts[ i ] = selectionStart( i );
1526 int end = selectionEnd( i );
1527 if ( end == length() - 1 && n && n->hasSelection( i ) )
1529 selectionEnds[ i ] = end;
1532 if ( !hasASelection )
1533 drawSelections =
false;
1537 int line = m_lineChanged;
1538 if (line<0) line = 0;
1540 int numLines = lines();
1542 kdDebug(32500) <<
" paintLines: from line " << line <<
" to " << numLines-1 << endl;
1544 for( ; line<numLines ; line++ )
1549 lineStartOfLine(line, &startOfLine);
1550 if (line == numLines-1 )
1551 nextLine = length();
1553 lineStartOfLine(line+1, &nextLine);
1556 int cy, h, baseLine;
1557 lineInfo( line, cy, h, baseLine );
1558 if ( clipy != -1 && cy > clipy - r.y() + cliph )
1562 int paintStart = startOfLine;
1563 KoTextStringChar* chr = at(startOfLine);
1564 KoTextStringChar* nextchr = chr;
1567 for(
int i=startOfLine;i<nextLine;i++)
1570 if ( i < nextLine-1 )
1571 nextchr = at( i+1 );
1574 bool flush = ( i == nextLine - 1 );
1578 flush = flush || ( nextchr->format() != chr->format() );
1582 if ( !flush && chr->format()->attributeFont() == KoTextFormat::ATT_SMALL_CAPS )
1584 bool isLowercase = chr->c.upper() != chr->c;
1585 bool nextLowercase = nextchr->c.upper() != nextchr->c;
1586 flush = isLowercase != nextLowercase;
1589 flush = flush || nextchr->startOfRun;
1591 flush = flush || ( nextchr->rightToLeft != chr->rightToLeft );
1592#ifdef CHECK_PIXELXADJ
1595 flush = flush || ( nextchr->pixelxadj != chr->pixelxadj && nextchr->charStop );
1598 flush = flush || ( chr->c ==
'\t' || nextchr->c ==
'\t' );
1600 flush = flush || ( chr->c.unicode() == 0xad );
1602 flush = flush || chr->isCustom();
1604 flush = flush || nextchr->isCustom();
1606 if ((alignment() & TQt::AlignJustify) == TQt::AlignJustify )
1608 flush = flush || chr->whiteSpace;
1610 if (!flush && chr->format()->wordByWord() && chr->format()->isStrikedOrUnderlined())
1611 flush = flush || chr->whiteSpace || nextchr->whiteSpace;
1613 flush = flush || ( i - paintStart >= 256 );
1615 if ( drawSelections ) {
1617 bool selectionChange =
false;
1618 if ( drawSelections ) {
1619 for (
int j = 0; j < nSels; ++j ) {
1620 selectionChange = selectionStarts[ j ] == i+1 || selectionEnds[ j ] == i+1;
1621 if ( selectionChange )
1625 flush = flush || selectionChange;
1629 if ( cursor &&
this == cursor->parag() && i == cursor->index() ) {
1632 KoTextStringChar *c = chr;
1636 cury = cy + baseLine - c->ascent();
1641 KoTextStringChar* cStart = at( paintStart );
1642 if ( chr->rightToLeft ) {
1644 xend = cStart->x + cStart->width;
1647 if ( i < length() - 1 && !str->at( i + 1 ).lineStart &&
1648 str->at( i + 1 ).rightToLeft == chr->rightToLeft )
1649 xend = str->at( i + 1 ).x;
1651 xend = chr->x + chr->width;
1654 if ( (clipx == -1 || clipw == -1) || (xend >= clipx && xstart <= clipx + clipw) ) {
1655 if ( !chr->isCustom() ) {
1656 drawParagString( painter, qstr, paintStart, i - paintStart + 1, xstart, cy,
1657 baseLine, xend-xstart, h, drawSelections,
1658 chr->format(), selectionStarts, selectionEnds,
1659 cg, chr->rightToLeft, line );
1662 if ( chr->customItem()->placement() == KoTextCustomItem::PlaceInline ) {
1663 chr->customItem()->draw( &painter, chr->x, cy + baseLine - chr->customItem()->ascent(),
1664 clipx - r.x(), clipy - r.y(), clipw, cliph, cg,
1665 drawSelections && nSels && selectionStarts[ 0 ] <= i && selectionEnds[ 0 ] > i );
1674 if ( curx != -1 && cursor ) {
1675 drawCursor( painter, cursor, curx, cury, curh, cg );
1682void KoTextParag::drawParagString( TQPainter &painter,
const TQString &str,
int start,
int len,
int startX,
1683 int lastY,
int baseLine,
int bw,
int h,
bool drawSelections,
1684 KoTextFormat *format,
const TQMemArray<int> &selectionStarts,
1685 const TQMemArray<int> &selectionEnds,
const TQColorGroup &cg,
bool rightToLeft,
int line )
1687 KoTextZoomHandler * zh = textDocument()->paintingZoomHandler();
1691 kdDebug(32500) <<
"KoTextParag::drawParagString drawing from " << start <<
" to " << start+len << endl;
1692 kdDebug(32500) <<
" startX in LU: " << startX <<
" lastY in LU:" << lastY
1693 <<
" baseLine in LU:" << baseLine << endl;
1700 int shadowOffsetY_pix = zh->layoutUnitToPixelY( format->offsetY() );
1705 kdDebug(32500) <<
"KoTextParag::drawParagString startX in pixels : " << startX_pix <<
" bw=" << bw << endl;
1709 int lastY_pix = zh->layoutUnitToPixelY( lastY );
1710 int baseLine_pix = zh->layoutUnitToPixelY( lastY, baseLine );
1711 int h_pix = zh->layoutUnitToPixelY( lastY, h );
1713 kdDebug(32500) <<
"KoTextParag::drawParagString h(LU)=" << h <<
" lastY(LU)=" << lastY
1714 <<
" h(PIX)=" << h_pix <<
" lastY(PIX)=" << lastY_pix
1715 <<
" baseLine(PIX)=" << baseLine_pix << endl;
1718 if ( format->textBackgroundColor().isValid() )
1719 painter.fillRect( startX_pix, lastY_pix, bw_pix, h_pix, format->textBackgroundColor() );
1723 int draw_startX = startX;
1724 int draw_bw = bw_pix;
1725 if ( at( start + len - 1 )->c ==
'\n' )
1728 draw_bw -= at( start + len - 1 )->pixelwidth;
1729 if ( rightToLeft && draw_len > 0 )
1730 draw_startX = at( start + draw_len - 1 )->x;
1735 if ( drawSelections ) {
1736 bool inSelection =
false;
1737 const int nSels = doc ? doc->numSelections() : 1;
1738 for (
int j = 0; j < nSels; ++j ) {
1739 if ( start >= selectionStarts[ j ] && start < selectionEnds[ j ] ) {
1742 case KoTextDocument::Standard:
1743 painter.fillRect( startX_pix, lastY_pix, bw_pix, h_pix, cg.color( TQColorGroup::Highlight ) );
1745 case KoTextDocument::InputMethodPreedit:
1749 painter.fillRect( startX_pix, lastY_pix, bw_pix, h_pix, doc ? doc->selectionColor( j ) : cg.color( TQColorGroup::Highlight ) );
1755 drawSelections =
false;
1759 const int nSels = doc ? doc->numSelections() : 1;
1760 if ( KoTextDocument::InputMethodPreedit < nSels
1761 && doc->hasSelection( KoTextDocument::InputMethodPreedit )
1762 && start >= selectionStarts[ KoTextDocument::InputMethodPreedit ]
1763 && start < selectionEnds[ KoTextDocument::InputMethodPreedit ] )
1765 TQColor textColor( format->color() );
1766 painter.setPen( TQPen( textColor ) );
1768 TQPoint p1( startX_pix, lastY_pix + h_pix - 1 );
1769 TQPoint p2( startX_pix + bw_pix, lastY_pix + h_pix - 1 );
1770 painter.drawLine( p1, p2 );
1776 draw_startX_pix += shadowOffsetX_pix;
1777 lastY_pix += shadowOffsetY_pix;
1779 if ( format->shadowDistanceX() != 0 || format->shadowDistanceY() != 0 ) {
1780 int sx = format->shadowX( zh );
1781 int sy = format->shadowY( zh );
1782 if ( sx != 0 || sy != 0 )
1785 painter.translate( sx, sy );
1786 drawParagStringInternal( painter, str, start, draw_len, draw_startX_pix,
1787 lastY_pix, baseLine_pix,
1790 format, selectionStarts,
1791 selectionEnds, cg, rightToLeft, line, zh,
true );
1796 drawParagStringInternal( painter, str, start, draw_len, draw_startX_pix,
1797 lastY_pix, baseLine_pix,
1799 h_pix, drawSelections, format, selectionStarts,
1800 selectionEnds, cg, rightToLeft, line, zh,
false );
1803 bool forPrint = ( painter.device()->devType() == TQInternal::Printer );
1804 if ( textDocument()->drawFormattingChars() && !forPrint )
1806 drawFormattingChars( painter, start, len,
1807 lastY_pix, baseLine_pix, h_pix,
1809 format, selectionStarts,
1810 selectionEnds, cg, rightToLeft,
1811 line, zh, AllFormattingChars );
1819void KoTextParag::drawParagStringInternal( TQPainter &painter,
const TQString &s,
int start,
int len,
int startX,
1820 int lastY,
int baseLine,
int bw,
int h,
bool drawSelections,
1821 KoTextFormat *format,
const TQMemArray<int> &selectionStarts,
1822 const TQMemArray<int> &selectionEnds,
const TQColorGroup &cg,
bool rightToLeft,
int line,
KoTextZoomHandler* zh,
bool drawingShadow )
1825 kdDebug(32500) <<
"KoTextParag::drawParagStringInternal start=" << start <<
" len=" << len <<
" : '" << s.mid(start,len) <<
"'" << endl;
1826 kdDebug(32500) <<
"In pixels: startX=" << startX <<
" lastY=" << lastY <<
" baseLine=" << baseLine
1827 <<
" bw=" << bw <<
" h=" << h <<
" rightToLeft=" << rightToLeft << endl;
1829 if ( drawingShadow && format->shadowDistanceX() == 0 && format->shadowDistanceY() == 0 )
1832 TQColor textColor( drawingShadow ? format->shadowColor() : format->color() );
1833 if ( !textColor.isValid() )
1837 TQFont font( format->screenFont( zh ) );
1838 if ( format->attributeFont() == KoTextFormat::ATT_SMALL_CAPS && s[start].upper() != s[start] )
1839 font = format->smallCapsFont( zh,
true );
1842 TQFontInfo fi( font );
1843 kdDebug(32500) <<
"KoTextParag::drawParagStringInternal requested font " << font.pointSizeFloat() <<
" using font " << fi.pointSize() <<
"pt (format font: " << format->font().pointSizeFloat() <<
"pt)" << endl;
1844 TQFontMetrics fm( font );
1845 kdDebug(32500) <<
"Real font: " << fi.family() <<
". Font height in pixels: " << fm.height() << endl;
1850 if ( str[ (
int)str.length() - 1 ].unicode() == 0xad )
1851 str.remove( str.length() - 1, 1 );
1852 painter.setPen( TQPen( textColor ) );
1853 painter.setFont( font );
1855 KoTextDocument* doc = document();
1857 if ( drawSelections ) {
1858 const int nSels = doc ? doc->numSelections() : 1;
1859 for (
int j = 0; j < nSels; ++j ) {
1860 if ( start >= selectionStarts[ j ] && start < selectionEnds[ j ] ) {
1861 if ( !doc || doc->invertSelectionText( j ) )
1862 textColor = cg.color( TQColorGroup::HighlightedText );
1863 painter.setPen( TQPen( textColor ) );
1869 TQPainter::TextDirection dir = rightToLeft ? TQPainter::RTL : TQPainter::LTR;
1871 if ( dir != TQPainter::RTL && start + len == length() )
1876 bw-=at(length()-1)->pixelwidth;
1878 KoTextParag::drawFontEffects( &painter, format, zh, font, textColor, startX, baseLine, bw, lastY, h, str[start] );
1880 if ( str[ start ] !=
'\t' && str[ start ].unicode() != 0xad ) {
1881 str = format->displayedString( str );
1882 if ( format->vAlign() == KoTextFormat::AlignNormal ) {
1883 int posY = lastY + baseLine;
1886 int sy = format->shadowY( zh );
1889 painter.drawText( startX, posY, str, start, len, dir );
1892 painter.setPen ( TQt::red );
1893 painter.drawLine( startX, lastY, startX, lastY + baseLine );
1894 painter.drawLine( startX, lastY + baseLine/2, startX + 10, lastY + baseLine/2 );
1898 w += painter.fontMetrics().charWidth( str, start + i++ );
1899 painter.setPen ( TQt::blue );
1900 painter.drawLine( startX + w - 1, lastY, startX + w - 1, lastY + baseLine );
1901 painter.drawLine( startX + w - 1, lastY + baseLine/2, startX + w - 1 - 10, lastY + baseLine/2 );
1904 }
else if ( format->vAlign() == KoTextFormat::AlignSuperScript ) {
1905 int posY =lastY + baseLine - ( painter.fontMetrics().height() / 2 );
1908 int sy = format->shadowY( zh );
1911 painter.drawText( startX, posY, str, start, len, dir );
1912 }
else if ( format->vAlign() == KoTextFormat::AlignSubScript ) {
1913 int posY =lastY + baseLine + ( painter.fontMetrics().height() / 6 );
1916 int sy = format->shadowY( zh );
1919 painter.drawText( startX, posY, str, start, len, dir );
1920 }
else if ( format->vAlign() == KoTextFormat::AlignCustom ) {
1921 int posY = lastY + baseLine - format->offsetFromBaseLine();
1924 int sy = format->shadowY( zh );
1927 painter.drawText( startX, posY, str, start, len, dir );
1930 if ( str[ start ] ==
'\t' && m_tabCache.contains( start ) ) {
1932 KoTextZoomHandler * zh = textDocument()->paintingZoomHandler();
1933 const KoTabulator& tab = m_layout.tabList()[ m_tabCache[ start ] ];
1934 int lineWidth = zh->zoomItY( tab.
ptWidth );
1937 painter.setPen( TQPen( textColor, lineWidth, TQt::DotLine ) );
1938 painter.drawLine( startX, lastY + baseLine, startX + bw, lastY + baseLine );
1941 painter.setPen( TQPen( textColor, lineWidth, TQt::SolidLine ) );
1942 painter.drawLine( startX, lastY + baseLine, startX + bw, lastY + baseLine );
1945 painter.setPen( TQPen( textColor, lineWidth, TQt::DashLine ) );
1946 painter.drawLine( startX, lastY + baseLine, startX + bw, lastY + baseLine );
1949 painter.setPen( TQPen( textColor, lineWidth, TQt::DashDotLine ) );
1950 painter.drawLine( startX, lastY + baseLine, startX + bw, lastY + baseLine );
1952 case TF_DASH_DOT_DOT:
1953 painter.setPen( TQPen( textColor, lineWidth, TQt::DashDotDotLine ) );
1954 painter.drawLine( startX, lastY + baseLine, startX + bw, lastY + baseLine );
1963 if ( start+len < length() && at( start+len )->lineStart )
1968 bool drawHyphen = at( start+len-1 )->c.unicode() == 0xad;
1969 drawHyphen = drawHyphen || lineHyphenated( line );
1972 kdDebug(32500) <<
"drawing hyphen at x=" << startX+bw << endl;
1974 painter.drawText( startX + bw, lastY + baseLine, TQString(
"-") );
1980 painter.device()->devType() != TQInternal::Printer &&
1981 format->isMisspelled() &&
1983 textDocument()->drawingMissingSpellLine() )
1986 painter.setPen( TQPen( TQt::red, 1 ) );
1989 for(
int zigzag_line = 0; zigzag_line < 3; ++zigzag_line )
1991 for(
int zigzag_x = zigzag_line; zigzag_x < bw; zigzag_x += 4 )
1995 lastY + baseLine + h/12 - 1 + zigzag_line );
2000 for(
int zigzag_x = 3; zigzag_x < bw; zigzag_x += 4 )
2004 lastY + baseLine + h/12 );
2011bool KoTextParag::lineHyphenated(
int l )
const
2013 if ( l > (
int)lineStarts.count() - 1 ) {
2014 kdWarning() <<
"KoTextParag::lineHyphenated: line " << l <<
" out of range!" << endl;
2019 const_cast<KoTextParag*
>(
this)->format();
2021 TQMap<int, KoTextParagLineStart*>::ConstIterator it = lineStarts.begin();
2024 return ( *it )->hyphenated;
2028void KoTextParag::drawCursor( TQPainter &painter, KoTextCursor *cursor,
int curx,
int cury,
int curh,
const TQColorGroup &cg )
2030 KoTextZoomHandler * zh = textDocument()->paintingZoomHandler();
2033 KoTextParag::drawCursorDefault( painter, cursor, x,
2034 zh->layoutUnitToPixelY( cury ),
2035 zh->layoutUnitToPixelY( cury, curh ), cg );
2039void KoTextParag::copyParagData( KoTextParag *parag )
2042 KoParagStyle * style = parag->style();
2044 bool styleApplied =
false;
2047 KoParagStyle * newStyle = style->followingStyle();
2048 if ( newStyle && style != newStyle )
2050 setParagLayout( newStyle->paragLayout() );
2051 KoTextFormat * format = &newStyle->
format();
2052 setFormat( format );
2054 str->setFormat( 0, format,
true );
2055 styleApplied =
true;
2065 setParagLayout( parag->paragLayout() );
2067 parag->m_layout.pageBreaking &= ~KoParagLayout::HardFrameBreakBefore;
2068 parag->m_layout.pageBreaking &= ~KoParagLayout::HardFrameBreakAfter;
2070 if ( m_layout.counter && m_layout.counter->numbering() == KoParagCounter::NUM_FOOTNOTE )
2073 if ( m_layout.counter )
2074 m_layout.counter->setRestartCounter(
false);
2077 setFormat( parag->at( parag->length()-1 )->format() );
2088void KoTextParag::setTabList(
const KoTabulatorList &tabList )
2090 KoTabulatorList lst( tabList );
2091 m_layout.setTabList( lst );
2092 if ( !tabList.isEmpty() )
2094 KoTextZoomHandler* zh = textDocument()->formattingZoomHandler();
2095 int * tabs =
new int[ tabList.count() + 1 ];
2096 KoTabulatorList::Iterator it = lst.begin();
2098 for ( ; it != lst.end() ; ++it, ++i )
2101 assert( i == tabList.count() );
2102 setTabArray( tabs );
2111int KoTextParag::nextTab(
int chnum,
int x,
int availableWidth )
2113 if ( !m_layout.tabList().isEmpty() )
2117 int * tArray = tabArray();
2119 if ( str->isRightToLeft() )
2120 i = m_layout.tabList().size() - 1;
2121 KoTextZoomHandler* zh = textDocument()->formattingZoomHandler();
2123 while ( i >= 0 && i < (
int)m_layout.tabList().size() ) {
2125 int tab = tArray[ i ];
2130 if ( tab > availableWidth ) {
2132 tab = availableWidth;
2135 if ( str->isRightToLeft() )
2136 tab = availableWidth - tab;
2139 int type = m_layout.tabList()[i].type;
2142 if ( str->isRightToLeft() )
2143 if ( type == T_RIGHT )
2145 else if ( type == T_LEFT )
2155 while ( c < str->length() - 1 && str->at( c ).c !=
'\t' && str->at( c ).c !=
'\n' )
2157 KoTextStringChar & ch = str->at( c );
2160 if ( ch.isCustom() )
2161 w += ch.customItem()->width;
2164 KoTextFormat *charFormat = ch.format();
2165 int ww = charFormat->
charWidth( zh,
false, &ch,
this, c );
2172 m_tabCache[chnum] = i;
2174 if ( type == T_RIGHT )
2185 while ( c < str->length()-1 && str->at( c ).c !=
'\t' && str->at( c ).c !=
'\n' )
2187 KoTextStringChar & ch = str->at( c );
2188 if ( ch.c == m_layout.tabList()[i].alignChar )
2191 int ww = ch.format()->charWidth( zh,
false, &ch,
this, c );
2193 if ( str->isRightToLeft() )
2207 if ( ch.isCustom() )
2208 w += ch.customItem()->width;
2211 int ww = ch.format()->charWidth( zh,
false, &ch,
this, c );
2217 m_tabCache[chnum] = i;
2221 m_tabCache[chnum] = i;
2225 if ( str->isRightToLeft() )
2232 return KoTextParag::nextTabDefault( chnum, x );
2237 setParagLayout( style->paragLayout() );
2238 KoTextFormat *newFormat = &style->format();
2239 setFormat( 0, str->length(), newFormat );
2240 setFormat( newFormat );
2243void KoTextParag::setParagLayout(
const KoParagLayout & layout,
int flags,
int marginIndex )
2246 if ( flags & KoParagLayout::Alignment )
2248 if ( flags & KoParagLayout::Margins ) {
2249 if ( marginIndex == -1 )
2252 setMargin( (TQStyleSheetItem::Margin)marginIndex, layout.
margins[marginIndex] );
2254 if ( flags & KoParagLayout::LineSpacing )
2256 setLineSpacingType( layout.lineSpacingType );
2257 setLineSpacing( layout.lineSpacingValue() );
2259 if ( flags & KoParagLayout::Borders )
2261 setLeftBorder( layout.leftBorder );
2262 setRightBorder( layout.rightBorder );
2263 setTopBorder( layout.topBorder );
2264 setBottomBorder( layout.bottomBorder );
2265 setJoinBorder( layout.joinBorder );
2267 if ( flags & KoParagLayout::BackgroundColor )
2271 if ( flags & KoParagLayout::BulletNumber )
2273 if ( flags & KoParagLayout::Tabulator )
2274 setTabList( layout.tabList() );
2275 if ( flags == KoParagLayout::All )
2277 setDirection(
static_cast<TQChar::Direction
>(layout.direction) );
2279 setStyle( layout.style );
2287 if ( currentFormat )
2288 setFormat( index, 1, currentFormat );
2289 at( index )->setCustomItem( custom );
2291 document()->registerCustomItem( custom,
this );
2297void KoTextParag::removeCustomItem(
int index )
2299 Q_ASSERT( at( index )->isCustom() );
2300 KoTextCustomItem * item = at( index )->customItem();
2301 at( index )->loseCustomItem();
2303 document()->unregisterCustomItem( item,
this );
2309 int len = str->length();
2310 for (
int i = 0; i < len; ++i )
2312 KoTextStringChar & ch = str->at(i);
2313 if ( ch.isCustom() && ch.customItem() == custom )
2316 kdWarning() <<
"KoTextParag::findCustomItem custom item " << (
void*)custom
2317 <<
" not found in paragraph " << paragId() << endl;
2322void KoTextParag::printRTDebug(
int info )
2324 TQString specialFlags;
2325 if ( str->needsSpellCheck() )
2326 specialFlags +=
" needsSpellCheck=true";
2327 if ( wasMovedDown() )
2328 specialFlags +=
" wasMovedDown=true";
2329 if ( partOfTableOfContents() )
2330 specialFlags +=
" part-of-TOC=true";
2331 kdDebug(32500) <<
"Paragraph " <<
this <<
" (" << paragId() <<
") [changed="
2332 << hasChanged() <<
", valid=" << isValid()
2334 <<
"] ------------------ " << endl;
2335 if ( prev() && prev()->paragId() + 1 != paragId() )
2336 kdWarning() <<
" Previous paragraph " << prev() <<
" has ID " << prev()->paragId() << endl;
2337 if ( next() && next()->paragId() != paragId() + 1 )
2338 kdWarning() <<
" Next paragraph " << next() <<
" has ID " << next()->paragId() << endl;
2341 kdDebug(32500) <<
" Style: " << style() <<
" " << ( style() ? style()->name().local8Bit().data() :
"NO STYLE" ) << endl;
2342 kdDebug(32500) <<
" Text: '" << str->toString() <<
"'" << endl;
2345 if ( m_layout.counter )
2347 m_layout.counter->printRTDebug(
this );
2349 static const char *
const s_align[] = {
"Auto",
"Left",
"Right",
"ERROR",
"HCenter",
"ERR",
"ERR",
"ERR",
"Justify", };
2350 static const char *
const s_linespacing[] = {
"Single",
"1.5",
"2",
"custom",
"atLeast",
"Multiple",
"Fixed" };
2351 static const char *
const s_dir[] = {
"DirL",
"DirR",
"DirEN",
"DirES",
"DirET",
"DirAN",
"DirCS",
"DirB",
"DirS",
"DirWS",
"DirON",
"DirLRE",
"DirLRO",
"DirAL",
"DirRLE",
"DirRLO",
"DirPDF",
"DirNSM",
"DirBN" };
2352 kdDebug(32500) <<
" align: " << s_align[alignment()] <<
" resolveAlignment: " << s_align[resolveAlignment()]
2353 <<
" isRTL:" << str->isRightToLeft()
2354 <<
" dir: " << s_dir[direction()] << endl;
2355 TQRect pixr = pixelRect( textDocument()->paintingZoomHandler() );
2356 kdDebug(32500) <<
" rect() : " << DEBUGRECT( rect() )
2357 <<
" pixelRect() : " << DEBUGRECT( pixr ) << endl;
2358 kdDebug(32500) <<
" topMargin()=" << topMargin()
2359 <<
" breakableTopMargin()=" << breakableTopMargin()
2360 <<
" bottomMargin()=" << bottomMargin()
2361 <<
" leftMargin()=" << leftMargin() <<
" firstLineMargin()=" << firstLineMargin()
2362 <<
" rightMargin()=" << rightMargin() << endl;
2363 if ( kwLineSpacingType() != KoParagLayout::LS_SINGLE )
2364 kdDebug(32500) <<
" linespacing type=" << s_linespacing[ -kwLineSpacingType() ]
2365 <<
" value=" << kwLineSpacing() << endl;
2366 const int pageBreaking = m_layout.pageBreaking;
2367 TQStringList pageBreakingFlags;
2368 if ( pageBreaking & KoParagLayout::KeepLinesTogether )
2369 pageBreakingFlags.append(
"KeepLinesTogether" );
2370 if ( pageBreaking & KoParagLayout::HardFrameBreakBefore )
2371 pageBreakingFlags.append(
"HardFrameBreakBefore" );
2372 if ( pageBreaking & KoParagLayout::HardFrameBreakAfter )
2373 pageBreakingFlags.append(
"HardFrameBreakAfter" );
2374 if ( pageBreaking & KoParagLayout::KeepWithPrevious )
2375 pageBreakingFlags.append(
"KeepWithPrevious" );
2376 if ( pageBreaking & KoParagLayout::KeepWithNext )
2377 pageBreakingFlags.append(
"KeepWithNext" );
2378 if ( !pageBreakingFlags.isEmpty() )
2379 kdDebug(32500) <<
" page Breaking: " << pageBreakingFlags.join(
",") << endl;
2381 static const char *
const tabtype[] = {
"T_LEFT",
"T_CENTER",
"T_RIGHT",
"T_DEC_PNT",
"error!!!" };
2382 KoTabulatorList tabList = m_layout.tabList();
2383 if ( tabList.isEmpty() ) {
2384 if ( str->toString().find(
'\t' ) != -1 )
2385 kdDebug(32500) <<
"Tab width: " << textDocument()->tabStopWidth() << endl;
2387 KoTabulatorList::Iterator it = tabList.begin();
2388 for ( ; it != tabList.end() ; it++ )
2389 kdDebug(32500) <<
"Tab type:" << tabtype[(*it).type] <<
" at: " << (*it).ptPos << endl;
2391 }
else if ( info == 1 )
2393 kdDebug(32500) <<
" Paragraph format=" << paragFormat() <<
" " << paragFormat()->key()
2394 <<
" fontsize:" <<
dynamic_cast<KoTextFormat *
>(paragFormat())->pointSize() << endl;
2396 for (
int line = 0 ; line < lines(); ++ line ) {
2398 lineInfo( line, y, h, baseLine );
2400 lineStartOfLine( line, &startOfLine );
2401 kdDebug(32500) <<
" Line " << line <<
" y=" << y <<
" height=" << h <<
" baseLine=" << baseLine <<
" startOfLine(index)=" << startOfLine << endl;
2403 kdDebug(32500) << endl;
2404 KoTextString * s = string();
2407 for (
int i = 0 ; i < s->length() ; ++i )
2409 KoTextStringChar & ch = s->at(i);
2410 int pixelx = textDocument()->formattingZoomHandler()->layoutUnitToPixelX( ch.x )
2413 kdDebug(32500) <<
"LINESTART" << endl;
2414 TQString attrs =
" ";
2415 if ( ch.whiteSpace )
2416 attrs +=
"whitespace ";
2418 attrs +=
"notCharStop ";
2420 attrs +=
"wordStop ";
2421 attrs.truncate( attrs.length() - 1 );
2423 kdDebug(32500) << i <<
": '" << TQString(ch.c).rightJustify(2)
2424 <<
"' (" << TQString::number( ch.c.unicode() ).rightJustify(3) <<
")"
2425 <<
" x(LU)=" << ch.x
2426 <<
" w(LU)=" << ch.width
2427 <<
" x(PIX)=" << pixelx
2428 <<
" (xadj=" << + ch.pixelxadj <<
")"
2429 <<
" w(PIX)=" << ch.pixelwidth
2430 <<
" height=" << ch.height()
2438 if ( ch.format() != textDocument()->formatCollection()->defaultFormat() )
2439 Q_ASSERT( textDocument()->formatCollection()->dict()[ch.format()->key()] );
2441 if ( !str->isBidi() && !ch.lineStart )
2442 Q_ASSERT( lastX + lastW == pixelx );
2444 lastW = ch.pixelwidth;
2445 if ( ch.isCustom() )
2447 KoTextCustomItem * item = ch.customItem();
2448 kdDebug(32500) <<
" - custom item " << item
2449 <<
" ownline=" << item->ownLine()
2450 <<
" size=" << item->width <<
"x" << item->height
2451 <<
" ascent=" << item->ascent()
2459void KoTextParag::drawFontEffects( TQPainter * p,
KoTextFormat *format,
KoTextZoomHandler *zh, TQFont font,
const TQColor & color,
int startX,
int baseLine,
int bw,
int lastY,
int , TQChar firstChar )
2463 if ( !format->isStrikedOrUnderlined() )
2468 if ( format->wordByWord() && firstChar.isSpace() )
2474 if (format->vAlign() == KoTextFormat::AlignSubScript )
2475 offset = p->fontMetrics().height() / 6;
2476 else if (format->vAlign() == KoTextFormat::AlignSuperScript )
2477 offset = -p->fontMetrics().height() / 2;
2479 dimd = KoBorder::zoomWidthY( format->underLineWidth(), zh, 1 );
2480 if((format->vAlign() == KoTextFormat::AlignSuperScript) ||
2481 (format->vAlign() == KoTextFormat::AlignSubScript ) || (format->vAlign() == KoTextFormat::AlignCustom ))
2482 dimd*=format->relativeTextSize();
2483 y = lastY + baseLine + offset - ( (format->vAlign() == KoTextFormat::AlignCustom)?format->offsetFromBaseLine():0 );
2485 if ( format->doubleUnderline())
2487 TQColor col = format->textUnderlineColor().isValid() ? format->textUnderlineColor(): color ;
2488 int dim=
static_cast<int>(0.75*dimd);
2492 switch( format->underlineStyle())
2494 case KoTextFormat::U_SOLID:
2495 p->setPen( TQPen( col, dim, TQt::SolidLine ) );
2497 case KoTextFormat::U_DASH:
2498 p->setPen( TQPen( col, dim, TQt::DashLine ) );
2500 case KoTextFormat::U_DOT:
2501 p->setPen( TQPen( col, dim, TQt::DotLine ) );
2503 case KoTextFormat::U_DASH_DOT:
2504 p->setPen( TQPen( col, dim, TQt::DashDotLine ) );
2506 case KoTextFormat::U_DASH_DOT_DOT:
2507 p->setPen( TQPen( col, dim, TQt::DashDotDotLine ) );
2510 p->setPen( TQPen( color, dim, TQt::SolidLine ) );
2513 y +=
static_cast<int>(1.125*dimd);
2514 p->drawLine( startX, y, startX + bw, y );
2515 y +=
static_cast<int>(1.5*dimd);
2516 p->drawLine( startX, y, startX + bw, y );
2518 if ( font.underline() ) {
2519 font.setUnderline(
false );
2523 else if ( format->underline() ||
2524 format->underlineType() == KoTextFormat::U_SIMPLE_BOLD)
2527 TQColor col = format->textUnderlineColor().isValid() ? format->textUnderlineColor(): color ;
2529 int dim=(format->underlineType() == KoTextFormat::U_SIMPLE_BOLD)?
static_cast<int>(2*dimd):static_cast<int>(dimd);
2531 y +=
static_cast<int>(1.875*dimd);
2533 switch( format->underlineStyle() )
2535 case KoTextFormat::U_SOLID:
2536 p->setPen( TQPen( col, dim, TQt::SolidLine ) );
2538 case KoTextFormat::U_DASH:
2539 p->setPen( TQPen( col, dim, TQt::DashLine ) );
2541 case KoTextFormat::U_DOT:
2542 p->setPen( TQPen( col, dim, TQt::DotLine ) );
2544 case KoTextFormat::U_DASH_DOT:
2545 p->setPen( TQPen( col, dim, TQt::DashDotLine ) );
2547 case KoTextFormat::U_DASH_DOT_DOT:
2548 p->setPen( TQPen( col, dim, TQt::DashDotDotLine ) );
2551 p->setPen( TQPen( col, dim, TQt::SolidLine ) );
2554 p->drawLine( startX, y, startX + bw, y );
2556 font.setUnderline(
false );
2559 else if ( format->waveUnderline() )
2561 int dim=
static_cast<int>(dimd);
2564 TQColor col = format->textUnderlineColor().isValid() ? format->textUnderlineColor(): color ;
2566 int offset = 2 * dim;
2567 TQPen pen(col, dim, TQt::SolidLine);
2568 pen.setCapStyle(TQt::RoundCap);
2571 double anc=acos(1.0-2*(
static_cast<double>(offset-(startX)%offset)/
static_cast<double>(offset)))/3.1415*180;
2574 if(2*((startX/offset)/2)==startX/offset)
2577 p->drawArc( (startX/offset)*offset, y, offset, offset, 0, -tqRound(pos*anc*16) );
2579 int zigzag_x = (startX/offset+1)*offset;
2580 for ( ; zigzag_x + offset <= bw+startX; zigzag_x += offset)
2582 p->drawArc( zigzag_x, y, offset, offset, 0, pos*180*16 );
2586 anc=acos(1.0-2*(
static_cast<double>((startX+bw)%offset)/
static_cast<double>(offset)))/3.1415*180;
2587 p->drawArc( zigzag_x, y, offset, offset, 180*16, -tqRound(pos*anc*16) );
2589 font.setUnderline(
false );
2593 dimd = KoBorder::zoomWidthY(
static_cast<double>(format->pointSize())/18.0, zh, 1 );
2594 if((format->vAlign() == KoTextFormat::AlignSuperScript) ||
2595 (format->vAlign() == KoTextFormat::AlignSubScript ) || (format->vAlign() == KoTextFormat::AlignCustom ))
2596 dimd*=format->relativeTextSize();
2597 y = lastY + baseLine + offset - ( (format->vAlign() == KoTextFormat::AlignCustom)?format->offsetFromBaseLine():0 );
2599 if ( format->strikeOutType() == KoTextFormat::S_SIMPLE
2600 || format->strikeOutType() == KoTextFormat::S_SIMPLE_BOLD)
2602 unsigned int dim = (format->strikeOutType() == KoTextFormat::S_SIMPLE_BOLD)?
static_cast<int>(2*dimd) : static_cast<int>(dimd);
2605 switch( format->strikeOutStyle() )
2607 case KoTextFormat::S_SOLID:
2608 p->setPen( TQPen( color, dim, TQt::SolidLine ) );
2610 case KoTextFormat::S_DASH:
2611 p->setPen( TQPen( color, dim, TQt::DashLine ) );
2613 case KoTextFormat::S_DOT:
2614 p->setPen( TQPen( color, dim, TQt::DotLine ) );
2616 case KoTextFormat::S_DASH_DOT:
2617 p->setPen( TQPen( color, dim, TQt::DashDotLine ) );
2619 case KoTextFormat::S_DASH_DOT_DOT:
2620 p->setPen( TQPen( color, dim, TQt::DashDotDotLine ) );
2623 p->setPen( TQPen( color, dim, TQt::SolidLine ) );
2626 y -=
static_cast<int>(5*dimd);
2627 p->drawLine( startX, y, startX + bw, y );
2629 font.setStrikeOut(
false );
2632 else if ( format->strikeOutType() == KoTextFormat::S_DOUBLE )
2634 unsigned int dim =
static_cast<int>(dimd);
2637 switch( format->strikeOutStyle() )
2639 case KoTextFormat::S_SOLID:
2640 p->setPen( TQPen( color, dim, TQt::SolidLine ) );
2642 case KoTextFormat::S_DASH:
2643 p->setPen( TQPen( color, dim, TQt::DashLine ) );
2645 case KoTextFormat::S_DOT:
2646 p->setPen( TQPen( color, dim, TQt::DotLine ) );
2648 case KoTextFormat::S_DASH_DOT:
2649 p->setPen( TQPen( color, dim, TQt::DashDotLine ) );
2651 case KoTextFormat::S_DASH_DOT_DOT:
2652 p->setPen( TQPen( color, dim, TQt::DashDotDotLine ) );
2655 p->setPen( TQPen( color, dim, TQt::SolidLine ) );
2658 y -=
static_cast<int>(4*dimd);
2659 p->drawLine( startX, y, startX + bw, y);
2660 y -=
static_cast<int>(2*dimd);
2661 p->drawLine( startX, y, startX + bw, y);
2663 font.setStrikeOut(
false );
2670TQString KoTextParag::toString(
int from,
int length )
const
2673 if ( from == 0 && m_layout.counter && m_layout.counter->numbering() != KoParagCounter::NUM_FOOTNOTE )
2674 str += m_layout.counter->text(
this ) +
' ';
2676 length = this->length() - 1 - from;
2677 for (
int i = from ; i < (length+from) ; ++i )
2679 KoTextStringChar *ch = at( i );
2680 if ( ch->isCustom() )
2682 KoVariable * var =
dynamic_cast<KoVariable *
>(ch->customItem());
2684 str += var->
text(
true);
2698static TQString normalizeWhitespace(
const TQString& in,
bool leadingSpace )
2702 int len = text.length();
2704 for ( r = 0; r < len; ++r )
2706 TQCharRef ch = text[r];
2709 if ( ch ==
' ' || ch ==
'\t' ||ch ==
'\r' || ch ==
'\n')
2713 if ( r != 0 || !leadingSpace )
2714 text[w++] = TQChar(
' ' );
2717 while ( r < len && text[r].isSpace() )
2722 text[w++] = text[r];
2736void KoTextParag::loadOasisSpan(
const TQDomElement& parent,
KoOasisContext& context, uint& pos,
bool stripLeadingSpace )
2740 return loadOasisSpan( parent, context, pos, stripLeadingSpace, &dummy );
2743void KoTextParag::loadOasisSpan(
const TQDomElement& parent,
KoOasisContext& context, uint& pos,
bool stripLeadingSpace,
bool *hasTrailingSpace )
2748 for ( node = parent.firstChild(); !node.isNull(); node = node.nextSibling() )
2750 TQDomElement ts = node.toElement();
2752 const TQString localName( ts.localName() );
2753 const bool isTextNS = ts.namespaceURI() == KoXmlNS::text;
2754 KoTextCustomItem* customItem = 0;
2757 context.styleStack().save();
2760 if ( node.isText() )
2762 textData = normalizeWhitespace( node.toText().data(), stripLeadingSpace );
2763 *hasTrailingSpace = stripLeadingSpace = textData[textData.length() - 1].isSpace();
2765 else if ( isTextNS && localName ==
"span" )
2767 context.styleStack().save();
2768 context.fillStyleStack( ts, KoXmlNS::text,
"style-name",
"text" );
2776 loadOasisSpan( ts, context, pos, stripLeadingSpace, hasTrailingSpace );
2777 stripLeadingSpace = *hasTrailingSpace;
2778 context.styleStack().restore();
2780 else if ( isTextNS && localName ==
"s" )
2783 if (ts.hasAttributeNS( KoXmlNS::text,
"c"))
2784 howmany = ts.attributeNS( KoXmlNS::text,
"c", TQString()).toInt();
2786 textData.fill(32, howmany);
2788 else if ( isTextNS && localName ==
"tab" )
2792 else if ( isTextNS && localName ==
"line-break" )
2796 else if ( isTextNS && localName ==
"number" )
2801 else if ( node.isProcessingInstruction() )
2803 TQDomProcessingInstruction pi = node.toProcessingInstruction();
2804 if ( pi.target() ==
"opendocument" && pi.data().startsWith(
"cursor-position" ) )
2806 context.setCursorPosition(
this, pos );
2811 bool handled =
false;
2813 KoVariable* var = context.variableCollection().loadOasisField( textDocument(), ts, context );
2822 handled = textDocument()->loadSpanTag( ts, context,
2824 textData, customItem );
2827 kdWarning(32500) <<
"Ignoring tag " << ts.tagName() << endl;
2828 context.styleStack().restore();
2834 const uint length = textData.length();
2837 insert( pos, textData );
2839 setCustomItem( pos, customItem, 0 );
2843 setFormat( pos, length, document()->formatCollection()->format( &f ),
true );
2846 context.styleStack().restore();
2852 KoParagLayout layout;
2857 KoParagStyle *style;
2860 TQString styleName = context.styleStack().userStyleName(
"paragraph" );
2861 if ( !styleName.isEmpty() )
2863 style = styleCollection->
findStyle( styleName );
2866 style = styleCollection->
findStyleByDisplayName( context.styleStack().userStyleDisplayName(
"paragraph" ) );
2869 kdError(32500) <<
"Cannot find style \"" << styleName <<
"\" - using Standard" << endl;
2870 style = styleCollection->
findStyle(
"Standard" );
2876 kdError(32500) <<
"No style name !? - using Standard" << endl;
2877 style = styleCollection->
findStyle(
"Standard" );
2880 layout.style = style;
2891 KoParagLayout paragLayout = loadParagLayout( context, styleCollection,
true );
2892 setParagLayout( paragLayout );
2895 KoTextFormat defaultFormat;
2896 defaultFormat.load( context );
2897 setFormat( document()->formatCollection()->format( &defaultFormat ) );
2901 loadOasisSpan( parent, context, pos,
true );
2904 const int len = str->length();
2905 Q_ASSERT( len >= 1 );
2906 setFormat( len - 1, 1, paragFormat(),
true );
2916 KoGenStyles& mainStyles = context.mainStyles();
2919 TQString parentStyleName;
2920 if ( m_layout.style )
2921 parentStyleName = m_layout.style->name();
2923 KoGenStyle autoStyle( KoGenStyle::STYLE_AUTO,
"paragraph", parentStyleName );
2924 paragFormat()->save( autoStyle, context );
2925 m_layout.saveOasis( autoStyle, context,
false );
2929 if ( context.variableSettings() )
2930 autoStyle.addProperty(
"style:page-number", context.variableSettings()->startingPageNumber() );
2932 autoStyle.addAttribute(
"style:master-page-name",
"Standard" );
2936 TQString autoParagStyleName = mainStyles.
lookup( autoStyle,
"P", KoGenStyles::ForceNumbering );
2938 KoParagCounter* paragCounter = m_layout.counter;
2940 bool outline = m_layout.style && m_layout.style->isOutline() && paragCounter;
2941 bool normalList = paragCounter && paragCounter->style() != KoParagCounter::STYLE_NONE && !outline;
2949 KoGenStyle listStyle( KoGenStyle::STYLE_AUTO_LIST );
2952 TQString autoListStyleName = mainStyles.
lookup( listStyle,
"L", KoGenStyles::ForceNumbering );
2953 writer.
addAttribute(
"text:style-name", autoListStyleName );
2955 TQString textNumber = m_layout.counter->text(
this );
2956 if ( !textNumber.isEmpty() )
2967 writer.
addAttribute(
"text:style-name", autoParagStyleName );
2969 if ( paragCounter->
numbering() == KoParagCounter::NUM_NONE )
2972 TQString textNumber = paragCounter->text(
this );
2973 if ( !textNumber.isEmpty() )
2985 writer.
addAttribute(
"text:style-name", autoParagStyleName );
2988 TQString text = str->toString();
2989 Q_ASSERT( text.right(1)[0] ==
' ' );
2991 const int cursorIndex = context.cursorTextParagraph() ==
this ? context.cursorTextIndex() : -1;
2996#define WRITESPAN( next ) { \
2997 if ( curFormat == paragFormat() ) { \
2998 writer.addTextSpan( text.mid( startPos, next - startPos ), m_tabCache ); \
3000 KoGenStyle gs( KoGenStyle::STYLE_AUTO, "text" ); \
3001 curFormat->save( gs, context, paragFormat() ); \
3002 writer.startElement( "text:span" ); \
3003 if ( !gs.isEmpty() ) { \
3004 const TQString autoStyleName = mainStyles.lookup( gs, "T" ); \
3005 writer.addAttribute( "text:style-name", autoStyleName ); \
3007 writer.addTextSpan( text.mid( startPos, next - startPos ), m_tabCache ); \
3008 writer.endElement(); \
3011#define ISSTARTBOOKMARK( i ) bkStartIter != bookmarkStarts.end() && (*bkStartIter).pos == i
3012#define ISENDBOOKMARK( i ) bkEndIter != bookmarkEnds.end() && (*bkEndIter).pos == i
3013#define CHECKPOS( i ) \
3014 if ( cursorIndex == i ) { \
3015 writer.addProcessingInstruction( "opendocument cursor-position" ); \
3017 if ( ISSTARTBOOKMARK( i ) ) { \
3018 if ( (*bkStartIter).startEqualsEnd ) \
3019 writer.startElement( "text:bookmark" ); \
3021 writer.startElement( "text:bookmark-start" ); \
3022 writer.addAttribute( "text:name", (*bkStartIter).name ); \
3023 writer.endElement(); \
3026 if ( ISENDBOOKMARK( i ) ) { \
3027 writer.startElement( "text:bookmark-end" ); \
3028 writer.addAttribute( "text:name", (*bkEndIter).name ); \
3029 writer.endElement(); \
3037 typedef KoSavingContext::BookmarkPositions BookmarkPositions;
3038 BookmarkPositions bookmarkStarts = context.bookmarkStarts();
3039 BookmarkPositions::const_iterator bkStartIter = bookmarkStarts.begin();
3040 while ( bkStartIter != bookmarkStarts.end() && (*bkStartIter).pos < from )
3043 BookmarkPositions bookmarkEnds = context.bookmarkEnds();
3044 BookmarkPositions::const_iterator bkEndIter = bookmarkEnds.begin();
3045 while ( bkEndIter != bookmarkEnds.end() && (*bkEndIter).pos < from )
3048 KoTextFormat *curFormat = 0;
3049 KoTextFormat *lastFormatRaw = 0;
3050 KoTextFormat *lastFormatFixed = 0;
3051 int startPos = from;
3052 for (
int i = from; i <= to; ++i ) {
3053 KoTextStringChar & ch = str->at(i);
3054 KoTextFormat * newFormat =
static_cast<KoTextFormat *
>( ch.format() );
3055 if ( newFormat->isMisspelled() ) {
3056 if ( newFormat == lastFormatRaw )
3057 newFormat = lastFormatFixed;
3060 lastFormatRaw = newFormat;
3063 KoTextFormat tmpFormat( *newFormat );
3064 tmpFormat.setMisspelled(
false );
3065 newFormat = formatCollection()->format( &tmpFormat );
3066 lastFormatFixed = newFormat;
3070 curFormat = newFormat;
3071 if ( newFormat != curFormat
3072 || ch.isCustom() || cursorIndex == i || ISSTARTBOOKMARK( i ) || ISENDBOOKMARK( i ) )
3076 curFormat = newFormat;
3079 if ( ch.isCustom() ) {
3080 KoGenStyle gs( KoGenStyle::STYLE_AUTO,
"text" );
3081 curFormat->
save( gs, context, paragFormat() );
3083 if ( !gs.isEmpty() ) {
3084 const TQString autoStyleName = mainStyles.
lookup( gs,
"T" );
3085 writer.
addAttribute(
"text:style-name", autoStyleName );
3087 KoTextCustomItem* customItem = ch.customItem();
3088 customItem->
saveOasis( writer, context );
3096 if ( to >= startPos ) {
3101 writer.endElement();
3103 writer.endElement();
3106void KoTextParag::applyListStyle( KoOasisContext& context,
int restartNumbering,
bool orderedList,
bool heading,
int level )
3109 delete m_layout.counter;
3110 m_layout.counter =
new KoParagCounter;
3111 m_layout.counter->loadOasis( context, restartNumbering, orderedList, heading, level );
3113 const TQDomElement listStyleProperties = context.listStyleStack().currentListStyleProperties();
3114 if ( listStyleProperties.hasAttributeNS( KoXmlNS::text,
"space-before" ) )
3116 double spaceBefore = KoUnit::parseValue( listStyleProperties.attributeNS( KoXmlNS::text,
"space-before", TQString() ) );
3117 m_layout.margins[ TQStyleSheetItem::MarginLeft ] += spaceBefore;
3122int KoTextParag::documentWidth()
const
3124 return doc ? doc->width() : 0;
3132int KoTextParag::documentX()
const
3134 return doc ? doc->x() : 0;
3137int KoTextParag::documentY()
const
3139 return doc ? doc->y() : 0;
3142void KoTextParag::fixParagWidth(
bool viewFormattingChars )
3145 if ( viewFormattingChars && lineStartList().count() == 1 )
3147 KoTextFormat * lastFormat = at( length() - 1 )->format();
3148 setWidth( TQMIN( rect().width() + lastFormat->
width(
'x'), doc->width() ) );
3154void KoTextParag::drawFormattingChars( TQPainter &painter,
int start,
int len,
3155 int lastY_pix,
int baseLine_pix,
int h_pix,
3157 KoTextFormat * ,
const TQMemArray<int> &,
3158 const TQMemArray<int> &,
const TQColorGroup & ,
3159 bool rightToLeft,
int , KoTextZoomHandler* zh,
3160 int whichFormattingChars )
3162 if ( !whichFormattingChars )
3166 TQPen pen( TDEGlobalSettings::linkColor() );
3167 painter.setPen( pen );
3169 if ( start + len == length() && ( whichFormattingChars & FormattingEndParag ) )
3172 KoTextStringChar &ch = str->at( length() - 1 );
3173 KoTextFormat* format =
static_cast<KoTextFormat *
>( ch.format() );
3174 int w = format->charWidth( zh,
true, &ch,
this,
'X' );
3175 int size = TQMIN( w, h_pix * 3 / 4 );
3183 int y = lastY_pix + baseLine_pix;
3185 painter.drawLine( (
int)(x - size * 0.2), y - size, (
int)(x - size * 0.2), y );
3186 painter.drawLine( (
int)(x - size * 0.5), y - size, (
int)(x - size * 0.5), y );
3187 painter.drawLine( x, y, (
int)(x - size * 0.7), y );
3188 painter.drawLine( x, y - size, (
int)(x - size * 0.5), y - size);
3189 painter.drawArc( x - size, y - size, size, (
int)(size / 2), -90*16, -180*16 );
3190#ifdef DEBUG_FORMATTING
3191 painter.setPen( TQt::blue );
3192 painter.drawRect( zh->
layoutUnitToPixelX( ch.x ) - 1, lastY_pix, ch.pixelwidth, baseLine_pix );
3193 TQPen pen( cg.color( TQColorGroup::Highlight ) );
3194 painter.setPen( pen );
3199 if ( (whichFormattingChars & FormattingSpace) ||
3200 (whichFormattingChars & FormattingTabs) ||
3201 (whichFormattingChars & FormattingBreak) )
3203 int end = TQMIN( start + len, length() - 1 );
3204 for (
int i = start ; i < end ; ++i )
3206 KoTextStringChar &ch = str->at(i);
3207#ifdef DEBUG_FORMATTING
3208 painter.setPen( (i % 2)? TQt::red: TQt::green );
3209 painter.drawRect( zh->
layoutUnitToPixelX( ch.x ) - 1, lastY_pix, ch.pixelwidth, baseLine_pix );
3210 TQPen pen( cg.color( TQColorGroup::Highlight ) );
3211 painter.setPen( pen );
3213 if ( ch.isCustom() )
3215 if ( (ch.c ==
' ' || ch.c.unicode() == 0x00a0U)
3216 && (whichFormattingChars & FormattingSpace))
3221 int height = zh->layoutUnitToPixelY( ch.ascent() );
3222 int size = TQMAX( 2, TQMIN( w/2, height/3 ) );
3224 TQRect spcRect( x + (ch.pixelwidth - size) / 2, lastY_pix + baseLine_pix - (height - size) / 2, size, size );
3226 painter.drawRect( spcRect );
3228 painter.fillRect( spcRect, pen.color() );
3230 else if ( ch.c ==
'\t' && (whichFormattingChars & FormattingTabs) )
3239 int availWidth = ch.pixelwidth;
3241 KoTextFormat* format = ch.format();
3243 int charWidth = format->screenFontMetrics( zh ).width(
'W' );
3244 int size = TQMIN( availWidth, charWidth ) / 2 ;
3245 int y = lastY_pix + baseLine_pix - zh->layoutUnitToPixelY( ch.ascent()/2 );
3246 int arrowsize = zh->zoomItY( 2 );
3247 painter.drawLine( x - size, y, x + size, y );
3250 painter.drawLine( x - size, y, x - size + arrowsize, y - arrowsize );
3251 painter.drawLine( x - size, y, x - size + arrowsize, y + arrowsize );
3255 painter.drawLine( x + size, y, x + size - arrowsize, y - arrowsize );
3256 painter.drawLine( x + size, y, x + size - arrowsize, y + arrowsize );
3259 else if ( ch.c ==
'\n' && (whichFormattingChars & FormattingBreak) )
3262 KoTextFormat* format =
static_cast<KoTextFormat *
>( ch.format() );
3263 int w = format->charWidth( zh,
true, &ch,
this,
'X' );
3264 int size = TQMIN( w, h_pix * 3 / 4 );
3265 int arrowsize = zh->zoomItY( 2 );
3268 int y = lastY_pix + baseLine_pix - arrowsize;
3273 painter.drawLine( x - size, y - size, x - size, y );
3274 painter.drawLine( x - size, y, (
int)(x - size * 0.3), y );
3276 painter.drawLine( (
int)(x - size * 0.3), y, (
int)(x - size * 0.3 - arrowsize), y - arrowsize );
3277 painter.drawLine( (
int)(x - size * 0.3), y, (
int)(x - size * 0.3 - arrowsize), y + arrowsize );
3282 painter.drawLine( x, y - size, x, y );
3283 painter.drawLine( x, y, (
int)(x - size * 0.7), y );
3285 painter.drawLine( (
int)(x - size * 0.7), y, (
int)(x - size * 0.7 + arrowsize), y - arrowsize );
3286 painter.drawLine( (
int)(x - size * 0.7), y, (
int)(x - size * 0.7 + arrowsize), y + arrowsize );
3294int KoTextParag::heightForLineSpacing(
int startChar,
int lastChar )
const
3297 int end = TQMIN( lastChar, length() - 1 );
3298 for(
int i = startChar; i <= end; ++i )
3300 const KoTextStringChar &chr = str->at( i );
3301 if ( !chr.isCustom() )
3302 h = TQMAX( h, chr.format()->height() );
This class represents a border - for anything, like paragraph, or frame.
const KoTextFormat & format() const
Return a format.
TQString lookup(const KoGenStyle &style, const TQString &name=TQString(), int flags=NoFlag)
Look up a style in the collection, inserting it if necessary.
Used during loading of Oasis format (and discarded at the end of the loading).
This is the structure associated with a paragraph (KoTextParag), to define the bullet or numbering of...
unsigned int depth() const
The level of the numbering.
void invalidate()
Invalidate the internal cache.
void saveOasis(KoGenStyle &listStyle, bool savingStyle=false) const
Save as OASIS XML.
Numbering numbering() const
Numbering type and style.
int startNumber() const
Starting number.
bool restartCounter() const
Should this counter start at "startNumber" (instead of being the 'last counter of the same type + 1')...
This class holds the paragraph-specific formatting information It's separated from KoTextParag so tha...
static void loadOasisParagLayout(KoParagLayout &layout, KoOasisContext &context)
Load this parag layout from Oasis XML.
SpacingType
Line spacing values Assuming h is the height of the biggest char in the line, and v is the linespacin...
TQColor backgroundColor
The background color of the paragraph.
double margins[5]
left, right, top, bottom, firstLineSpacing - in pt
KoParagCounter * counter
can be 0 if no counter set
char alignment
Alignment flag (AlignAuto/AlignLeft/AlignRight/AlignJustify).
A paragraph style is a combination of a character style and paragraph-layout attributes,...
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?
KoParagStyle * findStyleByDisplayName(const TQString &name) const
Find style based on the display name displayName.
KoParagStyle * findStyle(const TQString &name) const
Find style based on the internal name name.
KoTextCustomItem is the base class for custom items (i.e.
virtual void saveOasis(KoXmlWriter &writer, KoSavingContext &context) const =0
Save to Oasis XML.
virtual void recalc()
Reimplemented by KoVariable to recalculate the value.
Each character (KoTextStringChar) points to a KoTextFormat that defines the formatting of that charac...
void save(KoGenStyle &gs, KoSavingContext &context, KoTextFormat *refFormat=0) const
Save a text format to OASIS XML Only saves what differs from @refFormat, if set.
int charWidth(const KoTextZoomHandler *zh, bool applyZoom, const KoTextStringChar *c, const KoTextParag *parag, int i) const
Return the width of one char in one paragraph.
void load(KoOasisContext &context)
Load a text format from OASIS XML.
int width(const TQChar &c) const
Return the width of one char (from a string, not necessarily from a paragraph) in LU pixels.
static TQColor defaultTextColor(TQPainter *painter)
Call this when a text color is set to 'invalid', meaning 'whatever the default for the color scheme i...
This class extends KoZoomHandler to add support for WYSIWYG text layouting.
static double ptToLayoutUnitPt(double pt)
Not zoom dependent.
int ptToLayoutUnitPixX(double x_pt) const
The "document pt" -> "Layout Unit pixels" conversions, for convenience.
int layoutUnitToPixelX(int lupix) const
The "layout unit pixel" -> "[zoomed] view pixel" conversions.
virtual TQString text(bool realValue=false)
Returns the text to be displayed for this variable It doesn't need to be cached, convert() is fast,...
A class for writing out XML (to any TQIODevice), with a special attention on performance.
void startElement(const char *tagName, bool indentInside=true)
Start a new element, as a child of the current element.
void addTextNode(const TQString &str)
Overloaded version of addTextNode( const char* ), which is a bit slower because it needs to convert s...
void endElement()
Terminate the current element.
void addAttribute(const char *attrName, const TQString &value)
Overloaded version of addAttribute( const char*, const char* ), which is a bit slower because it need...
KoTabulatorFilling filling
Type of tab filling.
double ptWidth
Width of the tab filling line.