author | erik <erik> | 2007-02-08 01:46:35 (UTC) |
---|---|---|
committer | erik <erik> | 2007-02-08 01:46:35 (UTC) |
commit | 41dce553a418765d5075fc249c636104a2a82329 (patch) (side-by-side diff) | |
tree | ca9b39611b17355cf2cb1c890d68f3a008e38866 | |
parent | 2e497f7cae45184184e2416114887095735958f5 (diff) | |
download | opie-41dce553a418765d5075fc249c636104a2a82329.zip opie-41dce553a418765d5075fc249c636104a2a82329.tar.gz opie-41dce553a418765d5075fc249c636104a2a82329.tar.bz2 |
Removal of useless code based on a conditional that is never set to anything
but false.
-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 @@ -1,436 +1,427 @@ /**************************************************************************** ** $Id$ ** ** Implementation of the internal Qt classes dealing with rich text ** ** Created : 990101 ** ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. ** ** This file is part of the kernel module of the Qt GUI Toolkit. ** ** This file may be distributed under the terms of the Q Public License ** as defined by Trolltech AS of Norway and appearing in the file ** LICENSE.QPL included in the packaging of this file. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition ** licenses may use this file in accordance with the Qt Commercial License ** Agreement provided with the Software. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for ** information about Qt Commercial License Agreements. ** See http://www.trolltech.com/qpl/ for QPL licensing information. ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ #include "qrichtext_p.h" /* OPIE */ #include <opie2/odebug.h> using namespace Opie::Core; /* QT */ #include "qdragobject.h" #include "qpaintdevicemetrics.h" #include "qdrawutil.h" #include "qcleanuphandler.h" /* STD */ #include <stdlib.h> using namespace Qt3; static QTextCursor* richTextExportStart = 0; static QTextCursor* richTextExportEnd = 0; static QTextFormatCollection *qFormatCollection = 0; const int border_tolerance = 2; #ifdef Q_WS_WIN #include "qt_windows.h" #endif #define QChar_linesep QChar(0x2028U) static inline bool is_printer( QPainter *p ) { if ( !p || !p->device() ) return FALSE; return p->device()->devType() == QInternal::Printer; } static inline int scale( int value, QPainter *painter ) { if ( is_printer( painter ) ) { QPaintDeviceMetrics metrics( painter->device() ); #if defined(Q_WS_X11) value = value * metrics.logicalDpiY() / QPaintDevice::x11AppDpiY(); #elif defined (Q_WS_WIN) HDC hdc = GetDC( 0 ); int gdc = GetDeviceCaps( hdc, LOGPIXELSY ); if ( gdc ) value = value * metrics.logicalDpiY() / gdc; ReleaseDC( 0, hdc ); #elif defined (Q_WS_MAC) value = value * metrics.logicalDpiY() / 75; // ##### FIXME #elif defined (Q_WS_QWS) value = value * metrics.logicalDpiY() / 75; #endif } return value; } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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() ) { if ( sp == ep ) break; sp = sp->next(); idx = 0; } } QTextCursor end( doc ); end.setParagraph( ep ); end.setIndex( endIndex ); if ( endIndex == ep->length() ) end.gotoLeft(); *c = end; return c; } QTextStyleCommand::QTextStyleCommand( QTextDocument *d, int fParag, int lParag, const QByteArray& beforeChange ) : QTextCommand( d ), firstParag( fParag ), lastParag( lParag ), before( beforeChange ) { after = readStyleInformation( d, fParag, lParag ); } QByteArray QTextStyleCommand::readStyleInformation( QTextDocument* doc, int fParag, int lParag ) { QByteArray style; QTextParagraph *p = doc->paragAt( fParag ); if ( !p ) return style; QDataStream styleStream( style, IO_WriteOnly ); int num = lParag - fParag + 1; styleStream << num; while ( num -- && p ) { p->writeStyleInformation( styleStream ); p = p->next(); } return style; } void QTextStyleCommand::writeStyleInformation( QTextDocument* doc, int fParag, const QByteArray& style ) { QTextParagraph *p = doc->paragAt( fParag ); if ( !p ) return; QDataStream styleStream( style, IO_ReadOnly ); int num; styleStream >> num; while ( num-- && p ) { p->readStyleInformation( styleStream ); p = p->next(); } } QTextCursor *QTextStyleCommand::execute( QTextCursor *c ) { writeStyleInformation( doc, firstParag, after ); return c; } QTextCursor *QTextStyleCommand::unexecute( QTextCursor *c ) { writeStyleInformation( doc, firstParag, before ); return c; } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ QTextCursor::QTextCursor( QTextDocument *d ) : idx( 0 ), tmpIndex( -1 ), ox( 0 ), oy( 0 ), valid( TRUE ) { para = d ? d->firstParagraph() : 0; } QTextCursor::QTextCursor( const QTextCursor &c ) { ox = c.ox; oy = c.oy; idx = c.idx; para = c.para; tmpIndex = c.tmpIndex; indices = c.indices; paras = c.paras; xOffsets = c.xOffsets; yOffsets = c.yOffsets; valid = c.valid; } QTextCursor &QTextCursor::operator=( const QTextCursor &c ) { ox = c.ox; oy = c.oy; idx = c.idx; para = c.para; tmpIndex = c.tmpIndex; indices = c.indices; @@ -1212,413 +1203,402 @@ void QTextDocument::init() backBrush = 0; buf_pixmap = 0; nextDoubleBuffered = FALSE; if ( par ) withoutDoubleBuffer = par->withoutDoubleBuffer; else withoutDoubleBuffer = FALSE; lParag = fParag = createParagraph( this, 0, 0 ); cx = 0; cy = 2; if ( par ) cx = cy = 0; cw = 600; vw = 0; flow_ = new QTextFlow; flow_->setWidth( cw ); leftmargin = rightmargin = 4; scaleFontsFactor = 1; selectionColors[ Standard ] = QApplication::palette().color( QPalette::Active, QColorGroup::Highlight ); selectionText[ Standard ] = TRUE; commandHistory = new QTextCommandHistory( 100 ); tStopWidth = formatCollection()->defaultFormat()->width( 'x' ) * 8; } QTextDocument::~QTextDocument() { if ( par ) par->removeChild( this ); clear(); delete commandHistory; delete flow_; if ( !par ) delete pFormatter; delete fCollection; delete pProcessor; delete buf_pixmap; delete indenter; delete backBrush; if ( tArray ) delete [] tArray; } void QTextDocument::clear( bool createEmptyParag ) { if ( flow_ ) flow_->clear(); while ( fParag ) { QTextParagraph *p = fParag->next(); delete fParag; fParag = p; } fParag = lParag = 0; if ( createEmptyParag ) fParag = lParag = createParagraph( this ); selections.clear(); oText = QString::null; oTextValid = TRUE; } int QTextDocument::widthUsed() const { return wused + border_tolerance; } int QTextDocument::height() const { int h = 0; if ( lParag ) h = lParag->rect().top() + lParag->rect().height() + 1; int fh = flow_->boundingRect().bottom(); return QMAX( h, fh ); } QTextParagraph *QTextDocument::createParagraph( QTextDocument *d, QTextParagraph *pr, QTextParagraph *nx, bool updateIds ) { return new QTextParagraph( d, pr, nx, updateIds ); } bool QTextDocument::setMinimumWidth( int needed, int used, QTextParagraph *p ) { if ( needed == -1 ) { minw = 0; wused = 0; p = 0; } if ( p == minwParag ) { minw = needed; emit minimumWidthChanged( minw ); } 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 */ while ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) { if ( tags.isEmpty() ) break; curtag = tags.pop(); } } else if ( canMergeLi ) { /* we have an empty li and a block comes along, merge them */ nstyle = curtag.style; } canMergeLi = FALSE; } } } QTextCustomItem* custom = 0; // some well-known tags, some have a nstyle, some not if ( wellKnownTags.find( tagname ) != -1 ) { if ( tagname == "br" ) { emptyTag = space = TRUE; int index = QMAX( curpar->length(),1) - 1; QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor ); curpar->append( QChar_linesep ); curpar->setFormat( index, 1, &format ); } else if ( tagname == "hr" ) { emptyTag = space = TRUE; custom = sheet_->tag( tagname, attr, contxt, *factory_ , emptyTag, this ); NEWPAR; } else if ( tagname == "table" ) { emptyTag = space = TRUE; QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor ); curpar->setAlignment( curtag.alignment ); custom = parseTable( attr, format, doc, length, pos, curpar ); } else if ( tagname == "qt" || tagname == "body" ) { if ( attr.contains( "bgcolor" ) ) { QBrush *b = new QBrush( QColor( attr["bgcolor"] ) ); setPaper( b ); } if ( attr.contains( "background" ) ) { QImage img; QString bg = attr["background"]; const QMimeSource* m = factory_->data( bg, contxt ); if ( !m ) { owarn << "QRichText: no mimesource for " << bg.latin1() << "" << oendl; } else { if ( !QImageDrag::decode( m, img ) ) { owarn << "QTextImage: cannot decode " << bg.latin1() << "" << oendl; } } if ( !img.isNull() ) { QPixmap pm; pm.convertFromImage( img ); QBrush *b = new QBrush( QColor(), pm ); setPaper( b ); } } if ( attr.contains( "text" ) ) { QColor c( attr["text"] ); if ( formatCollection()->defaultFormat()->color() != c ) { QDict<QTextFormat> formats = formatCollection()->dict(); QDictIterator<QTextFormat> it( formats ); while ( it.current() ) { if ( it.current() == formatCollection()->defaultFormat() ) { ++it; continue; } it.current()->setColor( c ); ++it; } formatCollection()->defaultFormat()->setColor( c ); curtag.format.setColor( c ); } } if ( attr.contains( "link" ) ) linkColor = QColor( attr["link"] ); if ( attr.contains( "title" ) ) attribs.replace( "title", attr["title"] ); if ( textEditMode ) { if ( attr.contains("style" ) ) { QString a = attr["style"]; for ( int s = 0; s < a.contains(';')+1; s++ ) { QString style = QTextDocument::section( a, ";", s, s ); if ( style.startsWith("font-size:" ) && QTextDocument::endsWith(style, "pt") ) { scaleFontsFactor = double( formatCollection()->defaultFormat()->fn.pointSize() ) / style.mid( 10, style.length() - 12 ).toInt(); } } } nstyle = 0; // ignore body in textEditMode } // end qt- and body-tag handling } else if ( tagname == "meta" ) { if ( attr["name"] == "qrichtext" && attr["content"] == "1" ) textEditMode = TRUE; @@ -1726,389 +1706,386 @@ void QTextDocument::setRichTextInternal( const QString &text, QTextCursor* curso xMargin() functions we restrict ourselves to <ol>. Once we calculate the margins in the parser rathern than later, the unelegance of this approach goes awy */ if ( nstyle->name() == "ul" ) curtag.style = sheet_->item( "ol" ); if ( attr.contains( "align" ) ) { QString align = attr["align"]; if ( align == "center" ) curtag.alignment = Qt::AlignCenter; else if ( align == "right" ) curtag.alignment = Qt::AlignRight; else if ( align == "justify" ) curtag.alignment = Qt3::AlignJustify; } if ( attr.contains( "dir" ) ) { QString dir = attr["dir"]; if ( dir == "rtl" ) curtag.direction = QChar::DirR; else if ( dir == "ltr" ) curtag.direction = QChar::DirL; } NEWPAR; if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) { if ( attr.contains( "value " ) ) curpar->setListValue( attr["value"].toInt() ); } if ( attr.contains( "style" ) ) { QString a = attr["style"]; bool ok = TRUE; for ( int s = 0; ok && s < a.contains(';')+1; s++ ) { QString style = QTextDocument::section( a, ";", s, s ); if ( style.startsWith("margin-top:" ) && QTextDocument::endsWith(style, "px") ) curpar->utm = 1+style.mid(11, style.length() - 13).toInt(&ok); else if ( style.startsWith("margin-bottom:" ) && QTextDocument::endsWith(style, "px") ) curpar->ubm = 1+style.mid(14, style.length() - 16).toInt(&ok); else if ( style.startsWith("margin-left:" ) && QTextDocument::endsWith(style, "px") ) curpar->ulm = 1+style.mid(12, style.length() - 14).toInt(&ok); else if ( style.startsWith("margin-right:" ) && QTextDocument::endsWith(style, "px") ) curpar->urm = 1+style.mid(13, style.length() - 15).toInt(&ok); else if ( style.startsWith("text-indent:" ) && QTextDocument::endsWith(style, "px") ) curpar->uflm = 1+style.mid(12, style.length() - 14).toInt(&ok); } if ( !ok ) // be pressmistic curpar->utm = curpar->ubm = curpar->urm = curpar->ulm = 0; } } } } else { QString tagname = parseCloseTag( doc, length, pos ); if ( tagname.isEmpty() ) continue; // nothing we could do with this, probably parse error if ( !sheet_->item( tagname ) ) // ignore unknown tags continue; // we close a block item. Since the text may continue, we need to have a new paragraph bool needNewPar = curtag.style->displayMode() == QStyleSheetItem::DisplayBlock || curtag.style->displayMode() == QStyleSheetItem::DisplayListItem; // html slopiness: handle unbalanched tag closing while ( curtag.name != tagname ) { QString msg; msg.sprintf( "QText Warning: Document not valid ( '%s' not closed before '%s' #%d)", curtag.name.ascii(), tagname.ascii(), pos); sheet_->error( msg ); if ( tags.isEmpty() ) break; curtag = tags.pop(); } // close the tag if ( !tags.isEmpty() ) curtag = tags.pop(); else curtag = initag; if ( needNewPar ) { if ( textEditMode && tagname == "p" ) // preserve empty paragraphs hasNewPar = FALSE; NEWPAR; } } } else { // normal contents QString s; QChar c; while ( pos < length && !hasPrefix(doc, length, pos, QChar('<') ) ){ if ( textEditMode ) { // text edit mode: we handle all white space but ignore newlines 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 ]; m += QMAX( 0, item->margin( QStyleSheetItem::MarginRight ) ); } stylesPar->urm = m - stylesPar->rightMargin(); // do the first line margin, which really should be called text-indent item = mainStyle; if (stylesPar->uflm > 0 ) { m = stylesPar->uflm-1; stylesPar->uflm = 0; } else { m = QMAX( 0, item->margin( QStyleSheetItem::MarginFirstLine ) ); } for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) { item = (*curStyle)[ i ]; mar = QMAX( 0, item->margin( QStyleSheetItem::MarginFirstLine ) ); m = QMAX( m, mar ); } stylesPar->uflm =m - stylesPar->firstLineMargin(); // do the bogus line "spacing", which really is just an extra margin item = mainStyle; for ( i = (int)curStyle->size() - 1 ; i >= 0; --i ) { item = (*curStyle)[ i ]; if ( item->lineSpacing() != QStyleSheetItem::Undefined ) { stylesPar->ulinespacing = item->lineSpacing(); if ( formatCollection() && stylesPar->ulinespacing < formatCollection()->defaultFormat()->height() ) stylesPar->ulinespacing += formatCollection()->defaultFormat()->height(); break; } } stylesPar = stylesPar->next(); prevStyle = curStyle; curStyle = nextStyle; nextStyle = styles.next(); } } void QTextDocument::setText( const QString &text, const QString &context ) { focusIndicator.parag = 0; selections.clear(); if ( txtFormat == Qt::AutoText && QStyleSheet::mightBeRichText( text ) || txtFormat == Qt::RichText ) setRichText( text, context ); else setPlainText( text ); } QString QTextDocument::plainText() const { QString buffer; QString s; QTextParagraph *p = fParag; while ( p ) { if ( !p->mightHaveCustomItems ) { s = p->string()->toString(); } else { for ( int i = 0; i < p->length() - 1; ++i ) { if ( p->at( i )->isCustom() ) { if ( p->at( i )->customItem()->isNested() ) { s += "\n"; QTextTable *t = (QTextTable*)p->at( i )->customItem(); QPtrList<QTextTableCell> cells = t->tableCells(); for ( QTextTableCell *c = cells.first(); c; c = cells.next() ) s += c->richText()->plainText() + "\n"; s += "\n"; } } else { s += p->at( i )->c; } } } s.remove( s.length() - 1, 1 ); if ( p->next() ) s += "\n"; buffer += s; p = p->next(); } return buffer; } static QString align_to_string( int a ) { if ( a & Qt::AlignRight ) return " align=\"right\""; if ( a & Qt::AlignHCenter ) return " align=\"center\""; if ( a & Qt3::AlignJustify ) return " align=\"justify\""; return QString::null; } static QString direction_to_string( int d ) { @@ -2881,393 +2858,390 @@ bool QTextDocument::inSelection( int selId, const QPoint &pos ) const while ( p ) { if ( p->rect().contains( pos ) ) { bool inSel = FALSE; int selStart = p->selectionStart( selId ); int selEnd = p->selectionEnd( selId ); int y = 0; int h = 0; for ( int i = 0; i < p->length(); ++i ) { if ( i == selStart ) inSel = TRUE; if ( i == selEnd ) break; if ( p->at( i )->lineStart ) { y = (*p->lineStarts.find( i ))->y; h = (*p->lineStarts.find( i ))->h; } if ( pos.y() - p->rect().y() >= y && pos.y() - p->rect().y() <= y + h ) { if ( inSel && pos.x() >= p->at( i )->x && pos.x() <= p->at( i )->x + p->at( i )->format()->width( p->at( i )->c ) ) return TRUE; } } } if ( pos.y() < p->rect().y() ) break; if ( p == endParag ) break; p = p->next(); } return FALSE; } void QTextDocument::doLayout( QPainter *p, int w ) { minw = wused = 0; if ( !is_printer( p ) ) p = 0; withoutDoubleBuffer = ( p != 0 ); QPainter * oldPainter = QTextFormat::painter(); QTextFormat::setPainter( p ); flow_->setWidth( w ); cw = w; vw = w; QTextParagraph *parag = fParag; while ( parag ) { parag->invalidate( 0 ); if ( p ) parag->adjustToPainter( p ); parag->format(); parag = parag->next(); } QTextFormat::setPainter( oldPainter ); } QPixmap *QTextDocument::bufferPixmap( const QSize &s ) { if ( !buf_pixmap ) buf_pixmap = new QPixmap( s.expandedTo( QSize(1,1) ) ); else if ( buf_pixmap->size() != s ) buf_pixmap->resize( s.expandedTo( buf_pixmap->size() ) ); return buf_pixmap; } void QTextDocument::draw( QPainter *p, const QRect &rect, const QColorGroup &cg, const QBrush *paper ) { if ( !firstParagraph() ) return; if ( paper ) { p->setBrushOrigin( 0, 0 ); p->fillRect( rect, *paper ); } if ( formatCollection()->defaultFormat()->color() != cg.text() ) setDefaultFormat( formatCollection()->defaultFormat()->font(), cg.text() ); QTextParagraph *parag = firstParagraph(); while ( parag ) { if ( !parag->isValid() ) parag->format(); int y = parag->rect().y(); QRect pr( parag->rect() ); pr.setX( 0 ); pr.setWidth( QWIDGETSIZE_MAX ); if ( !rect.isNull() && !rect.intersects( pr ) ) { parag = parag->next(); continue; } p->translate( 0, y ); if ( rect.isValid() ) parag->paint( *p, cg, 0, FALSE, rect.x(), rect.y(), rect.width(), rect.height() ); else parag->paint( *p, cg, 0, FALSE ); p->translate( 0, -y ); 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(); focusIndicator.len = 0; } } else { focusIndicator.parag->setChanged( TRUE ); } focusIndicator.href = QString::null; if ( next ) { QTextParagraph *p = focusIndicator.parag; int index = focusIndicator.start + focusIndicator.len; while ( p ) { for ( int i = index; i < p->length(); ++i ) { if ( p->at( i )->isAnchor() ) { p->setChanged( TRUE ); focusIndicator.parag = p; focusIndicator.start = i; focusIndicator.len = 0; focusIndicator.href = p->at( i )->anchorHref(); while ( i < p->length() ) { if ( !p->at( i )->isAnchor() ) return TRUE; focusIndicator.len++; i++; } } else if ( p->at( i )->isCustom() ) { if ( p->at( i )->customItem()->isNested() ) { QTextTable *t = (QTextTable*)p->at( i )->customItem(); QPtrList<QTextTableCell> cells = t->tableCells(); // first try to continue QTextTableCell *c; bool resetCells = TRUE; for ( c = cells.first(); c; c = cells.next() ) { if ( c->richText()->hasFocusParagraph() ) { if ( c->richText()->focusNextPrevChild( next ) ) { p->setChanged( TRUE ); focusIndicator.parag = p; focusIndicator.start = i; focusIndicator.len = 0; focusIndicator.href = c->richText()->focusHref(); return TRUE; } else { resetCells = FALSE; c = cells.next(); break; } } } // now really try if ( resetCells ) c = cells.first(); for ( ; c; c = cells.next() ) { if ( c->richText()->focusNextPrevChild( next ) ) { p->setChanged( TRUE ); focusIndicator.parag = p; focusIndicator.start = i; focusIndicator.len = 0; focusIndicator.href = c->richText()->focusHref(); return TRUE; } } } } } index = 0; p = p->next(); } } else { QTextParagraph *p = focusIndicator.parag; int index = focusIndicator.start - 1; if ( focusIndicator.len == 0 && index < focusIndicator.parag->length() - 1 ) index++; while ( p ) { for ( int i = index; i >= 0; --i ) { if ( p->at( i )->isAnchor() ) { p->setChanged( TRUE ); focusIndicator.parag = p; focusIndicator.start = i; focusIndicator.len = 0; focusIndicator.href = p->at( i )->anchorHref(); while ( i >= -1 ) { if ( i < 0 || !p->at( i )->isAnchor() ) { focusIndicator.start++; return TRUE; } if ( i < 0 ) break; focusIndicator.len++; focusIndicator.start--; i--; } } else if ( p->at( i )->isCustom() ) { if ( p->at( i )->customItem()->isNested() ) { QTextTable *t = (QTextTable*)p->at( i )->customItem(); QPtrList<QTextTableCell> cells = t->tableCells(); // first try to continue QTextTableCell *c; @@ -5175,385 +5149,385 @@ int QTextFormatter::formatVertically( QTextDocument* doc, QTextParagraph* parag // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ QTextFormatterBreakInWords::QTextFormatterBreakInWords() { } #define SPACE(s) doc?(s>0?s:0):s int QTextFormatterBreakInWords::format( QTextDocument *doc,QTextParagraph *parag, int start, const QMap<int, QTextLineStart*> & ) { QTextStringChar *c = 0; QTextStringChar *firstChar = 0; int left = doc ? parag->leftMargin() + doc->leftMargin() : 0; int x = left + ( doc ? parag->firstLineMargin() : 0 ); int dw = parag->documentVisibleWidth() - ( doc ? doc->rightMargin() : 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, 4 ); int rm = parag->rightMargin(); int w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 ); bool fullWidth = TRUE; int minw = 0; int wused = 0; bool wrapEnabled = isWrapEnabled( parag ); start = 0; //######### what is the point with start?! (Matthias) if ( start == 0 ) c = ¶g->string()->at( 0 ); int i = start; QTextLineStart *lineStart = new QTextLineStart( y, y, 0 ); insertLineStart( parag, 0, lineStart ); QPainter *painter = QTextFormat::painter(); int col = 0; int ww = 0; QChar lastChr; for ( ; i < len; ++i, ++col ) { if ( c ) lastChr = c->c; c = ¶g->string()->at( i ); c->rightToLeft = FALSE; // ### the lines below should not be needed if ( painter ) c->format()->setPainter( painter ); if ( i > 0 ) { c->lineStart = 0; } else { c->lineStart = 1; firstChar = c; } if ( c->c.unicode() >= 32 || c->isCustom() ) { ww = parag->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( ' ' ); } if ( c->isCustom() && c->customItem()->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 ); c->customItem()->resize( w - x ); w = dw; y += h; h = c->height(); lineStart = new QTextLineStart( y, h, h ); insertLineStart( parag, i, lineStart ); c->lineStart = 1; firstChar = c; x = 0xffffff; continue; } if ( wrapEnabled && ( wrapAtColumn() == -1 && x + ww > w || wrapAtColumn() != -1 && col >= wrapAtColumn() ) ) { x = doc ? parag->document()->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left; w = dw; y += h; h = c->height(); lineStart = formatLine( parag, parag->string(), lineStart, firstChar, SPACE(c-1) ); lineStart->y = y; insertLineStart( parag, i, lineStart ); lineStart->baseLine = c->ascent(); lineStart->h = c->height(); c->lineStart = 1; firstChar = c; 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()) && ( (wrapAtColumn() == -1 && x + ww > w) || (wrapAtColumn() != -1 && col >= wrapAtColumn()) ) ) ) ) ) { if ( wrapAtColumn() != -1 ) minw = QMAX( minw, x + ww ); // if a break was forced (no breakable char, hard break or own line custom item), break immediately.... if ( !hadBreakableChar || lastWasHardBreak || lastWasOwnLineCustomItem ) { if ( lineStart ) { lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine ); h = QMAX( h, tmph ); lineStart->h = h; DO_FLOW( lineStart ); } lineStart = formatLine( parag, string, lineStart, firstChar, c-1, align, SPACE(w - x) ); 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 ); if ( !doc && c->c == '\t' ) { // qt_format_text tab handling int nx = parag->nextTab( i, x - left ) + left; if ( nx < x ) ww = w - x; else ww = nx - x; } curLeft = x; y += QMAX( h, linespacing ); tmph = c->height(); h = 0; lineStart->y = y; insertLineStart( parag, i, lineStart ); lineStart->baseLine = c->ascent(); lineStart->h = c->height(); c->lineStart = 1; firstChar = c; tmpBaseLine = lineStart->baseLine; lastBreak = -1; col = 0; } else { // ... otherwise if we had a breakable char, break there DO_FLOW( lineStart ); i = lastBreak; lineStart = formatLine( parag, string, lineStart, firstChar, parag->at( lastBreak ),align, SPACE(w - string->at( i ).x) ); 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 ); if ( !doc && c->c == '\t' ) { // qt_format_text tab handling int nx = parag->nextTab( i, x - left ) + left; if ( nx < x ) ww = w - x; else ww = nx - x; } curLeft = x; y += QMAX( h, linespacing ); tmph = c->height(); h = tmph; lineStart->y = y; insertLineStart( parag, i + 1, lineStart ); lineStart->baseLine = c->ascent(); lineStart->h = c->height(); c->lineStart = 1; firstChar = c; tmpBaseLine = lineStart->baseLine; lastBreak = -1; col = 0; tminw = marg; continue; } } else if ( lineStart && isBreakable( string, i ) ) { if ( len <= 2 || i < len - 1 ) { tmpBaseLine = QMAX( tmpBaseLine, c->ascent() ); tmph = QMAX( tmph, c->height() ); } minw = QMAX( minw, tminw ); tminw = marg + ww; lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine ); h = QMAX( h, tmph ); lineStart->h = h; if ( i < len - 2 || c->c != ' ' ) lastBreak = i; } else { tminw += ww; int belowBaseLine = QMAX( tmph - tmpBaseLine, c->height()- c->ascent() ); tmpBaseLine = QMAX( tmpBaseLine, c->ascent() ); tmph = tmpBaseLine + belowBaseLine; } c->x = x; x += ww; wused = QMAX( wused, x ); } // ### hack. The last char in the paragraph is always invisible, // ### and somehow sometimes has a wrong format. It changes // ### between // layouting and printing. This corrects some // ### layouting errors in BiDi mode due to this. if ( len > 1 && !c->isAnchor() ) { c->format()->removeRef(); |