-rw-r--r-- | noncore/apps/opie-write/qrichtext.cpp | 72 |
1 files changed, 23 insertions, 49 deletions
diff --git a/noncore/apps/opie-write/qrichtext.cpp b/noncore/apps/opie-write/qrichtext.cpp index 768da44..b457cd6 100644 --- a/noncore/apps/opie-write/qrichtext.cpp +++ b/noncore/apps/opie-write/qrichtext.cpp @@ -96,245 +96,236 @@ static inline int scale( int value, QPainter *painter ) // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void QTextCommandHistory::addCommand( QTextCommand *cmd ) { if ( current < (int)history.count() - 1 ) { QPtrList<QTextCommand> commands; commands.setAutoDelete( FALSE ); for( int i = 0; i <= current; ++i ) { commands.insert( i, history.at( 0 ) ); history.take( 0 ); } commands.append( cmd ); history.clear(); history = commands; history.setAutoDelete( TRUE ); } else { history.append( cmd ); } if ( (int)history.count() > steps ) history.removeFirst(); else ++current; } QTextCursor *QTextCommandHistory::undo( QTextCursor *c ) { if ( current > -1 ) { QTextCursor *c2 = history.at( current )->unexecute( c ); --current; return c2; } return 0; } QTextCursor *QTextCommandHistory::redo( QTextCursor *c ) { if ( current > -1 ) { if ( current < (int)history.count() - 1 ) { ++current; return history.at( current )->execute( c ); } } else { if ( history.count() > 0 ) { ++current; return history.at( current )->execute( c ); } } return 0; } bool QTextCommandHistory::isUndoAvailable() { return current > -1; } bool QTextCommandHistory::isRedoAvailable() { return current > -1 && current < (int)history.count() - 1 || current == -1 && history.count() > 0; } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ QTextDeleteCommand::QTextDeleteCommand( QTextDocument *d, int i, int idx, const QMemArray<QTextStringChar> &str, const QByteArray& oldStyleInfo ) : QTextCommand( d ), id( i ), index( idx ), parag( 0 ), text( str ), styleInformation( oldStyleInfo ) { for ( int j = 0; j < (int)text.size(); ++j ) { if ( text[ j ].format() ) text[ j ].format()->addRef(); } } QTextDeleteCommand::QTextDeleteCommand( QTextParagraph *p, int idx, const QMemArray<QTextStringChar> &str ) : QTextCommand( 0 ), id( -1 ), index( idx ), parag( p ), text( str ) { for ( int i = 0; i < (int)text.size(); ++i ) { if ( text[ i ].format() ) text[ i ].format()->addRef(); } } QTextDeleteCommand::~QTextDeleteCommand() { for ( int i = 0; i < (int)text.size(); ++i ) { if ( text[ i ].format() ) text[ i ].format()->removeRef(); } text.resize( 0 ); } QTextCursor *QTextDeleteCommand::execute( QTextCursor *c ) { QTextParagraph *s = doc ? doc->paragAt( id ) : parag; - if ( !s && doc ) { + if ( !s ) { owarn << "can't locate parag at " << id << ", last parag: " << doc->lastParagraph()->paragId() << "" << oendl; return 0; - } else if ( !doc ) { - owarn << "No valid doc" << oendl; - return 0; } cursor.setParagraph( s ); cursor.setIndex( index ); int len = text.size(); if ( c ) *c = cursor; if ( doc ) { doc->setSelectionStart( QTextDocument::Temp, cursor ); for ( int i = 0; i < len; ++i ) cursor.gotoNextLetter(); doc->setSelectionEnd( QTextDocument::Temp, cursor ); doc->removeSelectedText( QTextDocument::Temp, &cursor ); if ( c ) *c = cursor; } else { s->remove( index, len ); } return c; } QTextCursor *QTextDeleteCommand::unexecute( QTextCursor *c ) { QTextParagraph *s = doc ? doc->paragAt( id ) : parag; - if ( !s && doc ) { + if ( !s ) { owarn << "can't locate parag at " << id << ", last parag: " << doc->lastParagraph()->paragId() << "" << oendl; return 0; - } else if ( !doc ) { - owarn << "No valid doc" << oendl; - return 0; } cursor.setParagraph( s ); cursor.setIndex( index ); QString str = QTextString::toString( text ); cursor.insert( str, TRUE, &text ); cursor.setParagraph( s ); cursor.setIndex( index ); if ( c ) { c->setParagraph( s ); c->setIndex( index ); for ( int i = 0; i < (int)text.size(); ++i ) c->gotoNextLetter(); - } else { - owarn << "No valid cursor" << oendl; - return 0; } if ( !styleInformation.isEmpty() ) { QDataStream styleStream( styleInformation, IO_ReadOnly ); int num; styleStream >> num; QTextParagraph *p = s; while ( num-- && p ) { p->readStyleInformation( styleStream ); p = p->next(); } } s = cursor.paragraph(); while ( s ) { s->format(); s->setChanged( TRUE ); if ( s == c->paragraph() ) break; s = s->next(); } return &cursor; } QTextFormatCommand::QTextFormatCommand( QTextDocument *d, int sid, int sidx, int eid, int eidx, const QMemArray<QTextStringChar> &old, QTextFormat *f, int fl ) : QTextCommand( d ), startId( sid ), startIndex( sidx ), endId( eid ), endIndex( eidx ), format( f ), oldFormats( old ), flags( fl ) { format = d->formatCollection()->format( f ); for ( int j = 0; j < (int)oldFormats.size(); ++j ) { if ( oldFormats[ j ].format() ) oldFormats[ j ].format()->addRef(); } } QTextFormatCommand::~QTextFormatCommand() { format->removeRef(); for ( int j = 0; j < (int)oldFormats.size(); ++j ) { if ( oldFormats[ j ].format() ) oldFormats[ j ].format()->removeRef(); } } QTextCursor *QTextFormatCommand::execute( QTextCursor *c ) { QTextParagraph *sp = doc->paragAt( startId ); QTextParagraph *ep = doc->paragAt( endId ); if ( !sp || !ep ) return c; QTextCursor start( doc ); start.setParagraph( sp ); start.setIndex( startIndex ); QTextCursor end( doc ); end.setParagraph( ep ); end.setIndex( endIndex ); doc->setSelectionStart( QTextDocument::Temp, start ); doc->setSelectionEnd( QTextDocument::Temp, end ); doc->setFormat( QTextDocument::Temp, format, flags ); doc->removeSelection( QTextDocument::Temp ); if ( endIndex == ep->length() ) end.gotoLeft(); *c = end; return c; } QTextCursor *QTextFormatCommand::unexecute( QTextCursor *c ) { QTextParagraph *sp = doc->paragAt( startId ); QTextParagraph *ep = doc->paragAt( endId ); if ( !sp || !ep ) return 0; int idx = startIndex; int fIndex = 0; for ( ;; ) { if ( oldFormats.at( fIndex ).c == '\n' ) { if ( idx > 0 ) { if ( idx < sp->length() && fIndex > 0 ) sp->setFormat( idx, 1, oldFormats.at( fIndex - 1 ).format() ); if ( sp == ep ) break; sp = sp->next(); idx = 0; } fIndex++; } if ( oldFormats.at( fIndex ).format() ) sp->setFormat( idx, 1, oldFormats.at( fIndex ).format() ); idx++; fIndex++; if ( fIndex >= (int)oldFormats.size() ) break; if ( idx >= sp->length() ) { @@ -1308,221 +1299,210 @@ bool QTextDocument::setMinimumWidth( int needed, int used, QTextParagraph *p ) } else if ( needed > minw ) { minw = needed; minwParag = p; emit minimumWidthChanged( minw ); } wused = QMAX( wused, used ); wused = QMAX( wused, minw ); cw = QMAX( minw, cw ); return TRUE; } void QTextDocument::setPlainText( const QString &text ) { clear(); preferRichText = FALSE; oTextValid = TRUE; oText = text; int lastNl = 0; int nl = text.find( '\n' ); if ( nl == -1 ) { lParag = createParagraph( this, lParag, 0 ); if ( !fParag ) fParag = lParag; QString s = text; if ( !s.isEmpty() ) { if ( s[ (int)s.length() - 1 ] == '\r' ) s.remove( s.length() - 1, 1 ); lParag->append( s ); } } else { for (;;) { lParag = createParagraph( this, lParag, 0 ); if ( !fParag ) fParag = lParag; QString s = text.mid( lastNl, nl - lastNl ); if ( !s.isEmpty() ) { if ( s[ (int)s.length() - 1 ] == '\r' ) s.remove( s.length() - 1, 1 ); lParag->append( s ); } if ( nl == 0xffffff ) break; lastNl = nl + 1; nl = text.find( '\n', nl + 1 ); if ( nl == -1 ) nl = 0xffffff; } } if ( !lParag ) lParag = fParag = createParagraph( this, 0, 0 ); } struct Q_EXPORT QTextDocumentTag { QTextDocumentTag(){} QTextDocumentTag( const QString&n, const QStyleSheetItem* s, const QTextFormat& f ) :name(n),style(s), format(f), alignment(Qt3::AlignAuto), direction(QChar::DirON),liststyle(QStyleSheetItem::ListDisc) { wsm = QStyleSheetItem::WhiteSpaceNormal; } QString name; const QStyleSheetItem* style; QString anchorHref; QStyleSheetItem::WhiteSpaceMode wsm; QTextFormat format; int alignment : 16; int direction : 5; QStyleSheetItem::ListStyle liststyle; QTextDocumentTag( const QTextDocumentTag& t ) { name = t.name; style = t.style; anchorHref = t.anchorHref; wsm = t.wsm; format = t.format; alignment = t.alignment; direction = t.direction; liststyle = t.liststyle; } QTextDocumentTag& operator=(const QTextDocumentTag& t) { name = t.name; style = t.style; anchorHref = t.anchorHref; wsm = t.wsm; format = t.format; alignment = t.alignment; direction = t.direction; liststyle = t.liststyle; return *this; } #if defined(Q_FULL_TEMPLATE_INSTANTIATION) bool operator==( const QTextDocumentTag& ) const { return FALSE; } #endif }; -#define NEWPAR do { \ - if ( !hasNewPar) { \ - if ( !curpar ) { \ - owarn << "no current paragraph" << oendl; \ - return; \ - } \ - if ( !textEditMode && curpar && curpar->length()>1 && curpar->at( curpar->length()-2)->c == QChar_linesep ) \ - curpar->remove( curpar->length()-2, 1 ); \ - curpar = createParagraph( this, curpar, curpar->next() ); styles.append( vec ); \ - if ( !curpar ) { \ - owarn << "failed in creating a new paragraph" << oendl; \ - return; \ - } \ - vec = 0; \ - } \ - hasNewPar = TRUE; \ - curpar->rtext = TRUE; \ - curpar->align = curtag.alignment; \ - curpar->lstyle = curtag.liststyle; \ - curpar->litem = ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ); \ - curpar->str->setDirection( (QChar::Direction)curtag.direction ); \ - space = TRUE; \ - delete vec; \ - vec = new QPtrVector<QStyleSheetItem>( (uint)tags.count() + 1); \ - int i = 0; \ - for ( QValueStack<QTextDocumentTag>::Iterator it = tags.begin(); it != tags.end(); ++it ) \ - vec->insert( i++, (*it).style ); \ - vec->insert( i, curtag.style ); \ - } while ( FALSE ) +#define NEWPAR do{ if ( !hasNewPar) { \ + if ( !textEditMode && curpar && curpar->length()>1 && curpar->at( curpar->length()-2)->c == QChar_linesep ) \ + curpar->remove( curpar->length()-2, 1 ); \ + curpar = createParagraph( this, curpar, curpar->next() ); styles.append( vec ); vec = 0;} \ + hasNewPar = TRUE; \ + curpar->rtext = TRUE; \ + curpar->align = curtag.alignment; \ + curpar->lstyle = curtag.liststyle; \ + curpar->litem = ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ); \ + curpar->str->setDirection( (QChar::Direction)curtag.direction ); \ + space = TRUE; \ + delete vec; vec = new QPtrVector<QStyleSheetItem>( (uint)tags.count() + 1); \ + int i = 0; \ + for ( QValueStack<QTextDocumentTag>::Iterator it = tags.begin(); it != tags.end(); ++it ) \ + vec->insert( i++, (*it).style ); \ + vec->insert( i, curtag.style ); \ + }while(FALSE) + void QTextDocument::setRichText( const QString &text, const QString &context ) { if ( !context.isEmpty() ) setContext( context ); clear(); fParag = lParag = createParagraph( this ); oTextValid = TRUE; oText = text; setRichTextInternal( text ); fParag->rtext = TRUE; } void QTextDocument::setRichTextInternal( const QString &text, QTextCursor* cursor ) { QTextParagraph* curpar = lParag; int pos = 0; QValueStack<QTextDocumentTag> tags; QTextDocumentTag initag( "", sheet_->item(""), *formatCollection()->defaultFormat() ); QTextDocumentTag curtag = initag; bool space = TRUE; bool canMergeLi = FALSE; bool textEditMode = FALSE; const QChar* doc = text.unicode(); int length = text.length(); bool hasNewPar = curpar->length() <= 1; QString anchorName; // style sheet handling for margin and line spacing calculation below QTextParagraph* stylesPar = curpar; QPtrVector<QStyleSheetItem>* vec = 0; QPtrList< QPtrVector<QStyleSheetItem> > styles; styles.setAutoDelete( TRUE ); if ( cursor ) { cursor->splitAndInsertEmptyParagraph(); QTextCursor tmp = *cursor; tmp.gotoPreviousLetter(); stylesPar = curpar = tmp.paragraph(); hasNewPar = TRUE; textEditMode = TRUE; } else { NEWPAR; } // set rtext spacing to FALSE for the initial paragraph. curpar->rtext = FALSE; QString wellKnownTags = "br hr wsp table qt body meta title"; while ( pos < length ) { if ( hasPrefix(doc, length, pos, '<' ) ){ if ( !hasPrefix( doc, length, pos+1, QChar('/') ) ) { // open tag QMap<QString, QString> attr; bool emptyTag = FALSE; QString tagname = parseOpenTag(doc, length, pos, attr, emptyTag); if ( tagname.isEmpty() ) continue; // nothing we could do with this, probably parse error const QStyleSheetItem* nstyle = sheet_->item(tagname); if ( nstyle ) { // we might have to close some 'forgotten' tags while ( !nstyle->allowedInContext( curtag.style ) ) { QString msg; msg.sprintf( "QText Warning: Document not valid ( '%s' not allowed in '%s' #%d)", tagname.ascii(), curtag.style->name().ascii(), pos); sheet_->error( msg ); if ( tags.isEmpty() ) break; curtag = tags.pop(); } /* special handling for p and li for HTML compatibility. We do not want to embed blocks in p, and we do not want new blocks inside non-empty lis. Plus we want to merge empty lis sometimes. */ if( nstyle->displayMode() == QStyleSheetItem::DisplayListItem ) { canMergeLi = TRUE; } else if ( nstyle->displayMode() == QStyleSheetItem::DisplayBlock ) { while ( curtag.style->name() == "p" ) { if ( tags.isEmpty() ) break; curtag = tags.pop(); } if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) { // we are in a li and a new block comes along if ( nstyle->name() == "ul" || nstyle->name() == "ol" ) hasNewPar = FALSE; // we want an empty li (like most browsers) if ( !hasNewPar ) { /* do not add new blocks inside non-empty lis */ @@ -1822,197 +1802,194 @@ void QTextDocument::setRichTextInternal( const QString &text, QTextCursor* curso c = parseChar( doc, length, pos, QStyleSheetItem::WhiteSpacePre ); if ( c == QChar_linesep ) break; } else { int l = pos; c = parseChar( doc, length, pos, curtag.wsm ); // in white space pre mode: treat any space as non breakable if ( c == ' ' && curtag.wsm == QStyleSheetItem::WhiteSpacePre ) c = QChar::nbsp; if ( c == ' ' || c == QChar_linesep ) { /* avoid overlong paragraphs by forcing a new paragraph after 4096 characters. This case can occur when loading undiscovered plain text documents in rich text mode. Instead of hanging forever, we do the trick. */ if ( curtag.wsm == QStyleSheetItem::WhiteSpaceNormal && s.length() > 4096 ) do { if ( doc[l] == '\n' ) { hasNewPar = FALSE; // for a new paragraph ... NEWPAR; hasNewPar = FALSE; // ... and make it non-reusable c = '\n'; // make sure we break below break; } } while ( ++l < pos ); } } if ( c == '\n' ) break; // break on newlines, pre delievers a QChar_linesep bool c_isSpace = c.isSpace() && c.unicode() != 0x00a0U && !textEditMode; if ( curtag.wsm == QStyleSheetItem::WhiteSpaceNormal && c_isSpace && space ) continue; if ( c == '\r' ) continue; space = c_isSpace; s += c; } if ( !s.isEmpty() && curtag.style->displayMode() != QStyleSheetItem::DisplayNone ) { hasNewPar = FALSE; int index = QMAX( curpar->length(),1) - 1; curpar->append( s ); QTextFormat* f = formatCollection()->format( &curtag.format ); curpar->setFormat( index, s.length(), f, FALSE ); // do not use collection because we have done that already f->ref += s.length() -1; // that what friends are for... if ( !curtag.anchorHref.isEmpty() ) { for ( int i = 0; i < int(s.length()); i++ ) curpar->at(index + i)->setAnchor( QString::null, curtag.anchorHref ); } if ( !anchorName.isEmpty() ) { curpar->at(index)->setAnchor( anchorName, curpar->at(index)->anchorHref() ); anchorName = QString::null; } } } } if ( hasNewPar && curpar != fParag && !cursor ) { // cleanup unused last paragraphs curpar = curpar->p; delete curpar->n; } if ( !anchorName.isEmpty() ) { curpar->at(curpar->length() - 1)->setAnchor( anchorName, curpar->at( curpar->length() - 1 )->anchorHref() ); anchorName = QString::null; } setRichTextMarginsInternal( styles, stylesPar ); if ( cursor ) { cursor->gotoPreviousLetter(); cursor->remove(); } } void QTextDocument::setRichTextMarginsInternal( QPtrList< QPtrVector<QStyleSheetItem> >& styles, QTextParagraph* stylesPar ) { // margin and line spacing calculation QPtrVector<QStyleSheetItem>* prevStyle = 0; QPtrVector<QStyleSheetItem>* curStyle = styles.first(); QPtrVector<QStyleSheetItem>* nextStyle = styles.next(); while ( stylesPar ) { if ( !curStyle ) { stylesPar = stylesPar->next(); prevStyle = curStyle; curStyle = nextStyle; nextStyle = styles.next(); continue; } int i, mar; - QStyleSheetItem* mainStyle = (*curStyle)[curStyle->size()-1]; - if ( !mainStyle ) - return; - - if ( mainStyle->displayMode() == QStyleSheetItem::DisplayListItem ) + QStyleSheetItem* mainStyle = curStyle->size() ? (*curStyle)[curStyle->size()-1] : 0; + if ( mainStyle && mainStyle->displayMode() == QStyleSheetItem::DisplayListItem ) stylesPar->setListItem( TRUE ); int numLists = 0; for ( i = 0; i < (int)curStyle->size(); ++i ) { if ( (*curStyle)[ i ]->displayMode() == QStyleSheetItem::DisplayBlock && int((*curStyle)[ i ]->listStyle()) != QStyleSheetItem::Undefined ) numLists++; } stylesPar->ldepth = numLists; if ( stylesPar->next() && nextStyle ) { // also set the depth of the next paragraph, required for the margin calculation numLists = 0; for ( i = 0; i < (int)nextStyle->size(); ++i ) { if ( (*nextStyle)[ i ]->displayMode() == QStyleSheetItem::DisplayBlock && int((*nextStyle)[ i ]->listStyle()) != QStyleSheetItem::Undefined ) numLists++; } stylesPar->next()->ldepth = numLists; } // do the top margin QStyleSheetItem* item = mainStyle; int m; if (stylesPar->utm > 0 ) { m = stylesPar->utm-1; stylesPar->utm = 0; } else { m = QMAX(0, item->margin( QStyleSheetItem::MarginTop ) ); if ( item->displayMode() == QStyleSheetItem::DisplayListItem && stylesPar->ldepth ) m /= stylesPar->ldepth; } for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) { item = (*curStyle)[ i ]; if ( prevStyle && i < (int) prevStyle->size() && ( item->displayMode() == QStyleSheetItem::DisplayBlock && (*prevStyle)[ i ] == item ) ) break; // emulate CSS2' standard 0 vertical margin for multiple ul or ol tags if ( int(item->listStyle()) != QStyleSheetItem::Undefined && ( ( i> 0 && (*curStyle)[ i-1 ] == item ) || (*curStyle)[i+1] == item ) ) continue; mar = QMAX( 0, item->margin( QStyleSheetItem::MarginTop ) ); m = QMAX( m, mar ); } stylesPar->utm = m - stylesPar->topMargin(); // do the bottom margin item = mainStyle; if (stylesPar->ubm > 0 ) { m = stylesPar->ubm-1; stylesPar->ubm = 0; } else { m = QMAX(0, item->margin( QStyleSheetItem::MarginBottom ) ); if ( item->displayMode() == QStyleSheetItem::DisplayListItem && stylesPar->ldepth ) m /= stylesPar->ldepth; } for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) { item = (*curStyle)[ i ]; if ( nextStyle && i < (int) nextStyle->size() && ( item->displayMode() == QStyleSheetItem::DisplayBlock && (*nextStyle)[ i ] == item ) ) break; // emulate CSS2' standard 0 vertical margin for multiple ul or ol tags if ( int(item->listStyle()) != QStyleSheetItem::Undefined && ( ( i> 0 && (*curStyle)[ i-1 ] == item ) || (*curStyle)[i+1] == item ) ) continue; mar = QMAX(0, item->margin( QStyleSheetItem::MarginBottom ) ); m = QMAX( m, mar ); } stylesPar->ubm = m - stylesPar->bottomMargin(); // do the left margin, simplyfied item = mainStyle; if (stylesPar->ulm > 0 ) { m = stylesPar->ulm-1; stylesPar->ulm = 0; } else { m = QMAX( 0, item->margin( QStyleSheetItem::MarginLeft ) ); } for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) { item = (*curStyle)[ i ]; m += QMAX( 0, item->margin( QStyleSheetItem::MarginLeft ) ); } stylesPar->ulm = m - stylesPar->leftMargin(); // do the right margin, simplyfied item = mainStyle; if (stylesPar->urm > 0 ) { m = stylesPar->urm-1; stylesPar->urm = 0; } else { m = QMAX( 0, item->margin( QStyleSheetItem::MarginRight ) ); } for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) { item = (*curStyle)[ i ]; @@ -2977,201 +2954,198 @@ void QTextDocument::draw( QPainter *p, const QRect &rect, const QColorGroup &cg, parag = parag->next(); if ( !flow()->isEmpty() ) flow()->drawFloatingItems( p, rect.x(), rect.y(), rect.width(), rect.height(), cg, FALSE ); } } void QTextDocument::drawParagraph( QPainter *p, QTextParagraph *parag, int cx, int cy, int cw, int ch, QPixmap *&doubleBuffer, const QColorGroup &cg, bool drawCursor, QTextCursor *cursor, bool resetChanged ) { QPainter *painter = 0; if ( resetChanged ) parag->setChanged( FALSE ); QRect ir( parag->rect() ); bool useDoubleBuffer = !parag->document()->parent(); if ( !useDoubleBuffer && parag->document()->nextDoubleBuffered ) useDoubleBuffer = TRUE; if ( is_printer( p ) ) useDoubleBuffer = FALSE; if ( useDoubleBuffer ) { painter = new QPainter; if ( cx >= 0 && cy >= 0 ) ir = ir.intersect( QRect( cx, cy, cw, ch ) ); if ( !doubleBuffer || ir.width() > doubleBuffer->width() || ir.height() > doubleBuffer->height() ) { doubleBuffer = bufferPixmap( ir.size() ); painter->begin( doubleBuffer ); } else { painter->begin( doubleBuffer ); } } else { painter = p; painter->translate( ir.x(), ir.y() ); } painter->setBrushOrigin( -ir.x(), -ir.y() ); if ( useDoubleBuffer || is_printer( painter ) ) painter->fillRect( QRect( 0, 0, ir.width(), ir.height() ), parag->backgroundBrush( cg ) ); else if ( cursor && cursor->paragraph() == parag ) painter->fillRect( QRect( parag->at( cursor->index() )->x, 0, 2, ir.height() ), parag->backgroundBrush( cg ) ); painter->translate( -( ir.x() - parag->rect().x() ), -( ir.y() - parag->rect().y() ) ); parag->paint( *painter, cg, drawCursor ? cursor : 0, TRUE, cx, cy, cw, ch ); if ( useDoubleBuffer ) { delete painter; painter = 0; p->drawPixmap( ir.topLeft(), *doubleBuffer, QRect( QPoint( 0, 0 ), ir.size() ) ); } else { painter->translate( -ir.x(), -ir.y() ); } if ( useDoubleBuffer ) { if ( parag->rect().x() + parag->rect().width() < parag->document()->x() + parag->document()->width() ) { p->fillRect( parag->rect().x() + parag->rect().width(), parag->rect().y(), ( parag->document()->x() + parag->document()->width() ) - ( parag->rect().x() + parag->rect().width() ), parag->rect().height(), cg.brush( QColorGroup::Base ) ); } } parag->document()->nextDoubleBuffered = FALSE; } QTextParagraph *QTextDocument::draw( QPainter *p, int cx, int cy, int cw, int ch, const QColorGroup &cg, bool onlyChanged, bool drawCursor, QTextCursor *cursor, bool resetChanged ) { if ( withoutDoubleBuffer || par && par->withoutDoubleBuffer ) { withoutDoubleBuffer = TRUE; QRect r; draw( p, r, cg ); return 0; } withoutDoubleBuffer = FALSE; if ( !firstParagraph() ) return 0; if ( cx < 0 && cy < 0 ) { cx = 0; cy = 0; cw = width(); ch = height(); } QTextParagraph *lastFormatted = 0; QTextParagraph *parag = firstParagraph(); QPixmap *doubleBuffer = 0; QPainter painter; - bool fullWidthSelection = FALSE; while ( parag ) { lastFormatted = parag; if ( !parag->isValid() ) parag->format(); QRect pr = parag->rect(); - if ( fullWidthSelection ) - pr.setWidth( parag->document()->width() ); if ( pr.y() > cy + ch ) goto floating; if ( !pr.intersects( QRect( cx, cy, cw, ch ) ) || ( onlyChanged && !parag->hasChanged() ) ) { parag = parag->next(); continue; } drawParagraph( p, parag, cx, cy, cw, ch, doubleBuffer, cg, drawCursor, cursor, resetChanged ); parag = parag->next(); } parag = lastParagraph(); floating: if ( parag->rect().y() + parag->rect().height() < parag->document()->height() ) { if ( !parag->document()->parent() ) { p->fillRect( 0, parag->rect().y() + parag->rect().height(), parag->document()->width(), parag->document()->height() - ( parag->rect().y() + parag->rect().height() ), cg.brush( QColorGroup::Base ) ); } if ( !flow()->isEmpty() ) { QRect cr( cx, cy, cw, ch ); flow()->drawFloatingItems( p, cr.x(), cr.y(), cr.width(), cr.height(), cg, FALSE ); } } if ( buf_pixmap && buf_pixmap->height() > 300 ) { delete buf_pixmap; buf_pixmap = 0; } return lastFormatted; } /* #### this function only sets the default font size in the format collection */ void QTextDocument::setDefaultFormat( const QFont &font, const QColor &color ) { bool reformat = font != fCollection->defaultFormat()->font(); for ( QTextDocument *d = childList.first(); d; d = childList.next() ) d->setDefaultFormat( font, color ); fCollection->updateDefaultFormat( font, color, sheet_ ); if ( !reformat ) return; tStopWidth = formatCollection()->defaultFormat()->width( 'x' ) * 8; // invalidate paragraphs and custom items QTextParagraph *p = fParag; while ( p ) { p->invalidate( 0 ); for ( int i = 0; i < p->length() - 1; ++i ) if ( p->at( i )->isCustom() ) p->at( i )->customItem()->invalidate(); p = p->next(); } } void QTextDocument::registerCustomItem( QTextCustomItem *i, QTextParagraph *p ) { if ( i && i->placement() != QTextCustomItem::PlaceInline ) { flow_->registerFloatingItem( i ); p->registerFloatingItem( i ); i->setParagraph( p ); } p->mightHaveCustomItems = mightHaveCustomItems = TRUE; } void QTextDocument::unregisterCustomItem( QTextCustomItem *i, QTextParagraph *p ) { flow_->unregisterFloatingItem( i ); p->unregisterFloatingItem( i ); i->setParagraph( 0 ); } bool QTextDocument::hasFocusParagraph() const { return !!focusIndicator.parag; } QString QTextDocument::focusHref() const { return focusIndicator.href; } bool QTextDocument::focusNextPrevChild( bool next ) { if ( !focusIndicator.parag ) { if ( next ) { focusIndicator.parag = fParag; focusIndicator.start = 0; focusIndicator.len = 0; } else { focusIndicator.parag = lParag; focusIndicator.start = lParag->length(); @@ -5271,193 +5245,193 @@ int QTextFormatterBreakInWords::format( QTextDocument *doc,QTextParagraph *parag col = 0; if ( wrapAtColumn() != -1 ) minw = QMAX( minw, w ); } else if ( lineStart ) { lineStart->baseLine = QMAX( lineStart->baseLine, c->ascent() ); h = QMAX( h, c->height() ); lineStart->h = h; } c->x = x; x += ww; wused = QMAX( wused, x ); } int m = parag->bottomMargin(); if ( !parag->next() ) m = 0; else m = QMAX(m, parag->next()->topMargin() ) / 2; parag->setFullWidth( fullWidth ); y += h + m; if ( doc ) minw += doc->rightMargin(); if ( !wrapEnabled ) minw = QMAX(minw, wused); thisminw = minw; thiswused = wused; return y; } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ QTextFormatterBreakWords::QTextFormatterBreakWords() { } #define DO_FLOW( lineStart ) do{ if ( doc && doc->isPageBreakEnabled() ) { \ int yflow = lineStart->y + parag->rect().y();\ int shift = doc->flow()->adjustFlow( yflow, dw, lineStart->h ); \ lineStart->y += shift;\ y += shift;\ }}while(FALSE) int QTextFormatterBreakWords::format( QTextDocument *doc, QTextParagraph *parag, int start, const QMap<int, QTextLineStart*> & ) { QTextStringChar *c = 0; QTextStringChar *firstChar = 0; QTextString *string = parag->string(); int left = doc ? parag->leftMargin() + doc->leftMargin() : 0; int x = left + ( doc ? parag->firstLineMargin() : 0 ); int y = parag->prev() ? QMAX(parag->prev()->bottomMargin(),parag->topMargin()) / 2: 0; int h = y; int len = parag->length(); if ( doc ) x = doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), x, 0 ); int dw = parag->documentVisibleWidth() - ( doc ? ( left != x ? 0 : doc->rightMargin() ) : 0 ); int curLeft = x; int rm = parag->rightMargin(); int rdiff = doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 0 ) : 0; int w = dw - rdiff; bool fullWidth = TRUE; int marg = left + rdiff; int minw = 0; int wused = 0; int tminw = marg; int linespacing = doc ? parag->lineSpacing() : 0; bool wrapEnabled = isWrapEnabled( parag ); start = 0; if ( start == 0 ) c = ¶g->string()->at( 0 ); int i = start; QTextLineStart *lineStart = new QTextLineStart( y, y, 0 ); insertLineStart( parag, 0, lineStart ); int lastBreak = -1; int tmpBaseLine = 0, tmph = 0; bool lastWasNonInlineCustom = FALSE; int align = parag->alignment(); if ( align == Qt3::AlignAuto && doc && doc->alignment() != Qt3::AlignAuto ) align = doc->alignment(); align &= Qt3::AlignHorizontal_Mask; QPainter *painter = QTextFormat::painter(); int col = 0; int ww = 0; QChar lastChr; for ( ; i < len; ++i, ++col ) { if ( c ) lastChr = c->c; // ### next line should not be needed - if ( c && painter ) + if ( painter ) c->format()->setPainter( painter ); c = &string->at( i ); c->rightToLeft = FALSE; if ( i > 0 && (x > curLeft || ww == 0) || lastWasNonInlineCustom ) { c->lineStart = 0; } else { c->lineStart = 1; firstChar = c; } if ( c->isCustom() && c->customItem()->placement() != QTextCustomItem::PlaceInline ) lastWasNonInlineCustom = TRUE; else lastWasNonInlineCustom = FALSE; if ( c->c.unicode() >= 32 || c->isCustom() ) { ww = string->width( i ); } else if ( c->c == '\t' ) { int nx = parag->nextTab( i, x - left ) + left; if ( nx < x ) ww = w - x; else ww = nx - x; } else { ww = c->format()->width( ' ' ); } // last character ("invisible" space) has no width if ( i == len - 1 ) ww = 0; QTextCustomItem* ci = c->customItem(); if ( c->isCustom() && ci->ownLine() ) { x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left; w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 ); QTextLineStart *lineStart2 = formatLine( parag, string, lineStart, firstChar, c-1, align, SPACE(w - x) ); ci->resize( w - x); if ( ci->width < w - x ) { if ( align & Qt::AlignHCenter ) x = ( w - ci->width ) / 2; else if ( align & Qt::AlignRight ) { x = w - ci->width; } } c->x = x; curLeft = x; if ( i == 0 || !isBreakable( string, i - 1 ) || string->at( i - 1 ).lineStart == 0 ) { y += QMAX( h, QMAX( tmph, linespacing ) ); tmph = c->height(); h = tmph; lineStart = lineStart2; lineStart->y = y; insertLineStart( parag, i, lineStart ); c->lineStart = 1; firstChar = c; } else { tmph = c->height(); h = tmph; delete lineStart2; } lineStart->h = h; lineStart->baseLine = h; tmpBaseLine = lineStart->baseLine; lastBreak = -2; x = 0xffffff; minw = QMAX( minw, tminw ); int tw = ci->minimumWidth() + ( doc ? doc->leftMargin() : 0 ); if ( tw < QWIDGETSIZE_MAX ) tminw = tw; else tminw = marg; wused = QMAX( wused, ci->width ); continue; } else if ( c->isCustom() && ci->placement() != QTextCustomItem::PlaceInline ) { int tw = ci->minimumWidth(); if ( tw < QWIDGETSIZE_MAX ) minw = QMAX( minw, tw ); } bool lastWasOwnLineCustomItem = lastBreak == -2; bool hadBreakableChar = lastBreak != -1; bool lastWasHardBreak = lastChr == QChar_linesep; // we break if // 1. the last character was a hard break (QChar_linesep) or // 2. the last charater was a own-line custom item (eg. table or ruler) or // 3. wrapping was enabled, it was not a space and following // condition is true: We either had a breakable character // previously or we ar allowed to break in words and - either // we break at w pixels and the current char would exceed that // or - we break at a column and the current character would // exceed that. if ( lastWasHardBreak || lastWasOwnLineCustomItem || ( wrapEnabled && ( (!c->c.isSpace() && (hadBreakableChar || allowBreakInWords()) && |