Diffstat (limited to 'noncore/apps/opie-write/qrichtext.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/apps/opie-write/qrichtext.cpp | 28 |
1 files changed, 17 insertions, 11 deletions
diff --git a/noncore/apps/opie-write/qrichtext.cpp b/noncore/apps/opie-write/qrichtext.cpp index b77a0fc..c27eb1e 100644 --- a/noncore/apps/opie-write/qrichtext.cpp +++ b/noncore/apps/opie-write/qrichtext.cpp @@ -1,311 +1,317 @@ /**************************************************************************** ** $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 ) { - qWarning( "can't locate parag at %d, last parag: %d", id, doc->lastParagraph()->paragId() ); + owarn << "can't locate parag at " << id << ", last parag: " << doc->lastParagraph()->paragId() << "" << 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 ) { - qWarning( "can't locate parag at %d, last parag: %d", id, doc->lastParagraph()->paragId() ); + owarn << "can't locate parag at " << id << ", last parag: " << doc->lastParagraph()->paragId() << "" << 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(); } 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() ); @@ -1451,196 +1457,196 @@ void QTextDocument::setRichTextInternal( const QString &text, QTextCursor* curso 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 ) { - qWarning("QRichText: no mimesource for %s", bg.latin1() ); + owarn << "QRichText: no mimesource for " << bg.latin1() << "" << oendl; } else { if ( !QImageDrag::decode( m, img ) ) { - qWarning("QTextImage: cannot decode %s", bg.latin1() ); + 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; } else if ( tagname == "title" ) { QString title; while ( pos < length ) { if ( hasPrefix( doc, length, pos, QChar('<') ) && hasPrefix( doc, length, pos+1, QChar('/') ) && parseCloseTag( doc, length, pos ) == "title" ) break; title += doc[ pos ]; ++pos; } attribs.replace( "title", title ); } } // end of well-known tag handling if ( !custom ) // try generic custom item custom = sheet_->tag( tagname, attr, contxt, *factory_ , emptyTag, this ); if ( !nstyle && !custom ) // we have no clue what this tag could be, ignore it continue; if ( custom ) { int index = QMAX( curpar->length(),1) - 1; QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor ); curpar->append( QChar('*') ); curpar->setFormat( index, 1, &format ); curpar->at( index )->setCustomItem( custom ); if ( !curtag.anchorHref.isEmpty() ) curpar->at(index)->setAnchor( QString::null, curtag.anchorHref ); if ( !anchorName.isEmpty() ) { curpar->at(index)->setAnchor( anchorName, curpar->at(index)->anchorHref() ); anchorName = QString::null; } registerCustomItem( custom, curpar ); hasNewPar = FALSE; } else if ( !emptyTag ) { /* if we do nesting, push curtag on the stack, otherwise reinint curag. */ if ( curtag.style->name() != tagname || nstyle->selfNesting() ) { tags.push( curtag ); } else { if ( !tags.isEmpty() ) curtag = tags.top(); else curtag = initag; } curtag.name = tagname; curtag.style = nstyle; curtag.name = tagname; @@ -2059,193 +2065,193 @@ QString QTextDocument::plainText() const } 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 ) { if ( d != QChar::DirON ) return ( d == QChar::DirL? " dir=\"ltr\"" : " dir=\"rtl\"" ); return QString::null; } static QString list_value_to_string( int v ) { if ( v != -1 ) return " listvalue=\"" + QString::number( v ) + "\""; return QString::null; } static QString list_style_to_string( int v ) { switch( v ) { case QStyleSheetItem::ListDecimal: return "\"1\""; case QStyleSheetItem::ListLowerAlpha: return "\"a\""; case QStyleSheetItem::ListUpperAlpha: return "\"A\""; case QStyleSheetItem::ListDisc: return "\"disc\""; case QStyleSheetItem::ListSquare: return "\"square\""; case QStyleSheetItem::ListCircle: return "\"circle\""; default: return QString::null; } } static inline bool list_is_ordered( int v ) { return v == QStyleSheetItem::ListDecimal || v == QStyleSheetItem::ListLowerAlpha || v == QStyleSheetItem::ListUpperAlpha; } static QString margin_to_string( QStyleSheetItem* style, int t, int b, int l, int r, int fl ) { QString s; if ( l > 0 ) s += QString(!!s?";":"") + "margin-left:" + QString::number(l+QMAX(0,style->margin(QStyleSheetItem::MarginLeft))) + "px"; if ( r > 0 ) s += QString(!!s?";":"") + "margin-right:" + QString::number(r+QMAX(0,style->margin(QStyleSheetItem::MarginRight))) + "px"; if ( t > 0 ) s += QString(!!s?";":"") + "margin-top:" + QString::number(t+QMAX(0,style->margin(QStyleSheetItem::MarginTop))) + "px"; if ( b > 0 ) s += QString(!!s?";":"") + "margin-bottom:" + QString::number(b+QMAX(0,style->margin(QStyleSheetItem::MarginBottom))) + "px"; if ( fl > 0 ) s += QString(!!s?";":"") + "text-indent:" + QString::number(fl+QMAX(0,style->margin(QStyleSheetItem::MarginFirstLine))) + "px"; if ( !!s ) return " style=\"" + s + "\""; return QString::null; } QString QTextDocument::richText() const { QString s = ""; if ( !par ) { s += "<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body style=\"font-size:" ; s += QString::number( formatCollection()->defaultFormat()->font().pointSize() ); s += "pt;font-family:"; s += formatCollection()->defaultFormat()->font().family(); s +="\">"; } QTextParagraph* p = fParag; QStyleSheetItem* item_p = styleSheet()->item("p"); QStyleSheetItem* item_ul = styleSheet()->item("ul"); QStyleSheetItem* item_ol = styleSheet()->item("ol"); QStyleSheetItem* item_li = styleSheet()->item("li"); if ( !item_p || !item_ul || !item_ol || !item_li ) { - qWarning( "QTextEdit: cannot export HTML due to insufficient stylesheet (lack of p, ul, ol, or li)" ); + owarn << "QTextEdit: cannot export HTML due to insufficient stylesheet (lack of p, ul, ol, or li)" << oendl; return QString::null; } int pastListDepth = 0; int listDepth = 0; int futureListDepth = 0; QMemArray<int> listStyles(10); while ( p ) { listDepth = p->listDepth(); if ( listDepth < pastListDepth ) { for ( int i = listDepth+1; i <= pastListDepth; i++ ) s += list_is_ordered( listStyles[i] ) ? "</ol>" : "</ul>"; s += '\n'; } else if ( listDepth > pastListDepth ) { s += '\n'; listStyles.resize( QMAX( (int)listStyles.size(), listDepth+1 ) ); QString list_type; listStyles[listDepth] = p->listStyle(); if ( !list_is_ordered( p->listStyle() ) || item_ol->listStyle() != p->listStyle() ) list_type = " type=" + list_style_to_string( p->listStyle() ); for ( int i = pastListDepth; i < listDepth; i++ ) { s += list_is_ordered( p->listStyle() ) ? "<ol" : "<ul" ; s += list_type + ">"; } } else { s += '\n'; } QString ps = p->richText(); // for the bottom margin we need to know whether we are at the end of a list futureListDepth = 0; if ( listDepth > 0 && p->next() ) futureListDepth = p->next()->listDepth(); if ( richTextExportStart && richTextExportStart->paragraph() ==p && richTextExportStart->index() == 0 ) s += "<selstart/>"; if ( p->isListItem() ) { s += "<li"; if ( p->listStyle() != listStyles[listDepth] ) s += " type=" + list_style_to_string( p->listStyle() ); s +=align_to_string( p->alignment() ); s += margin_to_string( item_li, p->utm, p->ubm, p->ulm, p->urm, p->uflm ); s += list_value_to_string( p->listValue() ); s += direction_to_string( p->direction() ); s +=">"; s += ps; s += "</li>"; } else { // normal paragraph item s += "<p"; s += align_to_string( p->alignment() ); s += margin_to_string( item_p, p->utm, p->ubm, p->ulm, p->urm, p->uflm ); s +=direction_to_string( p->direction() ); s += ">"; s += ps; s += "</p>"; } pastListDepth = listDepth; p = p->next(); } while ( listDepth > 0 ) { s += list_is_ordered( listStyles[listDepth] ) ? "</ol>" : "</ul>"; listDepth--; } if ( !par ) s += "\n</body></html>\n"; return s; } QString QTextDocument::text() const { if ( txtFormat == Qt::AutoText && preferRichText || txtFormat == Qt::RichText ) return richText(); return plainText(); } QString QTextDocument::text( int parag ) const { QTextParagraph *p = paragAt( parag ); if ( !p ) return QString::null; if ( txtFormat == Qt::AutoText && preferRichText || txtFormat == Qt::RichText ) return p->richText(); else return p->string()->toString(); } void QTextDocument::invalidate() { QTextParagraph *s = fParag; @@ -4003,246 +4009,246 @@ void QTextParagraph::format( int start, bool doMove ) // with has to be the full document width on mac as the selections // always extend completely to the right. This is a bit unefficient, // as this results in a bigger double buffer than needed but ok for // now. if ( lineStarts.count() == 1 ) { if ( !string()->isBidi() ) { c = &str->at( str->length() - 1 ); r.setWidth( c->x + str->width( str->length() - 1 ) ); } else { r.setWidth( lineStarts[0]->w ); } } if ( !hasdoc ) { // qt_format_text bounding rect handling it = lineStarts.begin(); int usedw = 0; for ( ; it != lineStarts.end(); ++it ) usedw = QMAX( usedw, (*it)->w ); if ( r.width() <= 0 ) { // if the user specifies an invalid rect, this means that the // bounding box should grow to the width that the text actually // needs r.setWidth( usedw ); } else { r.setWidth( QMIN( usedw, r.width() ) ); } } if ( y != r.height() ) r.setHeight( y ); if ( !visible ) { r.setHeight( 0 ); } else { int minw = formatter()->minimumWidth(); int wused = formatter()->widthUsed(); wused = QMAX( minw, wused ); if ( hasdoc ) { document()->setMinimumWidth( minw, wused, this ); } else { pseudoDocument()->minw = QMAX( pseudoDocument()->minw, minw ); pseudoDocument()->wused = QMAX( pseudoDocument()->wused, wused ); } } // do page breaks if required if ( hasdoc && document()->isPageBreakEnabled() ) { int shift = document()->formatter()->formatVertically( document(), this ); if ( shift && !formattedAgain ) { formattedAgain = TRUE; goto formatAgain; } } if ( n && doMove && n->invalid == -1 && r.y() + r.height() != n->r.y() ) { int dy = ( r.y() + r.height() ) - n->r.y(); QTextParagraph *s = n; bool makeInvalid = p && p->lastInFrame; while ( s && dy ) { if ( !s->isFullWidth() ) makeInvalid = TRUE; if ( makeInvalid ) s->invalidate( 0 ); s->move( dy ); if ( s->lastInFrame ) makeInvalid = TRUE; s = s->n; } } firstFormat = FALSE; changed = TRUE; invalid = -1; //##### string()->setTextChanged( FALSE ); } int QTextParagraph::lineHeightOfChar( int i, int *bl, int *y ) const { if ( !isValid() ) ( (QTextParagraph*)this )->format(); QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.end(); --it; for ( ;; ) { if ( i >= it.key() ) { if ( bl ) *bl = ( *it )->baseLine; if ( y ) *y = ( *it )->y; return ( *it )->h; } if ( it == lineStarts.begin() ) break; --it; } - qWarning( "QTextParagraph::lineHeightOfChar: couldn't find lh for %d", i ); + owarn << "QTextParagraph::lineHeightOfChar: couldn't find lh for " << i << "" << oendl; return 15; } QTextStringChar *QTextParagraph::lineStartOfChar( int i, int *index, int *line ) const { if ( !isValid() ) ( (QTextParagraph*)this )->format(); int l = (int)lineStarts.count() - 1; QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.end(); --it; for ( ;; ) { if ( i >= it.key() ) { if ( index ) *index = it.key(); if ( line ) *line = l; return &str->at( it.key() ); } if ( it == lineStarts.begin() ) break; --it; --l; } - qWarning( "QTextParagraph::lineStartOfChar: couldn't find %d", i ); + owarn << "QTextParagraph::lineStartOfChar: couldn't find " << i << "" << oendl; return 0; } int QTextParagraph::lines() const { if ( !isValid() ) ( (QTextParagraph*)this )->format(); return (int)lineStarts.count(); } QTextStringChar *QTextParagraph::lineStartOfLine( int line, int *index ) const { if ( !isValid() ) ( (QTextParagraph*)this )->format(); if ( line >= 0 && line < (int)lineStarts.count() ) { QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.begin(); while ( line-- > 0 ) ++it; int i = it.key(); if ( index ) *index = i; return &str->at( i ); } - qWarning( "QTextParagraph::lineStartOfLine: couldn't find %d", line ); + owarn << "QTextParagraph::lineStartOfLine: couldn't find " << line << "" << oendl; return 0; } int QTextParagraph::leftGap() const { if ( !isValid() ) ( (QTextParagraph*)this )->format(); int line = 0; int x = str->at(0).x; /* set x to x of first char */ if ( str->isBidi() ) { for ( int i = 1; i < str->length()-1; ++i ) x = QMIN(x, str->at(i).x); return x; } QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.begin(); while (line < (int)lineStarts.count()) { int i = it.key(); /* char index */ x = QMIN(x, str->at(i).x); ++it; ++line; } return x; } void QTextParagraph::setFormat( int index, int len, QTextFormat *f, bool useCollection, int flags ) { if ( !f ) return; if ( index < 0 ) index = 0; if ( index > str->length() - 1 ) index = str->length() - 1; if ( index + len >= str->length() ) len = str->length() - index; QTextFormatCollection *fc = 0; if ( useCollection ) fc = formatCollection(); QTextFormat *of; for ( int i = 0; i < len; ++i ) { of = str->at( i + index ).format(); if ( !changed && f->key() != of->key() ) changed = TRUE; if ( invalid == -1 && ( f->font().family() != of->font().family() || f->font().pointSize() != of->font().pointSize() || f->font().weight() != of->font().weight() || f->font().italic() != of->font().italic() || f->vAlign() != of->vAlign() ) ) { invalidate( 0 ); } if ( flags == -1 || flags == QTextFormat::Format || !fc ) { if ( fc ) f = fc->format( f ); str->setFormat( i + index, f, useCollection ); } else { QTextFormat *fm = fc->format( of, f, flags ); str->setFormat( i + index, fm, useCollection ); } } } void QTextParagraph::indent( int *oldIndent, int *newIndent ) { if ( !hasdoc || !document()->indent() || isListItem() ) { if ( oldIndent ) *oldIndent = 0; if ( newIndent ) *newIndent = 0; if ( oldIndent && newIndent ) *newIndent = *oldIndent; return; } document()->indent()->indent( document(), this, oldIndent, newIndent ); } void QTextParagraph::paint( QPainter &painter, const QColorGroup &cg, QTextCursor *cursor, bool drawSelections, int clipx, int clipy, int clipw, int cliph ) { if ( !visible ) return; QTextStringChar *chr = 0; int i, y, h, baseLine, xstart, xend; i = y =h = baseLine = 0; QRect cursorRect; drawSelections &= ( mSelections != 0 ); // macintosh full-width selection style bool fullWidthStyle = FALSE; int fullSelectionWidth = 0; if ( drawSelections && fullWidthStyle ) fullSelectionWidth = (hasdoc ? document()->width() : r.width()); QString qstr = str->toString(); // ### workaround so that \n are not drawn, actually this should @@ -5604,193 +5610,193 @@ QTextFormat *QTextFormatCollection::format( QTextFormat *f ) return lastFormat; } if ( f == lastFormat || ( lastFormat && f->key() == lastFormat->key() ) ) { lastFormat->addRef(); return lastFormat; } QTextFormat *fm = cKey.find( f->key() ); if ( fm ) { lastFormat = fm; lastFormat->addRef(); return lastFormat; } if ( f->key() == defFormat->key() ) return defFormat; lastFormat = createFormat( *f ); lastFormat->collection = this; cKey.insert( lastFormat->key(), lastFormat ); return lastFormat; } QTextFormat *QTextFormatCollection::format( QTextFormat *of, QTextFormat *nf, int flags ) { if ( cres && kof == of->key() && knf == nf->key() && cflags == flags ) { cres->addRef(); return cres; } cres = createFormat( *of ); kof = of->key(); knf = nf->key(); cflags = flags; if ( flags & QTextFormat::Bold ) cres->fn.setBold( nf->fn.bold() ); if ( flags & QTextFormat::Italic ) cres->fn.setItalic( nf->fn.italic() ); if ( flags & QTextFormat::Underline ) cres->fn.setUnderline( nf->fn.underline() ); if ( flags & QTextFormat::StrikeOut ) cres->fn.setStrikeOut( nf->fn.strikeOut() ); if ( flags & QTextFormat::Family ) cres->fn.setFamily( nf->fn.family() ); if ( flags & QTextFormat::Size ) { if ( of->usePixelSizes ) cres->fn.setPixelSize( nf->fn.pixelSize() ); else cres->fn.setPointSize( nf->fn.pointSize() ); } if ( flags & QTextFormat::Color ) cres->col = nf->col; if ( flags & QTextFormat::Misspelled ) cres->missp = nf->missp; if ( flags & QTextFormat::VAlign ) cres->ha = nf->ha; cres->update(); QTextFormat *fm = cKey.find( cres->key() ); if ( !fm ) { cres->collection = this; cKey.insert( cres->key(), cres ); } else { delete cres; cres = fm; cres->addRef(); } return cres; } QTextFormat *QTextFormatCollection::format( const QFont &f, const QColor &c ) { if ( cachedFormat && cfont == f && ccol == c ) { cachedFormat->addRef(); return cachedFormat; } QString key = QTextFormat::getKey( f, c, FALSE, QTextFormat::AlignNormal ); cachedFormat = cKey.find( key ); cfont = f; ccol = c; if ( cachedFormat ) { cachedFormat->addRef(); return cachedFormat; } if ( key == defFormat->key() ) return defFormat; cachedFormat = createFormat( f, c ); cachedFormat->collection = this; cKey.insert( cachedFormat->key(), cachedFormat ); if ( cachedFormat->key() != key ) - qWarning("ASSERT: keys for format not identical: '%s '%s'", cachedFormat->key().latin1(), key.latin1() ); + owarn << "ASSERT: keys for format not identical: '" << cachedFormat->key().latin1() << " '" << key.latin1() << "'" << oendl; return cachedFormat; } void QTextFormatCollection::remove( QTextFormat *f ) { if ( lastFormat == f ) lastFormat = 0; if ( cres == f ) cres = 0; if ( cachedFormat == f ) cachedFormat = 0; cKey.remove( f->key() ); } #define UPDATE( up, lo, rest ) \ if ( font.lo##rest() != defFormat->fn.lo##rest() && fm->fn.lo##rest() == defFormat->fn.lo##rest() ) \ fm->fn.set##up##rest( font.lo##rest() ) void QTextFormatCollection::updateDefaultFormat( const QFont &font, const QColor &color, QStyleSheet *sheet ) { QDictIterator<QTextFormat> it( cKey ); QTextFormat *fm; bool usePixels = font.pointSize() == -1; bool changeSize = usePixels ? font.pixelSize() != defFormat->fn.pixelSize() : font.pointSize() != defFormat->fn.pointSize(); int base = usePixels ? font.pixelSize() : font.pointSize(); while ( ( fm = it.current() ) ) { ++it; UPDATE( F, f, amily ); UPDATE( W, w, eight ); UPDATE( B, b, old ); UPDATE( I, i, talic ); UPDATE( U, u, nderline ); if ( changeSize ) { fm->stdSize = base; fm->usePixelSizes = usePixels; if ( usePixels ) fm->fn.setPixelSize( fm->stdSize ); else fm->fn.setPointSize( fm->stdSize ); sheet->scaleFont( fm->fn, fm->logicalFontSize ); } if ( color.isValid() && color != defFormat->col && fm->col == defFormat->col ) fm->col = color; fm->update(); } defFormat->fn = font; defFormat->col = color; defFormat->update(); defFormat->stdSize = base; defFormat->usePixelSizes = usePixels; updateKeys(); } // the keys in cKey have changed, rebuild the hashtable void QTextFormatCollection::updateKeys() { if ( cKey.isEmpty() ) return; cKey.setAutoDelete( FALSE ); QTextFormat** formats = new QTextFormat*[ cKey.count() + 1 ]; QTextFormat **f = formats; QDictIterator<QTextFormat> it( cKey ); while ( ( *f = it.current() ) ) { ++it; ++f; } cKey.clear(); for ( f = formats; *f; f++ ) cKey.insert( (*f)->key(), *f ); cKey.setAutoDelete( TRUE ); delete [] formats; } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void QTextFormat::setBold( bool b ) { if ( b == fn.bold() ) return; fn.setBold( b ); update(); } void QTextFormat::setMisspelled( bool b ) { if ( b == (bool)missp ) return; missp = b; update(); } @@ -5990,197 +5996,197 @@ QTextFormat QTextFormat::makeTextFormat( const QStyleSheetItem *style, const QMa if ( attr.contains("size") ) { QString a = attr["size"]; int n = a.toInt(); if ( a[0] == '+' || a[0] == '-' ) n += format.logicalFontSize; format.logicalFontSize = n; if ( format.usePixelSizes ) format.fn.setPixelSize( format.stdSize ); else format.fn.setPointSize( format.stdSize ); style->styleSheet()->scaleFont( format.fn, format.logicalFontSize ); } } 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") ) { format.logicalFontSize = 0; format.setPointSize( int( scaleFontsFactor * style.mid( 10, style.length() - 12 ).toInt() ) ); } if ( style.startsWith("font-style:" ) ) { QString s = style.mid( 11 ).stripWhiteSpace(); if ( s == "normal" ) format.fn.setItalic( FALSE ); else if ( s == "italic" || s == "oblique" ) format.fn.setItalic( TRUE ); } else if ( style.startsWith("font-weight:" ) ) { QString s = style.mid( 12 ); bool ok = TRUE; int n = s.toInt( &ok ); if ( ok ) format.fn.setWeight( n/8 ); } else if ( style.startsWith("font-family:" ) ) { format.fn.setFamily( QTextDocument::section(style.mid(12),",",0,0).stripWhiteSpace() ); } else if ( style.startsWith("text-decoration:" ) ) { QString s = style.mid( 16 ).stripWhiteSpace(); format.fn.setUnderline( s == "underline" ); } else if ( style.startsWith("vertical-align:" ) ) { QString s = style.mid( 15 ).stripWhiteSpace(); if ( s == "sub" ) format.setVAlign( QTextFormat::AlignSubScript ); else if ( s == "super" ) format.setVAlign( QTextFormat::AlignSuperScript ); else format.setVAlign( QTextFormat::AlignNormal ); } else if ( style.startsWith("color:" ) ) { format.col.setNamedColor( style.mid(6) ); format.linkColor = FALSE; } } } format.update(); return format; } struct QPixmapInt { QPixmapInt() : ref( 0 ) {} QPixmap pm; int ref; }; static QMap<QString, QPixmapInt> *pixmap_map = 0; QTextImage::QTextImage( QTextDocument *p, const QMap<QString, QString> &attr, const QString& context, QMimeSourceFactory &factory ) : QTextCustomItem( p ) { width = height = 0; if ( attr.contains("width") ) width = attr["width"].toInt(); if ( attr.contains("height") ) height = attr["height"].toInt(); reg = 0; QString imageName = attr["src"]; if (!imageName) imageName = attr["source"]; if ( !imageName.isEmpty() ) { imgId = QString( "%1,%2,%3,%4" ).arg( imageName ).arg( width ).arg( height ).arg( (ulong)&factory ); if ( !pixmap_map ) pixmap_map = new QMap<QString, QPixmapInt>; if ( pixmap_map->contains( imgId ) ) { QPixmapInt& pmi = pixmap_map->operator[](imgId); pm = pmi.pm; pmi.ref++; width = pm.width(); height = pm.height(); } else { QImage img; const QMimeSource* m = factory.data( imageName, context ); if ( !m ) { - qWarning("QTextImage: no mimesource for %s", imageName.latin1() ); + owarn << "QTextImage: no mimesource for " << imageName.latin1() << "" << oendl; } else { if ( !QImageDrag::decode( m, img ) ) { - qWarning("QTextImage: cannot decode %s", imageName.latin1() ); + owarn << "QTextImage: cannot decode " << imageName.latin1() << "" << oendl; } } if ( !img.isNull() ) { if ( width == 0 ) { width = img.width(); if ( height != 0 ) { width = img.width() * height / img.height(); } } if ( height == 0 ) { height = img.height(); if ( width != img.width() ) { height = img.height() * width / img.width(); } } if ( img.width() != width || img.height() != height ){ #ifndef QT_NO_IMAGE_SMOOTHSCALE img = img.smoothScale(width, height); #endif width = img.width(); height = img.height(); } pm.convertFromImage( img ); } if ( !pm.isNull() ) { QPixmapInt& pmi = pixmap_map->operator[](imgId); pmi.pm = pm; pmi.ref++; } } if ( pm.mask() ) { QRegion mask( *pm.mask() ); QRegion all( 0, 0, pm.width(), pm.height() ); reg = new QRegion( all.subtract( mask ) ); } } if ( pm.isNull() && (width*height)==0 ) width = height = 50; place = PlaceInline; if ( attr["align"] == "left" ) place = PlaceLeft; else if ( attr["align"] == "right" ) place = PlaceRight; tmpwidth = width; tmpheight = height; attributes = attr; } QTextImage::~QTextImage() { if ( pixmap_map && pixmap_map->contains( imgId ) ) { QPixmapInt& pmi = pixmap_map->operator[](imgId); pmi.ref--; if ( !pmi.ref ) { pixmap_map->remove( imgId ); if ( pixmap_map->isEmpty() ) { delete pixmap_map; pixmap_map = 0; } } } delete reg; } QString QTextImage::richText() const { QString s; s += "<img "; QMap<QString, QString>::ConstIterator it = attributes.begin(); for ( ; it != attributes.end(); ++it ) s += it.key() + "=" + *it + " "; s += ">"; return s; } void QTextImage::adjustToPainter( QPainter* p ) { width = scale( tmpwidth, p ); height = scale( tmpheight, p ); } #if !defined(Q_WS_X11) #include <qbitmap.h> #include "qcleanuphandler.h" static QPixmap *qrt_selection = 0; static QSingleCleanupHandler<QPixmap> qrt_cleanup_pixmap; static void qrt_createSelectionPixmap( const QColorGroup &cg ) { qrt_selection = new QPixmap( 2, 2 ); qrt_cleanup_pixmap.set( &qrt_selection ); qrt_selection->fill( Qt::color0 ); |