summaryrefslogtreecommitdiff
path: root/noncore/apps/opie-write/qrichtext.cpp
Side-by-side diff
Diffstat (limited to 'noncore/apps/opie-write/qrichtext.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/apps/opie-write/qrichtext.cpp28
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 );