| 1 | /****************************************************************************
|
|---|
| 2 | ** $Id: qrichtext.cpp 8 2005-11-16 19:36:46Z dmik $
|
|---|
| 3 | **
|
|---|
| 4 | ** Implementation of the internal Qt classes dealing with rich text
|
|---|
| 5 | **
|
|---|
| 6 | ** Created : 990101
|
|---|
| 7 | **
|
|---|
| 8 | ** Copyright (C) 1992-2003 Trolltech AS. All rights reserved.
|
|---|
| 9 | **
|
|---|
| 10 | ** This file is part of the kernel module of the Qt GUI Toolkit.
|
|---|
| 11 | **
|
|---|
| 12 | ** This file may be distributed under the terms of the Q Public License
|
|---|
| 13 | ** as defined by Trolltech AS of Norway and appearing in the file
|
|---|
| 14 | ** LICENSE.QPL included in the packaging of this file.
|
|---|
| 15 | **
|
|---|
| 16 | ** This file may be distributed and/or modified under the terms of the
|
|---|
| 17 | ** GNU General Public License version 2 as published by the Free Software
|
|---|
| 18 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
|---|
| 19 | ** packaging of this file.
|
|---|
| 20 | **
|
|---|
| 21 | ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
|
|---|
| 22 | ** licenses may use this file in accordance with the Qt Commercial License
|
|---|
| 23 | ** Agreement provided with the Software.
|
|---|
| 24 | **
|
|---|
| 25 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|---|
| 26 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|---|
| 27 | **
|
|---|
| 28 | ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
|
|---|
| 29 | ** information about Qt Commercial License Agreements.
|
|---|
| 30 | ** See http://www.trolltech.com/qpl/ for QPL licensing information.
|
|---|
| 31 | ** See http://www.trolltech.com/gpl/ for GPL licensing information.
|
|---|
| 32 | **
|
|---|
| 33 | ** Contact info@trolltech.com if any conditions of this licensing are
|
|---|
| 34 | ** not clear to you.
|
|---|
| 35 | **
|
|---|
| 36 | **********************************************************************/
|
|---|
| 37 |
|
|---|
| 38 | #include "qrichtext_p.h"
|
|---|
| 39 |
|
|---|
| 40 | #ifndef QT_NO_RICHTEXT
|
|---|
| 41 |
|
|---|
| 42 |
|
|---|
| 43 | #include "qstringlist.h"
|
|---|
| 44 | #include "qfont.h"
|
|---|
| 45 | #include "qtextstream.h"
|
|---|
| 46 | #include "qfile.h"
|
|---|
| 47 | #include "qapplication.h"
|
|---|
| 48 | #include "qmap.h"
|
|---|
| 49 | #include "qfileinfo.h"
|
|---|
| 50 | #include "qstylesheet.h"
|
|---|
| 51 | #include "qmime.h"
|
|---|
| 52 | #include "qimage.h"
|
|---|
| 53 | #include "qdragobject.h"
|
|---|
| 54 | #include "qpaintdevicemetrics.h"
|
|---|
| 55 | #include "qpainter.h"
|
|---|
| 56 | #include "qdrawutil.h"
|
|---|
| 57 | #include "qcursor.h"
|
|---|
| 58 | #include "qptrstack.h"
|
|---|
| 59 | #include "qptrdict.h"
|
|---|
| 60 | #include "qstyle.h"
|
|---|
| 61 | #include "qcleanuphandler.h"
|
|---|
| 62 | #include "qtextengine_p.h"
|
|---|
| 63 | #include <private/qunicodetables_p.h>
|
|---|
| 64 |
|
|---|
| 65 | #include <stdlib.h>
|
|---|
| 66 |
|
|---|
| 67 | static QTextCursor* richTextExportStart = 0;
|
|---|
| 68 | static QTextCursor* richTextExportEnd = 0;
|
|---|
| 69 |
|
|---|
| 70 | class QTextFormatCollection;
|
|---|
| 71 |
|
|---|
| 72 | const int border_tolerance = 2;
|
|---|
| 73 |
|
|---|
| 74 | #ifdef Q_WS_WIN
|
|---|
| 75 | #include "qt_windows.h"
|
|---|
| 76 | #endif
|
|---|
| 77 |
|
|---|
| 78 | #ifdef Q_WS_PM
|
|---|
| 79 | #include "qt_os2.h"
|
|---|
| 80 | #endif
|
|---|
| 81 |
|
|---|
| 82 | #define QChar_linesep QChar(0x2028U)
|
|---|
| 83 |
|
|---|
| 84 | static inline bool is_printer( QPainter *p )
|
|---|
| 85 | {
|
|---|
| 86 | if ( !p || !p->device() )
|
|---|
| 87 | return FALSE;
|
|---|
| 88 | return p->device()->devType() == QInternal::Printer;
|
|---|
| 89 | }
|
|---|
| 90 |
|
|---|
| 91 | static inline int scale( int value, QPainter *painter )
|
|---|
| 92 | {
|
|---|
| 93 | if ( is_printer( painter ) ) {
|
|---|
| 94 | QPaintDeviceMetrics metrics( painter->device() );
|
|---|
| 95 | #if defined(Q_WS_X11)
|
|---|
| 96 | value = value * metrics.logicalDpiY() /
|
|---|
| 97 | QPaintDevice::x11AppDpiY( painter->device()->x11Screen() );
|
|---|
| 98 | #elif defined (Q_WS_WIN)
|
|---|
| 99 | HDC hdc = GetDC( 0 );
|
|---|
| 100 | int gdc = GetDeviceCaps( hdc, LOGPIXELSY );
|
|---|
| 101 | if ( gdc )
|
|---|
| 102 | value = value * metrics.logicalDpiY() / gdc;
|
|---|
| 103 | ReleaseDC( 0, hdc );
|
|---|
| 104 | #elif defined (Q_WS_PM)
|
|---|
| 105 | LONG dpi;
|
|---|
| 106 | DevQueryCaps( GpiQueryDevice( qt_display_ps() ),
|
|---|
| 107 | CAPS_VERTICAL_FONT_RES, 1, &dpi );
|
|---|
| 108 | value = value * metrics.logicalDpiY() / dpi;
|
|---|
| 109 | #elif defined (Q_WS_MAC)
|
|---|
| 110 | value = value * metrics.logicalDpiY() / 75; // ##### FIXME
|
|---|
| 111 | #elif defined (Q_WS_QWS)
|
|---|
| 112 | value = value * metrics.logicalDpiY() / 75;
|
|---|
| 113 | #endif
|
|---|
| 114 | }
|
|---|
| 115 | return value;
|
|---|
| 116 | }
|
|---|
| 117 |
|
|---|
| 118 |
|
|---|
| 119 | inline bool isBreakable( QTextString *string, int pos )
|
|---|
| 120 | {
|
|---|
| 121 | if (string->at(pos).nobreak)
|
|---|
| 122 | return FALSE;
|
|---|
| 123 | return (pos < string->length()-1 && string->at(pos+1).softBreak);
|
|---|
| 124 | }
|
|---|
| 125 |
|
|---|
| 126 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 127 |
|
|---|
| 128 | void QTextCommandHistory::addCommand( QTextCommand *cmd )
|
|---|
| 129 | {
|
|---|
| 130 | if ( current < (int)history.count() - 1 ) {
|
|---|
| 131 | QPtrList<QTextCommand> commands;
|
|---|
| 132 | commands.setAutoDelete( FALSE );
|
|---|
| 133 |
|
|---|
| 134 | for( int i = 0; i <= current; ++i ) {
|
|---|
| 135 | commands.insert( i, history.at( 0 ) );
|
|---|
| 136 | history.take( 0 );
|
|---|
| 137 | }
|
|---|
| 138 |
|
|---|
| 139 | commands.append( cmd );
|
|---|
| 140 | history.clear();
|
|---|
| 141 | history = commands;
|
|---|
| 142 | history.setAutoDelete( TRUE );
|
|---|
| 143 | } else {
|
|---|
| 144 | history.append( cmd );
|
|---|
| 145 | }
|
|---|
| 146 |
|
|---|
| 147 | if ( (int)history.count() > steps )
|
|---|
| 148 | history.removeFirst();
|
|---|
| 149 | else
|
|---|
| 150 | ++current;
|
|---|
| 151 | }
|
|---|
| 152 |
|
|---|
| 153 | QTextCursor *QTextCommandHistory::undo( QTextCursor *c )
|
|---|
| 154 | {
|
|---|
| 155 | if ( current > -1 ) {
|
|---|
| 156 | QTextCursor *c2 = history.at( current )->unexecute( c );
|
|---|
| 157 | --current;
|
|---|
| 158 | return c2;
|
|---|
| 159 | }
|
|---|
| 160 | return 0;
|
|---|
| 161 | }
|
|---|
| 162 |
|
|---|
| 163 | QTextCursor *QTextCommandHistory::redo( QTextCursor *c )
|
|---|
| 164 | {
|
|---|
| 165 | if ( current > -1 ) {
|
|---|
| 166 | if ( current < (int)history.count() - 1 ) {
|
|---|
| 167 | ++current;
|
|---|
| 168 | return history.at( current )->execute( c );
|
|---|
| 169 | }
|
|---|
| 170 | } else {
|
|---|
| 171 | if ( history.count() > 0 ) {
|
|---|
| 172 | ++current;
|
|---|
| 173 | return history.at( current )->execute( c );
|
|---|
| 174 | }
|
|---|
| 175 | }
|
|---|
| 176 | return 0;
|
|---|
| 177 | }
|
|---|
| 178 |
|
|---|
| 179 | bool QTextCommandHistory::isUndoAvailable()
|
|---|
| 180 | {
|
|---|
| 181 | return current > -1;
|
|---|
| 182 | }
|
|---|
| 183 |
|
|---|
| 184 | bool QTextCommandHistory::isRedoAvailable()
|
|---|
| 185 | {
|
|---|
| 186 | return current > -1 && current < (int)history.count() - 1 || current == -1 && history.count() > 0;
|
|---|
| 187 | }
|
|---|
| 188 |
|
|---|
| 189 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 190 |
|
|---|
| 191 | QTextDeleteCommand::QTextDeleteCommand( QTextDocument *d, int i, int idx, const QMemArray<QTextStringChar> &str,
|
|---|
| 192 | const QByteArray& oldStyleInfo )
|
|---|
| 193 | : QTextCommand( d ), id( i ), index( idx ), parag( 0 ), text( str ), styleInformation( oldStyleInfo )
|
|---|
| 194 | {
|
|---|
| 195 | for ( int j = 0; j < (int)text.size(); ++j ) {
|
|---|
| 196 | if ( text[ j ].format() )
|
|---|
| 197 | text[ j ].format()->addRef();
|
|---|
| 198 | }
|
|---|
| 199 | }
|
|---|
| 200 |
|
|---|
| 201 | QTextDeleteCommand::QTextDeleteCommand( QTextParagraph *p, int idx, const QMemArray<QTextStringChar> &str )
|
|---|
| 202 | : QTextCommand( 0 ), id( -1 ), index( idx ), parag( p ), text( str )
|
|---|
| 203 | {
|
|---|
| 204 | for ( int i = 0; i < (int)text.size(); ++i ) {
|
|---|
| 205 | if ( text[ i ].format() )
|
|---|
| 206 | text[ i ].format()->addRef();
|
|---|
| 207 | }
|
|---|
| 208 | }
|
|---|
| 209 |
|
|---|
| 210 | QTextDeleteCommand::~QTextDeleteCommand()
|
|---|
| 211 | {
|
|---|
| 212 | for ( int i = 0; i < (int)text.size(); ++i ) {
|
|---|
| 213 | if ( text[ i ].format() )
|
|---|
| 214 | text[ i ].format()->removeRef();
|
|---|
| 215 | }
|
|---|
| 216 | text.resize( 0 );
|
|---|
| 217 | }
|
|---|
| 218 |
|
|---|
| 219 | QTextCursor *QTextDeleteCommand::execute( QTextCursor *c )
|
|---|
| 220 | {
|
|---|
| 221 | QTextParagraph *s = doc ? doc->paragAt( id ) : parag;
|
|---|
| 222 | if ( !s ) {
|
|---|
| 223 | qWarning( "can't locate parag at %d, last parag: %d", id, doc->lastParagraph()->paragId() );
|
|---|
| 224 | return 0;
|
|---|
| 225 | }
|
|---|
| 226 |
|
|---|
| 227 | cursor.setParagraph( s );
|
|---|
| 228 | cursor.setIndex( index );
|
|---|
| 229 | int len = text.size();
|
|---|
| 230 | if ( c )
|
|---|
| 231 | *c = cursor;
|
|---|
| 232 | if ( doc ) {
|
|---|
| 233 | doc->setSelectionStart( QTextDocument::Temp, cursor );
|
|---|
| 234 | for ( int i = 0; i < len; ++i )
|
|---|
| 235 | cursor.gotoNextLetter();
|
|---|
| 236 | doc->setSelectionEnd( QTextDocument::Temp, cursor );
|
|---|
| 237 | doc->removeSelectedText( QTextDocument::Temp, &cursor );
|
|---|
| 238 | if ( c )
|
|---|
| 239 | *c = cursor;
|
|---|
| 240 | } else {
|
|---|
| 241 | s->remove( index, len );
|
|---|
| 242 | }
|
|---|
| 243 |
|
|---|
| 244 | return c;
|
|---|
| 245 | }
|
|---|
| 246 |
|
|---|
| 247 | QTextCursor *QTextDeleteCommand::unexecute( QTextCursor *c )
|
|---|
| 248 | {
|
|---|
| 249 | QTextParagraph *s = doc ? doc->paragAt( id ) : parag;
|
|---|
| 250 | if ( !s ) {
|
|---|
| 251 | qWarning( "can't locate parag at %d, last parag: %d", id, doc->lastParagraph()->paragId() );
|
|---|
| 252 | return 0;
|
|---|
| 253 | }
|
|---|
| 254 |
|
|---|
| 255 | cursor.setParagraph( s );
|
|---|
| 256 | cursor.setIndex( index );
|
|---|
| 257 | QString str = QTextString::toString( text );
|
|---|
| 258 | cursor.insert( str, TRUE, &text );
|
|---|
| 259 | if ( c )
|
|---|
| 260 | *c = cursor;
|
|---|
| 261 | cursor.setParagraph( s );
|
|---|
| 262 | cursor.setIndex( index );
|
|---|
| 263 |
|
|---|
| 264 | #ifndef QT_NO_DATASTREAM
|
|---|
| 265 | if ( !styleInformation.isEmpty() ) {
|
|---|
| 266 | QDataStream styleStream( styleInformation, IO_ReadOnly );
|
|---|
| 267 | int num;
|
|---|
| 268 | styleStream >> num;
|
|---|
| 269 | QTextParagraph *p = s;
|
|---|
| 270 | while ( num-- && p ) {
|
|---|
| 271 | p->readStyleInformation( styleStream );
|
|---|
| 272 | p = p->next();
|
|---|
| 273 | }
|
|---|
| 274 | }
|
|---|
| 275 | #endif
|
|---|
| 276 | s = cursor.paragraph();
|
|---|
| 277 | while ( s ) {
|
|---|
| 278 | s->format();
|
|---|
| 279 | s->setChanged( TRUE );
|
|---|
| 280 | if ( s == c->paragraph() )
|
|---|
| 281 | break;
|
|---|
| 282 | s = s->next();
|
|---|
| 283 | }
|
|---|
| 284 |
|
|---|
| 285 | return &cursor;
|
|---|
| 286 | }
|
|---|
| 287 |
|
|---|
| 288 | QTextFormatCommand::QTextFormatCommand( QTextDocument *d, int sid, int sidx, int eid, int eidx,
|
|---|
| 289 | const QMemArray<QTextStringChar> &old, QTextFormat *f, int fl )
|
|---|
| 290 | : QTextCommand( d ), startId( sid ), startIndex( sidx ), endId( eid ), endIndex( eidx ), format( f ), oldFormats( old ), flags( fl )
|
|---|
| 291 | {
|
|---|
| 292 | format = d->formatCollection()->format( f );
|
|---|
| 293 | for ( int j = 0; j < (int)oldFormats.size(); ++j ) {
|
|---|
| 294 | if ( oldFormats[ j ].format() )
|
|---|
| 295 | oldFormats[ j ].format()->addRef();
|
|---|
| 296 | }
|
|---|
| 297 | }
|
|---|
| 298 |
|
|---|
| 299 | QTextFormatCommand::~QTextFormatCommand()
|
|---|
| 300 | {
|
|---|
| 301 | format->removeRef();
|
|---|
| 302 | for ( int j = 0; j < (int)oldFormats.size(); ++j ) {
|
|---|
| 303 | if ( oldFormats[ j ].format() )
|
|---|
| 304 | oldFormats[ j ].format()->removeRef();
|
|---|
| 305 | }
|
|---|
| 306 | }
|
|---|
| 307 |
|
|---|
| 308 | QTextCursor *QTextFormatCommand::execute( QTextCursor *c )
|
|---|
| 309 | {
|
|---|
| 310 | QTextParagraph *sp = doc->paragAt( startId );
|
|---|
| 311 | QTextParagraph *ep = doc->paragAt( endId );
|
|---|
| 312 | if ( !sp || !ep )
|
|---|
| 313 | return c;
|
|---|
| 314 |
|
|---|
| 315 | QTextCursor start( doc );
|
|---|
| 316 | start.setParagraph( sp );
|
|---|
| 317 | start.setIndex( startIndex );
|
|---|
| 318 | QTextCursor end( doc );
|
|---|
| 319 | end.setParagraph( ep );
|
|---|
| 320 | end.setIndex( endIndex );
|
|---|
| 321 |
|
|---|
| 322 | doc->setSelectionStart( QTextDocument::Temp, start );
|
|---|
| 323 | doc->setSelectionEnd( QTextDocument::Temp, end );
|
|---|
| 324 | doc->setFormat( QTextDocument::Temp, format, flags );
|
|---|
| 325 | doc->removeSelection( QTextDocument::Temp );
|
|---|
| 326 | if ( endIndex == ep->length() )
|
|---|
| 327 | end.gotoLeft();
|
|---|
| 328 | *c = end;
|
|---|
| 329 | return c;
|
|---|
| 330 | }
|
|---|
| 331 |
|
|---|
| 332 | QTextCursor *QTextFormatCommand::unexecute( QTextCursor *c )
|
|---|
| 333 | {
|
|---|
| 334 | QTextParagraph *sp = doc->paragAt( startId );
|
|---|
| 335 | QTextParagraph *ep = doc->paragAt( endId );
|
|---|
| 336 | if ( !sp || !ep )
|
|---|
| 337 | return 0;
|
|---|
| 338 |
|
|---|
| 339 | int idx = startIndex;
|
|---|
| 340 | int fIndex = 0;
|
|---|
| 341 | for ( ;; ) {
|
|---|
| 342 | if ( oldFormats.at( fIndex ).c == '\n' ) {
|
|---|
| 343 | if ( idx > 0 ) {
|
|---|
| 344 | if ( idx < sp->length() && fIndex > 0 )
|
|---|
| 345 | sp->setFormat( idx, 1, oldFormats.at( fIndex - 1 ).format() );
|
|---|
| 346 | if ( sp == ep )
|
|---|
| 347 | break;
|
|---|
| 348 | sp = sp->next();
|
|---|
| 349 | idx = 0;
|
|---|
| 350 | }
|
|---|
| 351 | fIndex++;
|
|---|
| 352 | }
|
|---|
| 353 | if ( oldFormats.at( fIndex ).format() )
|
|---|
| 354 | sp->setFormat( idx, 1, oldFormats.at( fIndex ).format() );
|
|---|
| 355 | idx++;
|
|---|
| 356 | fIndex++;
|
|---|
| 357 | if ( fIndex >= (int)oldFormats.size() )
|
|---|
| 358 | break;
|
|---|
| 359 | if ( idx >= sp->length() ) {
|
|---|
| 360 | if ( sp == ep )
|
|---|
| 361 | break;
|
|---|
| 362 | sp = sp->next();
|
|---|
| 363 | idx = 0;
|
|---|
| 364 | }
|
|---|
| 365 | }
|
|---|
| 366 |
|
|---|
| 367 | QTextCursor end( doc );
|
|---|
| 368 | end.setParagraph( ep );
|
|---|
| 369 | end.setIndex( endIndex );
|
|---|
| 370 | if ( endIndex == ep->length() )
|
|---|
| 371 | end.gotoLeft();
|
|---|
| 372 | *c = end;
|
|---|
| 373 | return c;
|
|---|
| 374 | }
|
|---|
| 375 |
|
|---|
| 376 | QTextStyleCommand::QTextStyleCommand( QTextDocument *d, int fParag, int lParag, const QByteArray& beforeChange )
|
|---|
| 377 | : QTextCommand( d ), firstParag( fParag ), lastParag( lParag ), before( beforeChange )
|
|---|
| 378 | {
|
|---|
| 379 | after = readStyleInformation( d, fParag, lParag );
|
|---|
| 380 | }
|
|---|
| 381 |
|
|---|
| 382 |
|
|---|
| 383 | QByteArray QTextStyleCommand::readStyleInformation( QTextDocument* doc, int fParag, int lParag )
|
|---|
| 384 | {
|
|---|
| 385 | QByteArray style;
|
|---|
| 386 | #ifndef QT_NO_DATASTREAM
|
|---|
| 387 | QTextParagraph *p = doc->paragAt( fParag );
|
|---|
| 388 | if ( !p )
|
|---|
| 389 | return style;
|
|---|
| 390 | QDataStream styleStream( style, IO_WriteOnly );
|
|---|
| 391 | int num = lParag - fParag + 1;
|
|---|
| 392 | styleStream << num;
|
|---|
| 393 | while ( num -- && p ) {
|
|---|
| 394 | p->writeStyleInformation( styleStream );
|
|---|
| 395 | p = p->next();
|
|---|
| 396 | }
|
|---|
| 397 | #endif
|
|---|
| 398 | return style;
|
|---|
| 399 | }
|
|---|
| 400 |
|
|---|
| 401 | void QTextStyleCommand::writeStyleInformation( QTextDocument* doc, int fParag, const QByteArray& style )
|
|---|
| 402 | {
|
|---|
| 403 | #ifndef QT_NO_DATASTREAM
|
|---|
| 404 | QTextParagraph *p = doc->paragAt( fParag );
|
|---|
| 405 | if ( !p )
|
|---|
| 406 | return;
|
|---|
| 407 | QDataStream styleStream( style, IO_ReadOnly );
|
|---|
| 408 | int num;
|
|---|
| 409 | styleStream >> num;
|
|---|
| 410 | while ( num-- && p ) {
|
|---|
| 411 | p->readStyleInformation( styleStream );
|
|---|
| 412 | p = p->next();
|
|---|
| 413 | }
|
|---|
| 414 | #endif
|
|---|
| 415 | }
|
|---|
| 416 |
|
|---|
| 417 | QTextCursor *QTextStyleCommand::execute( QTextCursor *c )
|
|---|
| 418 | {
|
|---|
| 419 | writeStyleInformation( doc, firstParag, after );
|
|---|
| 420 | return c;
|
|---|
| 421 | }
|
|---|
| 422 |
|
|---|
| 423 | QTextCursor *QTextStyleCommand::unexecute( QTextCursor *c )
|
|---|
| 424 | {
|
|---|
| 425 | writeStyleInformation( doc, firstParag, before );
|
|---|
| 426 | return c;
|
|---|
| 427 | }
|
|---|
| 428 |
|
|---|
| 429 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 430 |
|
|---|
| 431 | QTextCursor::QTextCursor( QTextDocument *d )
|
|---|
| 432 | : idx( 0 ), tmpX( -1 ), ox( 0 ), oy( 0 ),
|
|---|
| 433 | valid( TRUE )
|
|---|
| 434 | {
|
|---|
| 435 | para = d ? d->firstParagraph() : 0;
|
|---|
| 436 | }
|
|---|
| 437 |
|
|---|
| 438 | QTextCursor::QTextCursor( const QTextCursor &c )
|
|---|
| 439 | {
|
|---|
| 440 | ox = c.ox;
|
|---|
| 441 | oy = c.oy;
|
|---|
| 442 | idx = c.idx;
|
|---|
| 443 | para = c.para;
|
|---|
| 444 | tmpX = c.tmpX;
|
|---|
| 445 | indices = c.indices;
|
|---|
| 446 | paras = c.paras;
|
|---|
| 447 | xOffsets = c.xOffsets;
|
|---|
| 448 | yOffsets = c.yOffsets;
|
|---|
| 449 | valid = c.valid;
|
|---|
| 450 | }
|
|---|
| 451 |
|
|---|
| 452 | QTextCursor &QTextCursor::operator=( const QTextCursor &c )
|
|---|
| 453 | {
|
|---|
| 454 | ox = c.ox;
|
|---|
| 455 | oy = c.oy;
|
|---|
| 456 | idx = c.idx;
|
|---|
| 457 | para = c.para;
|
|---|
| 458 | tmpX = c.tmpX;
|
|---|
| 459 | indices = c.indices;
|
|---|
| 460 | paras = c.paras;
|
|---|
| 461 | xOffsets = c.xOffsets;
|
|---|
| 462 | yOffsets = c.yOffsets;
|
|---|
| 463 | valid = c.valid;
|
|---|
| 464 |
|
|---|
| 465 | return *this;
|
|---|
| 466 | }
|
|---|
| 467 |
|
|---|
| 468 | bool QTextCursor::operator==( const QTextCursor &c ) const
|
|---|
| 469 | {
|
|---|
| 470 | return para == c.para && idx == c.idx;
|
|---|
| 471 | }
|
|---|
| 472 |
|
|---|
| 473 | int QTextCursor::totalOffsetX() const
|
|---|
| 474 | {
|
|---|
| 475 | int xoff = ox;
|
|---|
| 476 | for ( QValueStack<int>::ConstIterator xit = xOffsets.begin(); xit != xOffsets.end(); ++xit )
|
|---|
| 477 | xoff += *xit;
|
|---|
| 478 | return xoff;
|
|---|
| 479 | }
|
|---|
| 480 |
|
|---|
| 481 | int QTextCursor::totalOffsetY() const
|
|---|
| 482 | {
|
|---|
| 483 | int yoff = oy;
|
|---|
| 484 | for ( QValueStack<int>::ConstIterator yit = yOffsets.begin(); yit != yOffsets.end(); ++yit )
|
|---|
| 485 | yoff += *yit;
|
|---|
| 486 | return yoff;
|
|---|
| 487 | }
|
|---|
| 488 |
|
|---|
| 489 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 490 | void QTextCursor::gotoIntoNested( const QPoint &globalPos )
|
|---|
| 491 | {
|
|---|
| 492 | if ( !para )
|
|---|
| 493 | return;
|
|---|
| 494 | Q_ASSERT( para->at( idx )->isCustom() );
|
|---|
| 495 | push();
|
|---|
| 496 | ox = 0;
|
|---|
| 497 | int bl, y;
|
|---|
| 498 | para->lineHeightOfChar( idx, &bl, &y );
|
|---|
| 499 | oy = y + para->rect().y();
|
|---|
| 500 | ox = para->at( idx )->x;
|
|---|
| 501 | QTextDocument* doc = document();
|
|---|
| 502 | para->at( idx )->customItem()->enterAt( this, doc, para, idx, ox, oy, globalPos-QPoint(ox,oy) );
|
|---|
| 503 | }
|
|---|
| 504 | #endif
|
|---|
| 505 |
|
|---|
| 506 | void QTextCursor::invalidateNested()
|
|---|
| 507 | {
|
|---|
| 508 | if ( nestedDepth() ) {
|
|---|
| 509 | QValueStack<QTextParagraph*>::Iterator it = paras.begin();
|
|---|
| 510 | QValueStack<int>::Iterator it2 = indices.begin();
|
|---|
| 511 | for ( ; it != paras.end(); ++it, ++it2 ) {
|
|---|
| 512 | if ( *it == para )
|
|---|
| 513 | continue;
|
|---|
| 514 | (*it)->invalidate( 0 );
|
|---|
| 515 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 516 | if ( (*it)->at( *it2 )->isCustom() )
|
|---|
| 517 | (*it)->at( *it2 )->customItem()->invalidate();
|
|---|
| 518 | #endif
|
|---|
| 519 | }
|
|---|
| 520 | }
|
|---|
| 521 | }
|
|---|
| 522 |
|
|---|
| 523 | void QTextCursor::insert( const QString &str, bool checkNewLine, QMemArray<QTextStringChar> *formatting )
|
|---|
| 524 | {
|
|---|
| 525 | tmpX = -1;
|
|---|
| 526 | bool justInsert = TRUE;
|
|---|
| 527 | QString s( str );
|
|---|
| 528 | #if defined(Q_WS_WIN) || defined(Q_WS_PM)
|
|---|
| 529 | if ( checkNewLine ) {
|
|---|
| 530 | int i = 0;
|
|---|
| 531 | while ( ( i = s.find( '\r', i ) ) != -1 )
|
|---|
| 532 | s.remove( i ,1 );
|
|---|
| 533 | }
|
|---|
| 534 | #endif
|
|---|
| 535 | if ( checkNewLine )
|
|---|
| 536 | justInsert = s.find( '\n' ) == -1;
|
|---|
| 537 | if ( justInsert ) { // we ignore new lines and insert all in the current para at the current index
|
|---|
| 538 | para->insert( idx, s.unicode(), s.length() );
|
|---|
| 539 | if ( formatting ) {
|
|---|
| 540 | for ( int i = 0; i < (int)s.length(); ++i ) {
|
|---|
| 541 | if ( formatting->at( i ).format() ) {
|
|---|
| 542 | formatting->at( i ).format()->addRef();
|
|---|
| 543 | para->string()->setFormat( idx + i, formatting->at( i ).format(), TRUE );
|
|---|
| 544 | }
|
|---|
| 545 | }
|
|---|
| 546 | }
|
|---|
| 547 | idx += s.length();
|
|---|
| 548 | } else { // we split at new lines
|
|---|
| 549 | int start = -1;
|
|---|
| 550 | int end;
|
|---|
| 551 | int y = para->rect().y() + para->rect().height();
|
|---|
| 552 | int lastIndex = 0;
|
|---|
| 553 | do {
|
|---|
| 554 | end = s.find( '\n', start + 1 ); // find line break
|
|---|
| 555 | if ( end == -1 ) // didn't find one, so end of line is end of string
|
|---|
| 556 | end = s.length();
|
|---|
| 557 | int len = (start == -1 ? end : end - start - 1);
|
|---|
| 558 | if ( len > 0 ) // insert the line
|
|---|
| 559 | para->insert( idx, s.unicode() + start + 1, len );
|
|---|
| 560 | else
|
|---|
| 561 | para->invalidate( 0 );
|
|---|
| 562 | if ( formatting ) { // set formats to the chars of the line
|
|---|
| 563 | for ( int i = 0; i < len; ++i ) {
|
|---|
| 564 | if ( formatting->at( i + lastIndex ).format() ) {
|
|---|
| 565 | formatting->at( i + lastIndex ).format()->addRef();
|
|---|
| 566 | para->string()->setFormat( i + idx, formatting->at( i + lastIndex ).format(), TRUE );
|
|---|
| 567 | }
|
|---|
| 568 | }
|
|---|
| 569 | lastIndex += len;
|
|---|
| 570 | }
|
|---|
| 571 | start = end; // next start is at the end of this line
|
|---|
| 572 | idx += len; // increase the index of the cursor to the end of the inserted text
|
|---|
| 573 | if ( s[end] == '\n' ) { // if at the end was a line break, break the line
|
|---|
| 574 | splitAndInsertEmptyParagraph( FALSE, TRUE );
|
|---|
| 575 | para->setEndState( -1 );
|
|---|
| 576 | para->prev()->format( -1, FALSE );
|
|---|
| 577 | lastIndex++;
|
|---|
| 578 | }
|
|---|
| 579 |
|
|---|
| 580 | } while ( end < (int)s.length() );
|
|---|
| 581 |
|
|---|
| 582 | para->format( -1, FALSE );
|
|---|
| 583 | int dy = para->rect().y() + para->rect().height() - y;
|
|---|
| 584 | QTextParagraph *p = para;
|
|---|
| 585 | p->setParagId( p->prev() ? p->prev()->paragId() + 1 : 0 );
|
|---|
| 586 | p = p->next();
|
|---|
| 587 | while ( p ) {
|
|---|
| 588 | p->setParagId( p->prev()->paragId() + 1 );
|
|---|
| 589 | p->move( dy );
|
|---|
| 590 | p->invalidate( 0 );
|
|---|
| 591 | p->setEndState( -1 );
|
|---|
| 592 | p = p->next();
|
|---|
| 593 | }
|
|---|
| 594 | }
|
|---|
| 595 |
|
|---|
| 596 | int h = para->rect().height();
|
|---|
| 597 | para->format( -1, TRUE );
|
|---|
| 598 | if ( h != para->rect().height() )
|
|---|
| 599 | invalidateNested();
|
|---|
| 600 | else if ( para->document() && para->document()->parent() )
|
|---|
| 601 | para->document()->nextDoubleBuffered = TRUE;
|
|---|
| 602 |
|
|---|
| 603 | fixCursorPosition();
|
|---|
| 604 | }
|
|---|
| 605 |
|
|---|
| 606 | void QTextCursor::gotoLeft()
|
|---|
| 607 | {
|
|---|
| 608 | if ( para->string()->isRightToLeft() )
|
|---|
| 609 | gotoNextLetter();
|
|---|
| 610 | else
|
|---|
| 611 | gotoPreviousLetter();
|
|---|
| 612 | }
|
|---|
| 613 |
|
|---|
| 614 | void QTextCursor::gotoPreviousLetter()
|
|---|
| 615 | {
|
|---|
| 616 | tmpX = -1;
|
|---|
| 617 |
|
|---|
| 618 | if ( idx > 0 ) {
|
|---|
| 619 | idx = para->string()->previousCursorPosition( idx );
|
|---|
| 620 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 621 | const QTextStringChar *tsc = para->at( idx );
|
|---|
| 622 | if ( tsc && tsc->isCustom() && tsc->customItem()->isNested() )
|
|---|
| 623 | processNesting( EnterEnd );
|
|---|
| 624 | #endif
|
|---|
| 625 | } else if ( para->prev() ) {
|
|---|
| 626 | para = para->prev();
|
|---|
| 627 | while ( !para->isVisible() && para->prev() )
|
|---|
| 628 | para = para->prev();
|
|---|
| 629 | idx = para->length() - 1;
|
|---|
| 630 | } else if ( nestedDepth() ) {
|
|---|
| 631 | pop();
|
|---|
| 632 | processNesting( Prev );
|
|---|
| 633 | if ( idx == -1 ) {
|
|---|
| 634 | pop();
|
|---|
| 635 | if ( idx > 0 ) {
|
|---|
| 636 | idx = para->string()->previousCursorPosition( idx );
|
|---|
| 637 | } else if ( para->prev() ) {
|
|---|
| 638 | para = para->prev();
|
|---|
| 639 | idx = para->length() - 1;
|
|---|
| 640 | }
|
|---|
| 641 | }
|
|---|
| 642 | }
|
|---|
| 643 | }
|
|---|
| 644 |
|
|---|
| 645 | void QTextCursor::push()
|
|---|
| 646 | {
|
|---|
| 647 | indices.push( idx );
|
|---|
| 648 | paras.push( para );
|
|---|
| 649 | xOffsets.push( ox );
|
|---|
| 650 | yOffsets.push( oy );
|
|---|
| 651 | }
|
|---|
| 652 |
|
|---|
| 653 | void QTextCursor::pop()
|
|---|
| 654 | {
|
|---|
| 655 | if ( indices.isEmpty() )
|
|---|
| 656 | return;
|
|---|
| 657 | idx = indices.pop();
|
|---|
| 658 | para = paras.pop();
|
|---|
| 659 | ox = xOffsets.pop();
|
|---|
| 660 | oy = yOffsets.pop();
|
|---|
| 661 | }
|
|---|
| 662 |
|
|---|
| 663 | void QTextCursor::restoreState()
|
|---|
| 664 | {
|
|---|
| 665 | while ( !indices.isEmpty() )
|
|---|
| 666 | pop();
|
|---|
| 667 | }
|
|---|
| 668 |
|
|---|
| 669 | bool QTextCursor::place( const QPoint &p, QTextParagraph *s, bool link )
|
|---|
| 670 | {
|
|---|
| 671 | QPoint pos( p );
|
|---|
| 672 | QRect r;
|
|---|
| 673 | QTextParagraph *str = s;
|
|---|
| 674 | if ( pos.y() < s->rect().y() ) {
|
|---|
| 675 | pos.setY( s->rect().y() );
|
|---|
| 676 | #ifdef Q_WS_MACX
|
|---|
| 677 | pos.setX( s->rect().x() );
|
|---|
| 678 | #endif
|
|---|
| 679 | }
|
|---|
| 680 | while ( s ) {
|
|---|
| 681 | r = s->rect();
|
|---|
| 682 | r.setWidth( document() ? document()->width() : QWIDGETSIZE_MAX );
|
|---|
| 683 | if ( s->isVisible() )
|
|---|
| 684 | str = s;
|
|---|
| 685 | if ( pos.y() >= r.y() && pos.y() <= r.y() + r.height() )
|
|---|
| 686 | break;
|
|---|
| 687 | if ( !s->next() ) {
|
|---|
| 688 | #ifdef Q_WS_MACX
|
|---|
| 689 | pos.setX( s->rect().x() + s->rect().width() );
|
|---|
| 690 | #endif
|
|---|
| 691 | break;
|
|---|
| 692 | }
|
|---|
| 693 | s = s->next();
|
|---|
| 694 | }
|
|---|
| 695 |
|
|---|
| 696 | if ( !s || !str )
|
|---|
| 697 | return FALSE;
|
|---|
| 698 |
|
|---|
| 699 | s = str;
|
|---|
| 700 |
|
|---|
| 701 | setParagraph( s );
|
|---|
| 702 | int y = s->rect().y();
|
|---|
| 703 | int lines = s->lines();
|
|---|
| 704 | QTextStringChar *chr = 0;
|
|---|
| 705 | int index = 0;
|
|---|
| 706 | int i = 0;
|
|---|
| 707 | int cy = 0;
|
|---|
| 708 | int ch = 0;
|
|---|
| 709 | for ( ; i < lines; ++i ) {
|
|---|
| 710 | chr = s->lineStartOfLine( i, &index );
|
|---|
| 711 | cy = s->lineY( i );
|
|---|
| 712 | ch = s->lineHeight( i );
|
|---|
| 713 | if ( !chr )
|
|---|
| 714 | return FALSE;
|
|---|
| 715 | if ( pos.y() <= y + cy + ch )
|
|---|
| 716 | break;
|
|---|
| 717 | }
|
|---|
| 718 | int nextLine;
|
|---|
| 719 | if ( i < lines - 1 )
|
|---|
| 720 | s->lineStartOfLine( i+1, &nextLine );
|
|---|
| 721 | else
|
|---|
| 722 | nextLine = s->length();
|
|---|
| 723 | i = index;
|
|---|
| 724 | int x = s->rect().x();
|
|---|
| 725 | if ( pos.x() < x )
|
|---|
| 726 | pos.setX( x + 1 );
|
|---|
| 727 | int cw;
|
|---|
| 728 | int curpos = s->length()-1;
|
|---|
| 729 | int dist = 10000000;
|
|---|
| 730 | bool inCustom = FALSE;
|
|---|
| 731 | while ( i < nextLine ) {
|
|---|
| 732 | chr = s->at(i);
|
|---|
| 733 | int cpos = x + chr->x;
|
|---|
| 734 | cw = s->string()->width( i );
|
|---|
| 735 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 736 | if ( chr->isCustom() && chr->customItem()->isNested() ) {
|
|---|
| 737 | if ( pos.x() >= cpos && pos.x() <= cpos + cw &&
|
|---|
| 738 | pos.y() >= y + cy && pos.y() <= y + cy + chr->height() ) {
|
|---|
| 739 | inCustom = TRUE;
|
|---|
| 740 | curpos = i;
|
|---|
| 741 | break;
|
|---|
| 742 | }
|
|---|
| 743 | } else
|
|---|
| 744 | #endif
|
|---|
| 745 | {
|
|---|
| 746 | if( chr->rightToLeft )
|
|---|
| 747 | cpos += cw;
|
|---|
| 748 | int d = cpos - pos.x();
|
|---|
| 749 | bool dm = d < 0 ? !chr->rightToLeft : chr->rightToLeft;
|
|---|
| 750 | if ( (QABS( d ) < dist || (dist == d && dm == TRUE )) && para->string()->validCursorPosition( i ) ) {
|
|---|
| 751 | dist = QABS( d );
|
|---|
| 752 | if ( !link || pos.x() >= x + chr->x )
|
|---|
| 753 | curpos = i;
|
|---|
| 754 | }
|
|---|
| 755 | }
|
|---|
| 756 | i++;
|
|---|
| 757 | }
|
|---|
| 758 | setIndex( curpos );
|
|---|
| 759 |
|
|---|
| 760 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 761 | if ( inCustom && para->document() && para->at( curpos )->isCustom() && para->at( curpos )->customItem()->isNested() ) {
|
|---|
| 762 | QTextDocument *oldDoc = para->document();
|
|---|
| 763 | gotoIntoNested( pos );
|
|---|
| 764 | if ( oldDoc == para->document() )
|
|---|
| 765 | return TRUE;
|
|---|
| 766 | QPoint p( pos.x() - offsetX(), pos.y() - offsetY() );
|
|---|
| 767 | if ( !place( p, document()->firstParagraph(), link ) )
|
|---|
| 768 | pop();
|
|---|
| 769 | }
|
|---|
| 770 | #endif
|
|---|
| 771 | return TRUE;
|
|---|
| 772 | }
|
|---|
| 773 |
|
|---|
| 774 | bool QTextCursor::processNesting( Operation op )
|
|---|
| 775 | {
|
|---|
| 776 | if ( !para->document() )
|
|---|
| 777 | return FALSE;
|
|---|
| 778 | QTextDocument* doc = para->document();
|
|---|
| 779 | push();
|
|---|
| 780 | ox = para->at( idx )->x;
|
|---|
| 781 | int bl, y;
|
|---|
| 782 | para->lineHeightOfChar( idx, &bl, &y );
|
|---|
| 783 | oy = y + para->rect().y();
|
|---|
| 784 | bool ok = FALSE;
|
|---|
| 785 |
|
|---|
| 786 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 787 | switch ( op ) {
|
|---|
| 788 | case EnterBegin:
|
|---|
| 789 | ok = para->at( idx )->customItem()->enter( this, doc, para, idx, ox, oy );
|
|---|
| 790 | break;
|
|---|
| 791 | case EnterEnd:
|
|---|
| 792 | ok = para->at( idx )->customItem()->enter( this, doc, para, idx, ox, oy, TRUE );
|
|---|
| 793 | break;
|
|---|
| 794 | case Next:
|
|---|
| 795 | ok = para->at( idx )->customItem()->next( this, doc, para, idx, ox, oy );
|
|---|
| 796 | break;
|
|---|
| 797 | case Prev:
|
|---|
| 798 | ok = para->at( idx )->customItem()->prev( this, doc, para, idx, ox, oy );
|
|---|
| 799 | break;
|
|---|
| 800 | case Down:
|
|---|
| 801 | ok = para->at( idx )->customItem()->down( this, doc, para, idx, ox, oy );
|
|---|
| 802 | break;
|
|---|
| 803 | case Up:
|
|---|
| 804 | ok = para->at( idx )->customItem()->up( this, doc, para, idx, ox, oy );
|
|---|
| 805 | break;
|
|---|
| 806 | }
|
|---|
| 807 | if ( !ok )
|
|---|
| 808 | #endif
|
|---|
| 809 | pop();
|
|---|
| 810 | return ok;
|
|---|
| 811 | }
|
|---|
| 812 |
|
|---|
| 813 | void QTextCursor::gotoRight()
|
|---|
| 814 | {
|
|---|
| 815 | if ( para->string()->isRightToLeft() )
|
|---|
| 816 | gotoPreviousLetter();
|
|---|
| 817 | else
|
|---|
| 818 | gotoNextLetter();
|
|---|
| 819 | }
|
|---|
| 820 |
|
|---|
| 821 | void QTextCursor::gotoNextLetter()
|
|---|
| 822 | {
|
|---|
| 823 | tmpX = -1;
|
|---|
| 824 |
|
|---|
| 825 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 826 | const QTextStringChar *tsc = para->at( idx );
|
|---|
| 827 | if ( tsc && tsc->isCustom() && tsc->customItem()->isNested() ) {
|
|---|
| 828 | if ( processNesting( EnterBegin ) )
|
|---|
| 829 | return;
|
|---|
| 830 | }
|
|---|
| 831 | #endif
|
|---|
| 832 |
|
|---|
| 833 | if ( idx < para->length() - 1 ) {
|
|---|
| 834 | idx = para->string()->nextCursorPosition( idx );
|
|---|
| 835 | } else if ( para->next() ) {
|
|---|
| 836 | para = para->next();
|
|---|
| 837 | while ( !para->isVisible() && para->next() )
|
|---|
| 838 | para = para->next();
|
|---|
| 839 | idx = 0;
|
|---|
| 840 | } else if ( nestedDepth() ) {
|
|---|
| 841 | pop();
|
|---|
| 842 | processNesting( Next );
|
|---|
| 843 | if ( idx == -1 ) {
|
|---|
| 844 | pop();
|
|---|
| 845 | if ( idx < para->length() - 1 ) {
|
|---|
| 846 | idx = para->string()->nextCursorPosition( idx );
|
|---|
| 847 | } else if ( para->next() ) {
|
|---|
| 848 | para = para->next();
|
|---|
| 849 | idx = 0;
|
|---|
| 850 | }
|
|---|
| 851 | }
|
|---|
| 852 | }
|
|---|
| 853 | }
|
|---|
| 854 |
|
|---|
| 855 | void QTextCursor::gotoUp()
|
|---|
| 856 | {
|
|---|
| 857 | int indexOfLineStart;
|
|---|
| 858 | int line;
|
|---|
| 859 | QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
|
|---|
| 860 | if ( !c )
|
|---|
| 861 | return;
|
|---|
| 862 |
|
|---|
| 863 | if (tmpX < 0)
|
|---|
| 864 | tmpX = x();
|
|---|
| 865 |
|
|---|
| 866 | if ( indexOfLineStart == 0 ) {
|
|---|
| 867 | if ( !para->prev() ) {
|
|---|
| 868 | if ( !nestedDepth() )
|
|---|
| 869 | return;
|
|---|
| 870 | pop();
|
|---|
| 871 | processNesting( Up );
|
|---|
| 872 | if ( idx == -1 ) {
|
|---|
| 873 | pop();
|
|---|
| 874 | if ( !para->prev() )
|
|---|
| 875 | return;
|
|---|
| 876 | idx = tmpX = 0;
|
|---|
| 877 | } else {
|
|---|
| 878 | tmpX = -1;
|
|---|
| 879 | return;
|
|---|
| 880 | }
|
|---|
| 881 | }
|
|---|
| 882 | QTextParagraph *p = para->prev();
|
|---|
| 883 | while ( p && !p->isVisible() )
|
|---|
| 884 | p = p->prev();
|
|---|
| 885 | if ( p )
|
|---|
| 886 | para = p;
|
|---|
| 887 | int lastLine = para->lines() - 1;
|
|---|
| 888 | if ( !para->lineStartOfLine( lastLine, &indexOfLineStart ) )
|
|---|
| 889 | return;
|
|---|
| 890 | idx = indexOfLineStart;
|
|---|
| 891 | while (idx < para->length()-1 && para->at(idx)->x < tmpX)
|
|---|
| 892 | ++idx;
|
|---|
| 893 | if (idx > indexOfLineStart &&
|
|---|
| 894 | para->at(idx)->x - tmpX > tmpX - para->at(idx-1)->x)
|
|---|
| 895 | --idx;
|
|---|
| 896 | } else {
|
|---|
| 897 | --line;
|
|---|
| 898 | int oldIndexOfLineStart = indexOfLineStart;
|
|---|
| 899 | if ( !para->lineStartOfLine( line, &indexOfLineStart ) )
|
|---|
| 900 | return;
|
|---|
| 901 | idx = indexOfLineStart;
|
|---|
| 902 | while (idx < oldIndexOfLineStart-1 && para->at(idx)->x < tmpX)
|
|---|
| 903 | ++idx;
|
|---|
| 904 | if (idx > indexOfLineStart &&
|
|---|
| 905 | para->at(idx)->x - tmpX > tmpX - para->at(idx-1)->x)
|
|---|
| 906 | --idx;
|
|---|
| 907 | }
|
|---|
| 908 | fixCursorPosition();
|
|---|
| 909 | }
|
|---|
| 910 |
|
|---|
| 911 | void QTextCursor::gotoDown()
|
|---|
| 912 | {
|
|---|
| 913 | int indexOfLineStart;
|
|---|
| 914 | int line;
|
|---|
| 915 | QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
|
|---|
| 916 | if ( !c )
|
|---|
| 917 | return;
|
|---|
| 918 |
|
|---|
| 919 | if (tmpX < 0)
|
|---|
| 920 | tmpX = x();
|
|---|
| 921 | if ( line == para->lines() - 1 ) {
|
|---|
| 922 | if ( !para->next() ) {
|
|---|
| 923 | if ( !nestedDepth() )
|
|---|
| 924 | return;
|
|---|
| 925 | pop();
|
|---|
| 926 | processNesting( Down );
|
|---|
| 927 | if ( idx == -1 ) {
|
|---|
| 928 | pop();
|
|---|
| 929 | if ( !para->next() )
|
|---|
| 930 | return;
|
|---|
| 931 | idx = tmpX = 0;
|
|---|
| 932 | } else {
|
|---|
| 933 | tmpX = -1;
|
|---|
| 934 | return;
|
|---|
| 935 | }
|
|---|
| 936 | }
|
|---|
| 937 | QTextParagraph *s = para->next();
|
|---|
| 938 | while ( s && !s->isVisible() )
|
|---|
| 939 | s = s->next();
|
|---|
| 940 | if ( s )
|
|---|
| 941 | para = s;
|
|---|
| 942 | if ( !para->lineStartOfLine( 0, &indexOfLineStart ) )
|
|---|
| 943 | return;
|
|---|
| 944 | int end;
|
|---|
| 945 | if ( para->lines() == 1 )
|
|---|
| 946 | end = para->length();
|
|---|
| 947 | else
|
|---|
| 948 | para->lineStartOfLine( 1, &end );
|
|---|
| 949 |
|
|---|
| 950 | idx = indexOfLineStart;
|
|---|
| 951 | while (idx < end-1 && para->at(idx)->x < tmpX)
|
|---|
| 952 | ++idx;
|
|---|
| 953 | if (idx > indexOfLineStart &&
|
|---|
| 954 | para->at(idx)->x - tmpX > tmpX - para->at(idx-1)->x)
|
|---|
| 955 | --idx;
|
|---|
| 956 | } else {
|
|---|
| 957 | ++line;
|
|---|
| 958 | int end;
|
|---|
| 959 | if ( line == para->lines() - 1 )
|
|---|
| 960 | end = para->length();
|
|---|
| 961 | else
|
|---|
| 962 | para->lineStartOfLine( line + 1, &end );
|
|---|
| 963 | if ( !para->lineStartOfLine( line, &indexOfLineStart ) )
|
|---|
| 964 | return;
|
|---|
| 965 | idx = indexOfLineStart;
|
|---|
| 966 | while (idx < end-1 && para->at(idx)->x < tmpX)
|
|---|
| 967 | ++idx;
|
|---|
| 968 | if (idx > indexOfLineStart &&
|
|---|
| 969 | para->at(idx)->x - tmpX > tmpX - para->at(idx-1)->x)
|
|---|
| 970 | --idx;
|
|---|
| 971 | }
|
|---|
| 972 | fixCursorPosition();
|
|---|
| 973 | }
|
|---|
| 974 |
|
|---|
| 975 | void QTextCursor::gotoLineEnd()
|
|---|
| 976 | {
|
|---|
| 977 | tmpX = -1;
|
|---|
| 978 | int indexOfLineStart;
|
|---|
| 979 | int line;
|
|---|
| 980 | QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
|
|---|
| 981 | if ( !c )
|
|---|
| 982 | return;
|
|---|
| 983 |
|
|---|
| 984 | if ( line == para->lines() - 1 ) {
|
|---|
| 985 | idx = para->length() - 1;
|
|---|
| 986 | } else {
|
|---|
| 987 | c = para->lineStartOfLine( ++line, &indexOfLineStart );
|
|---|
| 988 | indexOfLineStart--;
|
|---|
| 989 | idx = indexOfLineStart;
|
|---|
| 990 | }
|
|---|
| 991 | }
|
|---|
| 992 |
|
|---|
| 993 | void QTextCursor::gotoLineStart()
|
|---|
| 994 | {
|
|---|
| 995 | tmpX = -1;
|
|---|
| 996 | int indexOfLineStart;
|
|---|
| 997 | int line;
|
|---|
| 998 | QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
|
|---|
| 999 | if ( !c )
|
|---|
| 1000 | return;
|
|---|
| 1001 |
|
|---|
| 1002 | idx = indexOfLineStart;
|
|---|
| 1003 | }
|
|---|
| 1004 |
|
|---|
| 1005 | void QTextCursor::gotoHome()
|
|---|
| 1006 | {
|
|---|
| 1007 | if ( topParagraph()->document() )
|
|---|
| 1008 | gotoPosition( topParagraph()->document()->firstParagraph() );
|
|---|
| 1009 | else
|
|---|
| 1010 | gotoLineStart();
|
|---|
| 1011 | }
|
|---|
| 1012 |
|
|---|
| 1013 | void QTextCursor::gotoEnd()
|
|---|
| 1014 | {
|
|---|
| 1015 | if ( topParagraph()->document() && topParagraph()->document()->lastParagraph()->isValid() )
|
|---|
| 1016 | gotoPosition( topParagraph()->document()->lastParagraph(),
|
|---|
| 1017 | topParagraph()->document()->lastParagraph()->length() - 1);
|
|---|
| 1018 | else
|
|---|
| 1019 | gotoLineEnd();
|
|---|
| 1020 | }
|
|---|
| 1021 |
|
|---|
| 1022 | void QTextCursor::gotoPageUp( int visibleHeight )
|
|---|
| 1023 | {
|
|---|
| 1024 | int targetY = globalY() - visibleHeight;
|
|---|
| 1025 | QTextParagraph* old; int index;
|
|---|
| 1026 | do {
|
|---|
| 1027 | old = para; index = idx;
|
|---|
| 1028 | gotoUp();
|
|---|
| 1029 | } while ( (old != para || index != idx) && globalY() > targetY );
|
|---|
| 1030 | }
|
|---|
| 1031 |
|
|---|
| 1032 | void QTextCursor::gotoPageDown( int visibleHeight )
|
|---|
| 1033 | {
|
|---|
| 1034 | int targetY = globalY() + visibleHeight;
|
|---|
| 1035 | QTextParagraph* old; int index;
|
|---|
| 1036 | do {
|
|---|
| 1037 | old = para; index = idx;
|
|---|
| 1038 | gotoDown();
|
|---|
| 1039 | } while ( (old != para || index != idx) && globalY() < targetY );
|
|---|
| 1040 | }
|
|---|
| 1041 |
|
|---|
| 1042 | void QTextCursor::gotoWordRight()
|
|---|
| 1043 | {
|
|---|
| 1044 | if ( para->string()->isRightToLeft() )
|
|---|
| 1045 | gotoPreviousWord();
|
|---|
| 1046 | else
|
|---|
| 1047 | gotoNextWord();
|
|---|
| 1048 | }
|
|---|
| 1049 |
|
|---|
| 1050 | void QTextCursor::gotoWordLeft()
|
|---|
| 1051 | {
|
|---|
| 1052 | if ( para->string()->isRightToLeft() )
|
|---|
| 1053 | gotoNextWord();
|
|---|
| 1054 | else
|
|---|
| 1055 | gotoPreviousWord();
|
|---|
| 1056 | }
|
|---|
| 1057 |
|
|---|
| 1058 | static bool is_seperator( const QChar &c, bool onlySpace )
|
|---|
| 1059 | {
|
|---|
| 1060 | if ( onlySpace )
|
|---|
| 1061 | return c.isSpace();
|
|---|
| 1062 | return c.isSpace() ||
|
|---|
| 1063 | c == '\t' ||
|
|---|
| 1064 | c == '.' ||
|
|---|
| 1065 | c == ',' ||
|
|---|
| 1066 | c == ':' ||
|
|---|
| 1067 | c == ';' ||
|
|---|
| 1068 | c == '-' ||
|
|---|
| 1069 | c == '<' ||
|
|---|
| 1070 | c == '>' ||
|
|---|
| 1071 | c == '[' ||
|
|---|
| 1072 | c == ']' ||
|
|---|
| 1073 | c == '(' ||
|
|---|
| 1074 | c == ')' ||
|
|---|
| 1075 | c == '{' ||
|
|---|
| 1076 | c == '}';
|
|---|
| 1077 | }
|
|---|
| 1078 |
|
|---|
| 1079 | void QTextCursor::gotoPreviousWord( bool onlySpace )
|
|---|
| 1080 | {
|
|---|
| 1081 | gotoPreviousLetter();
|
|---|
| 1082 | tmpX = -1;
|
|---|
| 1083 | QTextString *s = para->string();
|
|---|
| 1084 | bool allowSame = FALSE;
|
|---|
| 1085 | if ( idx == ((int)s->length()-1) )
|
|---|
| 1086 | return;
|
|---|
| 1087 | for ( int i = idx; i >= 0; --i ) {
|
|---|
| 1088 | if ( is_seperator( s->at( i ).c, onlySpace ) ) {
|
|---|
| 1089 | if ( !allowSame )
|
|---|
| 1090 | continue;
|
|---|
| 1091 | idx = i + 1;
|
|---|
| 1092 | return;
|
|---|
| 1093 | }
|
|---|
| 1094 | if ( !allowSame && !is_seperator( s->at( i ).c, onlySpace ) )
|
|---|
| 1095 | allowSame = TRUE;
|
|---|
| 1096 | }
|
|---|
| 1097 | idx = 0;
|
|---|
| 1098 | }
|
|---|
| 1099 |
|
|---|
| 1100 | void QTextCursor::gotoNextWord( bool onlySpace )
|
|---|
| 1101 | {
|
|---|
| 1102 | tmpX = -1;
|
|---|
| 1103 | QTextString *s = para->string();
|
|---|
| 1104 | bool allowSame = FALSE;
|
|---|
| 1105 | for ( int i = idx; i < (int)s->length(); ++i ) {
|
|---|
| 1106 | if ( !is_seperator( s->at( i ).c, onlySpace ) ) {
|
|---|
| 1107 | if ( !allowSame )
|
|---|
| 1108 | continue;
|
|---|
| 1109 | idx = i;
|
|---|
| 1110 | return;
|
|---|
| 1111 | }
|
|---|
| 1112 | if ( !allowSame && is_seperator( s->at( i ).c, onlySpace ) )
|
|---|
| 1113 | allowSame = TRUE;
|
|---|
| 1114 |
|
|---|
| 1115 | }
|
|---|
| 1116 |
|
|---|
| 1117 | if ( idx < ((int)s->length()-1) ) {
|
|---|
| 1118 | gotoLineEnd();
|
|---|
| 1119 | } else if ( para->next() ) {
|
|---|
| 1120 | QTextParagraph *p = para->next();
|
|---|
| 1121 | while ( p && !p->isVisible() )
|
|---|
| 1122 | p = p->next();
|
|---|
| 1123 | if ( s ) {
|
|---|
| 1124 | para = p;
|
|---|
| 1125 | idx = 0;
|
|---|
| 1126 | }
|
|---|
| 1127 | } else {
|
|---|
| 1128 | gotoLineEnd();
|
|---|
| 1129 | }
|
|---|
| 1130 | }
|
|---|
| 1131 |
|
|---|
| 1132 | bool QTextCursor::atParagStart()
|
|---|
| 1133 | {
|
|---|
| 1134 | return idx == 0;
|
|---|
| 1135 | }
|
|---|
| 1136 |
|
|---|
| 1137 | bool QTextCursor::atParagEnd()
|
|---|
| 1138 | {
|
|---|
| 1139 | return idx == para->length() - 1;
|
|---|
| 1140 | }
|
|---|
| 1141 |
|
|---|
| 1142 | void QTextCursor::splitAndInsertEmptyParagraph( bool ind, bool updateIds )
|
|---|
| 1143 | {
|
|---|
| 1144 | if ( !para->document() )
|
|---|
| 1145 | return;
|
|---|
| 1146 | tmpX = -1;
|
|---|
| 1147 | QTextFormat *f = 0;
|
|---|
| 1148 | if ( para->document()->useFormatCollection() ) {
|
|---|
| 1149 | f = para->at( idx )->format();
|
|---|
| 1150 | if ( idx == para->length() - 1 && idx > 0 )
|
|---|
| 1151 | f = para->at( idx - 1 )->format();
|
|---|
| 1152 | if ( f->isMisspelled() ) {
|
|---|
| 1153 | f->removeRef();
|
|---|
| 1154 | f = para->document()->formatCollection()->format( f->font(), f->color() );
|
|---|
| 1155 | }
|
|---|
| 1156 | }
|
|---|
| 1157 |
|
|---|
| 1158 | if ( atParagEnd() ) {
|
|---|
| 1159 | QTextParagraph *n = para->next();
|
|---|
| 1160 | QTextParagraph *s = para->document()->createParagraph( para->document(), para, n, updateIds );
|
|---|
| 1161 | if ( f )
|
|---|
| 1162 | s->setFormat( 0, 1, f, TRUE );
|
|---|
| 1163 | s->copyParagData( para );
|
|---|
| 1164 | if ( ind ) {
|
|---|
| 1165 | int oi, ni;
|
|---|
| 1166 | s->indent( &oi, &ni );
|
|---|
| 1167 | para = s;
|
|---|
| 1168 | idx = ni;
|
|---|
| 1169 | } else {
|
|---|
| 1170 | para = s;
|
|---|
| 1171 | idx = 0;
|
|---|
| 1172 | }
|
|---|
| 1173 | } else if ( atParagStart() ) {
|
|---|
| 1174 | QTextParagraph *p = para->prev();
|
|---|
| 1175 | QTextParagraph *s = para->document()->createParagraph( para->document(), p, para, updateIds );
|
|---|
| 1176 | if ( f )
|
|---|
| 1177 | s->setFormat( 0, 1, f, TRUE );
|
|---|
| 1178 | s->copyParagData( para );
|
|---|
| 1179 | if ( ind ) {
|
|---|
| 1180 | s->indent();
|
|---|
| 1181 | s->format();
|
|---|
| 1182 | indent();
|
|---|
| 1183 | para->format();
|
|---|
| 1184 | }
|
|---|
| 1185 | } else {
|
|---|
| 1186 | QString str = para->string()->toString().mid( idx, 0xFFFFFF );
|
|---|
| 1187 | QTextParagraph *n = para->next();
|
|---|
| 1188 | QTextParagraph *s = para->document()->createParagraph( para->document(), para, n, updateIds );
|
|---|
| 1189 | s->copyParagData( para );
|
|---|
| 1190 | s->remove( 0, 1 );
|
|---|
| 1191 | s->append( str, TRUE );
|
|---|
| 1192 | for ( uint i = 0; i < str.length(); ++i ) {
|
|---|
| 1193 | QTextStringChar* tsc = para->at( idx + i );
|
|---|
| 1194 | s->setFormat( i, 1, tsc->format(), TRUE );
|
|---|
| 1195 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 1196 | if ( tsc->isCustom() ) {
|
|---|
| 1197 | QTextCustomItem * item = tsc->customItem();
|
|---|
| 1198 | s->at( i )->setCustomItem( item );
|
|---|
| 1199 | tsc->loseCustomItem();
|
|---|
| 1200 | }
|
|---|
| 1201 | #endif
|
|---|
| 1202 | if ( tsc->isAnchor() )
|
|---|
| 1203 | s->at( i )->setAnchor( tsc->anchorName(),
|
|---|
| 1204 | tsc->anchorHref() );
|
|---|
| 1205 | }
|
|---|
| 1206 | para->truncate( idx );
|
|---|
| 1207 | if ( ind ) {
|
|---|
| 1208 | int oi, ni;
|
|---|
| 1209 | s->indent( &oi, &ni );
|
|---|
| 1210 | para = s;
|
|---|
| 1211 | idx = ni;
|
|---|
| 1212 | } else {
|
|---|
| 1213 | para = s;
|
|---|
| 1214 | idx = 0;
|
|---|
| 1215 | }
|
|---|
| 1216 | }
|
|---|
| 1217 |
|
|---|
| 1218 | invalidateNested();
|
|---|
| 1219 | }
|
|---|
| 1220 |
|
|---|
| 1221 | bool QTextCursor::remove()
|
|---|
| 1222 | {
|
|---|
| 1223 | tmpX = -1;
|
|---|
| 1224 | if ( !atParagEnd() ) {
|
|---|
| 1225 | int next = para->string()->nextCursorPosition( idx );
|
|---|
| 1226 | para->remove( idx, next-idx );
|
|---|
| 1227 | int h = para->rect().height();
|
|---|
| 1228 | para->format( -1, TRUE );
|
|---|
| 1229 | if ( h != para->rect().height() )
|
|---|
| 1230 | invalidateNested();
|
|---|
| 1231 | else if ( para->document() && para->document()->parent() )
|
|---|
| 1232 | para->document()->nextDoubleBuffered = TRUE;
|
|---|
| 1233 | return FALSE;
|
|---|
| 1234 | } else if ( para->next() ) {
|
|---|
| 1235 | para->join( para->next() );
|
|---|
| 1236 | invalidateNested();
|
|---|
| 1237 | return TRUE;
|
|---|
| 1238 | }
|
|---|
| 1239 | return FALSE;
|
|---|
| 1240 | }
|
|---|
| 1241 |
|
|---|
| 1242 | /* needed to implement backspace the correct way */
|
|---|
| 1243 | bool QTextCursor::removePreviousChar()
|
|---|
| 1244 | {
|
|---|
| 1245 | tmpX = -1;
|
|---|
| 1246 | if ( !atParagStart() ) {
|
|---|
| 1247 | para->remove( idx-1, 1 );
|
|---|
| 1248 | int h = para->rect().height();
|
|---|
| 1249 | idx--;
|
|---|
| 1250 | // shouldn't be needed, just to make sure.
|
|---|
| 1251 | fixCursorPosition();
|
|---|
| 1252 | para->format( -1, TRUE );
|
|---|
| 1253 | if ( h != para->rect().height() )
|
|---|
| 1254 | invalidateNested();
|
|---|
| 1255 | else if ( para->document() && para->document()->parent() )
|
|---|
| 1256 | para->document()->nextDoubleBuffered = TRUE;
|
|---|
| 1257 | return FALSE;
|
|---|
| 1258 | } else if ( para->prev() ) {
|
|---|
| 1259 | para = para->prev();
|
|---|
| 1260 | para->join( para->next() );
|
|---|
| 1261 | invalidateNested();
|
|---|
| 1262 | return TRUE;
|
|---|
| 1263 | }
|
|---|
| 1264 | return FALSE;
|
|---|
| 1265 | }
|
|---|
| 1266 |
|
|---|
| 1267 | void QTextCursor::indent()
|
|---|
| 1268 | {
|
|---|
| 1269 | int oi = 0, ni = 0;
|
|---|
| 1270 | para->indent( &oi, &ni );
|
|---|
| 1271 | if ( oi == ni )
|
|---|
| 1272 | return;
|
|---|
| 1273 |
|
|---|
| 1274 | if ( idx >= oi )
|
|---|
| 1275 | idx += ni - oi;
|
|---|
| 1276 | else
|
|---|
| 1277 | idx = ni;
|
|---|
| 1278 | }
|
|---|
| 1279 |
|
|---|
| 1280 | void QTextCursor::fixCursorPosition()
|
|---|
| 1281 | {
|
|---|
| 1282 | // searches for the closest valid cursor position
|
|---|
| 1283 | if ( para->string()->validCursorPosition( idx ) )
|
|---|
| 1284 | return;
|
|---|
| 1285 |
|
|---|
| 1286 | int lineIdx;
|
|---|
| 1287 | QTextStringChar *start = para->lineStartOfChar( idx, &lineIdx, 0 );
|
|---|
| 1288 | int x = para->string()->at( idx ).x;
|
|---|
| 1289 | int diff = QABS(start->x - x);
|
|---|
| 1290 | int best = lineIdx;
|
|---|
| 1291 |
|
|---|
| 1292 | QTextStringChar *c = start;
|
|---|
| 1293 | ++c;
|
|---|
| 1294 |
|
|---|
| 1295 | QTextStringChar *end = ¶->string()->at( para->length()-1 );
|
|---|
| 1296 | while ( c <= end && !c->lineStart ) {
|
|---|
| 1297 | int xp = c->x;
|
|---|
| 1298 | if ( c->rightToLeft )
|
|---|
| 1299 | xp += para->string()->width( lineIdx + (c-start) );
|
|---|
| 1300 | int ndiff = QABS(xp - x);
|
|---|
| 1301 | if ( ndiff < diff && para->string()->validCursorPosition(lineIdx + (c-start)) ) {
|
|---|
| 1302 | diff = ndiff;
|
|---|
| 1303 | best = lineIdx + (c-start);
|
|---|
| 1304 | }
|
|---|
| 1305 | ++c;
|
|---|
| 1306 | }
|
|---|
| 1307 | idx = best;
|
|---|
| 1308 | }
|
|---|
| 1309 |
|
|---|
| 1310 |
|
|---|
| 1311 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 1312 |
|
|---|
| 1313 | QTextDocument::QTextDocument( QTextDocument *p )
|
|---|
| 1314 | : par( p ), parentPar( 0 )
|
|---|
| 1315 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 1316 | , tc( 0 )
|
|---|
| 1317 | #endif
|
|---|
| 1318 | , tArray( 0 ), tStopWidth( 0 )
|
|---|
| 1319 | {
|
|---|
| 1320 | fCollection = new QTextFormatCollection;
|
|---|
| 1321 | init();
|
|---|
| 1322 | }
|
|---|
| 1323 |
|
|---|
| 1324 | QTextDocument::QTextDocument( QTextDocument *p, QTextFormatCollection *f )
|
|---|
| 1325 | : par( p ), parentPar( 0 )
|
|---|
| 1326 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 1327 | , tc( 0 )
|
|---|
| 1328 | #endif
|
|---|
| 1329 | , tArray( 0 ), tStopWidth( 0 )
|
|---|
| 1330 | {
|
|---|
| 1331 | fCollection = f;
|
|---|
| 1332 | init();
|
|---|
| 1333 | }
|
|---|
| 1334 |
|
|---|
| 1335 | void QTextDocument::init()
|
|---|
| 1336 | {
|
|---|
| 1337 | oTextValid = TRUE;
|
|---|
| 1338 | mightHaveCustomItems = FALSE;
|
|---|
| 1339 | if ( par )
|
|---|
| 1340 | par->insertChild( this );
|
|---|
| 1341 | pProcessor = 0;
|
|---|
| 1342 | useFC = TRUE;
|
|---|
| 1343 | pFormatter = 0;
|
|---|
| 1344 | indenter = 0;
|
|---|
| 1345 | fParag = 0;
|
|---|
| 1346 | txtFormat = Qt::AutoText;
|
|---|
| 1347 | preferRichText = FALSE;
|
|---|
| 1348 | pages = FALSE;
|
|---|
| 1349 | focusIndicator.parag = 0;
|
|---|
| 1350 | minw = 0;
|
|---|
| 1351 | wused = 0;
|
|---|
| 1352 | minwParag = curParag = 0;
|
|---|
| 1353 | align = AlignAuto;
|
|---|
| 1354 | nSelections = 1;
|
|---|
| 1355 |
|
|---|
| 1356 | setStyleSheet( QStyleSheet::defaultSheet() );
|
|---|
| 1357 | #ifndef QT_NO_MIME
|
|---|
| 1358 | factory_ = QMimeSourceFactory::defaultFactory();
|
|---|
| 1359 | #endif
|
|---|
| 1360 | contxt = QString::null;
|
|---|
| 1361 |
|
|---|
| 1362 | underlLinks = par ? par->underlLinks : TRUE;
|
|---|
| 1363 | backBrush = 0;
|
|---|
| 1364 | buf_pixmap = 0;
|
|---|
| 1365 | nextDoubleBuffered = FALSE;
|
|---|
| 1366 |
|
|---|
| 1367 | if ( par )
|
|---|
| 1368 | withoutDoubleBuffer = par->withoutDoubleBuffer;
|
|---|
| 1369 | else
|
|---|
| 1370 | withoutDoubleBuffer = FALSE;
|
|---|
| 1371 |
|
|---|
| 1372 | lParag = fParag = createParagraph( this, 0, 0 );
|
|---|
| 1373 |
|
|---|
| 1374 | cx = 0;
|
|---|
| 1375 | cy = 2;
|
|---|
| 1376 | if ( par )
|
|---|
| 1377 | cx = cy = 0;
|
|---|
| 1378 | cw = 600;
|
|---|
| 1379 | vw = 0;
|
|---|
| 1380 | flow_ = new QTextFlow;
|
|---|
| 1381 | flow_->setWidth( cw );
|
|---|
| 1382 |
|
|---|
| 1383 | leftmargin = rightmargin = 4;
|
|---|
| 1384 | scaleFontsFactor = 1;
|
|---|
| 1385 |
|
|---|
| 1386 |
|
|---|
| 1387 | selectionColors[ Standard ] = QApplication::palette().color( QPalette::Active, QColorGroup::Highlight );
|
|---|
| 1388 | selectionText[ Standard ] = TRUE;
|
|---|
| 1389 | selectionText[ IMSelectionText ] = TRUE;
|
|---|
| 1390 | selectionText[ IMCompositionText ] = FALSE;
|
|---|
| 1391 | commandHistory = new QTextCommandHistory( 100 );
|
|---|
| 1392 | tStopWidth = formatCollection()->defaultFormat()->width( 'x' ) * 8;
|
|---|
| 1393 | }
|
|---|
| 1394 |
|
|---|
| 1395 | QTextDocument::~QTextDocument()
|
|---|
| 1396 | {
|
|---|
| 1397 | delete commandHistory;
|
|---|
| 1398 | if ( par )
|
|---|
| 1399 | par->removeChild( this );
|
|---|
| 1400 | clear();
|
|---|
| 1401 | delete flow_;
|
|---|
| 1402 | if ( !par )
|
|---|
| 1403 | delete pFormatter;
|
|---|
| 1404 | delete fCollection;
|
|---|
| 1405 | delete pProcessor;
|
|---|
| 1406 | delete buf_pixmap;
|
|---|
| 1407 | delete indenter;
|
|---|
| 1408 | delete backBrush;
|
|---|
| 1409 | delete [] tArray;
|
|---|
| 1410 | }
|
|---|
| 1411 |
|
|---|
| 1412 | void QTextDocument::clear( bool createEmptyParag )
|
|---|
| 1413 | {
|
|---|
| 1414 | while ( fParag ) {
|
|---|
| 1415 | QTextParagraph *p = fParag->next();
|
|---|
| 1416 | delete fParag;
|
|---|
| 1417 | fParag = p;
|
|---|
| 1418 | }
|
|---|
| 1419 | if ( flow_ )
|
|---|
| 1420 | flow_->clear();
|
|---|
| 1421 | fParag = lParag = 0;
|
|---|
| 1422 | if ( createEmptyParag )
|
|---|
| 1423 | fParag = lParag = createParagraph( this );
|
|---|
| 1424 | selections.clear();
|
|---|
| 1425 | oText = QString::null;
|
|---|
| 1426 | oTextValid = FALSE;
|
|---|
| 1427 | }
|
|---|
| 1428 |
|
|---|
| 1429 | int QTextDocument::widthUsed() const
|
|---|
| 1430 | {
|
|---|
| 1431 | return wused + 2*border_tolerance;
|
|---|
| 1432 | }
|
|---|
| 1433 |
|
|---|
| 1434 | int QTextDocument::height() const
|
|---|
| 1435 | {
|
|---|
| 1436 | int h = 0;
|
|---|
| 1437 | if ( lParag )
|
|---|
| 1438 | h = lParag->rect().top() + lParag->rect().height() + 1;
|
|---|
| 1439 | int fh = flow_->boundingRect().bottom();
|
|---|
| 1440 | return QMAX( h, fh );
|
|---|
| 1441 | }
|
|---|
| 1442 |
|
|---|
| 1443 |
|
|---|
| 1444 |
|
|---|
| 1445 | QTextParagraph *QTextDocument::createParagraph( QTextDocument *d, QTextParagraph *pr, QTextParagraph *nx, bool updateIds )
|
|---|
| 1446 | {
|
|---|
| 1447 | return new QTextParagraph( d, pr, nx, updateIds );
|
|---|
| 1448 | }
|
|---|
| 1449 |
|
|---|
| 1450 | bool QTextDocument::setMinimumWidth( int needed, int used, QTextParagraph *p )
|
|---|
| 1451 | {
|
|---|
| 1452 | if ( needed == -1 ) {
|
|---|
| 1453 | minw = 0;
|
|---|
| 1454 | wused = 0;
|
|---|
| 1455 | p = 0;
|
|---|
| 1456 | }
|
|---|
| 1457 | if ( p == minwParag ) {
|
|---|
| 1458 | if (minw > needed) {
|
|---|
| 1459 | QTextParagraph *tp = fParag;
|
|---|
| 1460 | while (tp) {
|
|---|
| 1461 | if (tp != p && tp->minwidth > needed) {
|
|---|
| 1462 | needed = tp->minwidth;
|
|---|
| 1463 | minwParag = tp;
|
|---|
| 1464 | }
|
|---|
| 1465 | tp = tp->n;
|
|---|
| 1466 | }
|
|---|
| 1467 | }
|
|---|
| 1468 | minw = needed;
|
|---|
| 1469 | emit minimumWidthChanged( minw );
|
|---|
| 1470 | } else if ( needed > minw ) {
|
|---|
| 1471 | minw = needed;
|
|---|
| 1472 | minwParag = p;
|
|---|
| 1473 | emit minimumWidthChanged( minw );
|
|---|
| 1474 | }
|
|---|
| 1475 | wused = QMAX( wused, used );
|
|---|
| 1476 | wused = QMAX( wused, minw );
|
|---|
| 1477 | cw = QMAX( minw, cw );
|
|---|
| 1478 | return TRUE;
|
|---|
| 1479 | }
|
|---|
| 1480 |
|
|---|
| 1481 | void QTextDocument::setPlainText( const QString &text )
|
|---|
| 1482 | {
|
|---|
| 1483 | preferRichText = FALSE;
|
|---|
| 1484 | clear();
|
|---|
| 1485 | oTextValid = TRUE;
|
|---|
| 1486 | oText = text;
|
|---|
| 1487 |
|
|---|
| 1488 | int lastNl = 0;
|
|---|
| 1489 | int nl = text.find( '\n' );
|
|---|
| 1490 | if ( nl == -1 ) {
|
|---|
| 1491 | lParag = createParagraph( this, lParag, 0 );
|
|---|
| 1492 | if ( !fParag )
|
|---|
| 1493 | fParag = lParag;
|
|---|
| 1494 | QString s = text;
|
|---|
| 1495 | if ( !s.isEmpty() ) {
|
|---|
| 1496 | if ( s[ (int)s.length() - 1 ] == '\r' )
|
|---|
| 1497 | s.remove( s.length() - 1, 1 );
|
|---|
| 1498 | lParag->append( s );
|
|---|
| 1499 | }
|
|---|
| 1500 | } else {
|
|---|
| 1501 | for (;;) {
|
|---|
| 1502 | lParag = createParagraph( this, lParag, 0 );
|
|---|
| 1503 | if ( !fParag )
|
|---|
| 1504 | fParag = lParag;
|
|---|
| 1505 | int l = nl - lastNl;
|
|---|
| 1506 | if ( l > 0 ) {
|
|---|
| 1507 | if (text.unicode()[nl-1] == '\r')
|
|---|
| 1508 | l--;
|
|---|
| 1509 | QConstString cs(text.unicode()+lastNl, l);
|
|---|
| 1510 | lParag->append( cs.string() );
|
|---|
| 1511 | }
|
|---|
| 1512 | if ( nl == (int)text.length() )
|
|---|
| 1513 | break;
|
|---|
| 1514 | lastNl = nl + 1;
|
|---|
| 1515 | nl = text.find( '\n', nl + 1 );
|
|---|
| 1516 | if ( nl == -1 )
|
|---|
| 1517 | nl = text.length();
|
|---|
| 1518 | }
|
|---|
| 1519 | }
|
|---|
| 1520 | if ( !lParag )
|
|---|
| 1521 | lParag = fParag = createParagraph( this, 0, 0 );
|
|---|
| 1522 | }
|
|---|
| 1523 |
|
|---|
| 1524 | struct Q_EXPORT QTextDocumentTag {
|
|---|
| 1525 | QTextDocumentTag(){}
|
|---|
| 1526 | QTextDocumentTag( const QString&n, const QStyleSheetItem* s, const QTextFormat& f )
|
|---|
| 1527 | :name(n),style(s), format(f), alignment(Qt::AlignAuto), direction(QChar::DirON),liststyle(QStyleSheetItem::ListDisc) {
|
|---|
| 1528 | wsm = QStyleSheetItem::WhiteSpaceNormal;
|
|---|
| 1529 | }
|
|---|
| 1530 | QString name;
|
|---|
| 1531 | const QStyleSheetItem* style;
|
|---|
| 1532 | QString anchorHref;
|
|---|
| 1533 | QStyleSheetItem::WhiteSpaceMode wsm;
|
|---|
| 1534 | QTextFormat format;
|
|---|
| 1535 | int alignment : 16;
|
|---|
| 1536 | int direction : 5;
|
|---|
| 1537 | QStyleSheetItem::ListStyle liststyle;
|
|---|
| 1538 |
|
|---|
| 1539 | QTextDocumentTag( const QTextDocumentTag& t ) {
|
|---|
| 1540 | name = t.name;
|
|---|
| 1541 | style = t.style;
|
|---|
| 1542 | anchorHref = t.anchorHref;
|
|---|
| 1543 | wsm = t.wsm;
|
|---|
| 1544 | format = t.format;
|
|---|
| 1545 | alignment = t.alignment;
|
|---|
| 1546 | direction = t.direction;
|
|---|
| 1547 | liststyle = t.liststyle;
|
|---|
| 1548 | }
|
|---|
| 1549 | QTextDocumentTag& operator=(const QTextDocumentTag& t) {
|
|---|
| 1550 | name = t.name;
|
|---|
| 1551 | style = t.style;
|
|---|
| 1552 | anchorHref = t.anchorHref;
|
|---|
| 1553 | wsm = t.wsm;
|
|---|
| 1554 | format = t.format;
|
|---|
| 1555 | alignment = t.alignment;
|
|---|
| 1556 | direction = t.direction;
|
|---|
| 1557 | liststyle = t.liststyle;
|
|---|
| 1558 | return *this;
|
|---|
| 1559 | }
|
|---|
| 1560 |
|
|---|
| 1561 | Q_DUMMY_COMPARISON_OPERATOR(QTextDocumentTag)
|
|---|
| 1562 | };
|
|---|
| 1563 |
|
|---|
| 1564 |
|
|---|
| 1565 | #define NEWPAR do{ if ( !hasNewPar) { \
|
|---|
| 1566 | if ( !textEditMode && curpar && curpar->length()>1 && curpar->at( curpar->length()-2)->c == QChar_linesep ) \
|
|---|
| 1567 | curpar->remove( curpar->length()-2, 1 ); \
|
|---|
| 1568 | curpar = createParagraph( this, curpar, curpar->next() ); styles.append( vec ); vec = 0;} \
|
|---|
| 1569 | hasNewPar = TRUE; \
|
|---|
| 1570 | curpar->rtext = TRUE; \
|
|---|
| 1571 | curpar->align = curtag.alignment; \
|
|---|
| 1572 | curpar->lstyle = curtag.liststyle; \
|
|---|
| 1573 | curpar->litem = ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ); \
|
|---|
| 1574 | curpar->str->setDirection( (QChar::Direction)curtag.direction ); \
|
|---|
| 1575 | space = TRUE; \
|
|---|
| 1576 | tabExpansionColumn = 0; \
|
|---|
| 1577 | delete vec; vec = new QPtrVector<QStyleSheetItem>( (uint)tags.count() + 1); \
|
|---|
| 1578 | int i = 0; \
|
|---|
| 1579 | for ( QValueStack<QTextDocumentTag>::Iterator it = tags.begin(); it != tags.end(); ++it ) \
|
|---|
| 1580 | vec->insert( i++, (*it).style ); \
|
|---|
| 1581 | vec->insert( i, curtag.style ); \
|
|---|
| 1582 | }while(FALSE);
|
|---|
| 1583 |
|
|---|
| 1584 |
|
|---|
| 1585 | void QTextDocument::setRichText( const QString &text, const QString &context )
|
|---|
| 1586 | {
|
|---|
| 1587 | preferRichText = TRUE;
|
|---|
| 1588 | if ( !context.isEmpty() )
|
|---|
| 1589 | setContext( context );
|
|---|
| 1590 | clear();
|
|---|
| 1591 | fParag = lParag = createParagraph( this );
|
|---|
| 1592 | oTextValid = TRUE;
|
|---|
| 1593 | oText = text;
|
|---|
| 1594 | setRichTextInternal( text );
|
|---|
| 1595 | fParag->rtext = TRUE;
|
|---|
| 1596 | }
|
|---|
| 1597 |
|
|---|
| 1598 | void QTextDocument::setRichTextInternal( const QString &text, QTextCursor* cursor )
|
|---|
| 1599 | {
|
|---|
| 1600 | QTextParagraph* curpar = lParag;
|
|---|
| 1601 | int pos = 0;
|
|---|
| 1602 | QValueStack<QTextDocumentTag> tags;
|
|---|
| 1603 | QTextDocumentTag initag( "", sheet_->item(""), *formatCollection()->defaultFormat() );
|
|---|
| 1604 | if ( bodyText.isValid() )
|
|---|
| 1605 | initag.format.setColor( bodyText );
|
|---|
| 1606 | QTextDocumentTag curtag = initag;
|
|---|
| 1607 | bool space = TRUE;
|
|---|
| 1608 | bool canMergeLi = FALSE;
|
|---|
| 1609 |
|
|---|
| 1610 | bool textEditMode = FALSE;
|
|---|
| 1611 | int tabExpansionColumn = 0;
|
|---|
| 1612 |
|
|---|
| 1613 | const QChar* doc = text.unicode();
|
|---|
| 1614 | int length = text.length();
|
|---|
| 1615 | bool hasNewPar = curpar->length() <= 1;
|
|---|
| 1616 | QString anchorName;
|
|---|
| 1617 |
|
|---|
| 1618 | // style sheet handling for margin and line spacing calculation below
|
|---|
| 1619 | QTextParagraph* stylesPar = curpar;
|
|---|
| 1620 | QPtrVector<QStyleSheetItem>* vec = 0;
|
|---|
| 1621 | QPtrList< QPtrVector<QStyleSheetItem> > styles;
|
|---|
| 1622 | styles.setAutoDelete( TRUE );
|
|---|
| 1623 |
|
|---|
| 1624 | if ( cursor ) {
|
|---|
| 1625 | cursor->splitAndInsertEmptyParagraph();
|
|---|
| 1626 | QTextCursor tmp = *cursor;
|
|---|
| 1627 | tmp.gotoPreviousLetter();
|
|---|
| 1628 | stylesPar = curpar = tmp.paragraph();
|
|---|
| 1629 | hasNewPar = TRUE;
|
|---|
| 1630 | textEditMode = TRUE;
|
|---|
| 1631 | } else {
|
|---|
| 1632 | NEWPAR;
|
|---|
| 1633 | }
|
|---|
| 1634 |
|
|---|
| 1635 | // set rtext spacing to FALSE for the initial paragraph.
|
|---|
| 1636 | curpar->rtext = FALSE;
|
|---|
| 1637 |
|
|---|
| 1638 | QString wellKnownTags = "br hr wsp table qt body meta title";
|
|---|
| 1639 |
|
|---|
| 1640 | while ( pos < length ) {
|
|---|
| 1641 | if ( hasPrefix(doc, length, pos, '<' ) ){
|
|---|
| 1642 | if ( !hasPrefix( doc, length, pos+1, QChar('/') ) ) {
|
|---|
| 1643 | // open tag
|
|---|
| 1644 | QMap<QString, QString> attr;
|
|---|
| 1645 | bool emptyTag = FALSE;
|
|---|
| 1646 | QString tagname = parseOpenTag(doc, length, pos, attr, emptyTag);
|
|---|
| 1647 | if ( tagname.isEmpty() )
|
|---|
| 1648 | continue; // nothing we could do with this, probably parse error
|
|---|
| 1649 |
|
|---|
| 1650 | const QStyleSheetItem* nstyle = sheet_->item(tagname);
|
|---|
| 1651 |
|
|---|
| 1652 | if ( nstyle ) {
|
|---|
| 1653 | // we might have to close some 'forgotten' tags
|
|---|
| 1654 | while ( !nstyle->allowedInContext( curtag.style ) ) {
|
|---|
| 1655 | QString msg;
|
|---|
| 1656 | msg.sprintf( "QText Warning: Document not valid ( '%s' not allowed in '%s' #%d)",
|
|---|
| 1657 | tagname.ascii(), curtag.style->name().ascii(), pos);
|
|---|
| 1658 | sheet_->error( msg );
|
|---|
| 1659 | if ( tags.isEmpty() )
|
|---|
| 1660 | break;
|
|---|
| 1661 | curtag = tags.pop();
|
|---|
| 1662 | }
|
|---|
| 1663 |
|
|---|
| 1664 | /* special handling for p and li for HTML
|
|---|
| 1665 | compatibility. We do not want to embed blocks in
|
|---|
| 1666 | p, and we do not want new blocks inside non-empty
|
|---|
| 1667 | lis. Plus we want to merge empty lis sometimes. */
|
|---|
| 1668 | if( nstyle->displayMode() == QStyleSheetItem::DisplayListItem ) {
|
|---|
| 1669 | canMergeLi = TRUE;
|
|---|
| 1670 | } else if ( nstyle->displayMode() == QStyleSheetItem::DisplayBlock ) {
|
|---|
| 1671 | while ( curtag.style->name() == "p" ) {
|
|---|
| 1672 | if ( tags.isEmpty() )
|
|---|
| 1673 | break;
|
|---|
| 1674 | curtag = tags.pop();
|
|---|
| 1675 | }
|
|---|
| 1676 |
|
|---|
| 1677 | if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
|
|---|
| 1678 | // we are in a li and a new block comes along
|
|---|
| 1679 | if ( nstyle->name() == "ul" || nstyle->name() == "ol" )
|
|---|
| 1680 | hasNewPar = FALSE; // we want an empty li (like most browsers)
|
|---|
| 1681 | if ( !hasNewPar ) {
|
|---|
| 1682 | /* do not add new blocks inside
|
|---|
| 1683 | non-empty lis */
|
|---|
| 1684 | while ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
|
|---|
| 1685 | if ( tags.isEmpty() )
|
|---|
| 1686 | break;
|
|---|
| 1687 | curtag = tags.pop();
|
|---|
| 1688 | }
|
|---|
| 1689 | } else if ( canMergeLi ) {
|
|---|
| 1690 | /* we have an empty li and a block
|
|---|
| 1691 | comes along, merge them */
|
|---|
| 1692 | nstyle = curtag.style;
|
|---|
| 1693 | }
|
|---|
| 1694 | canMergeLi = FALSE;
|
|---|
| 1695 | }
|
|---|
| 1696 | }
|
|---|
| 1697 | }
|
|---|
| 1698 |
|
|---|
| 1699 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 1700 | QTextCustomItem* custom = 0;
|
|---|
| 1701 | #else
|
|---|
| 1702 | bool custom = FALSE;
|
|---|
| 1703 | #endif
|
|---|
| 1704 |
|
|---|
| 1705 | // some well-known tags, some have a nstyle, some not
|
|---|
| 1706 | if ( wellKnownTags.find( tagname ) != -1 ) {
|
|---|
| 1707 | if ( tagname == "br" ) {
|
|---|
| 1708 | emptyTag = space = TRUE;
|
|---|
| 1709 | int index = QMAX( curpar->length(),1) - 1;
|
|---|
| 1710 | QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
|
|---|
| 1711 | curpar->append( QChar_linesep );
|
|---|
| 1712 | curpar->setFormat( index, 1, &format );
|
|---|
| 1713 | } else if ( tagname == "hr" ) {
|
|---|
| 1714 | emptyTag = space = TRUE;
|
|---|
| 1715 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 1716 | custom = sheet_->tag( tagname, attr, contxt, *factory_ , emptyTag, this );
|
|---|
| 1717 | #endif
|
|---|
| 1718 | } else if ( tagname == "table" ) {
|
|---|
| 1719 | emptyTag = space = TRUE;
|
|---|
| 1720 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 1721 | QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
|
|---|
| 1722 | curpar->setAlignment( curtag.alignment );
|
|---|
| 1723 | custom = parseTable( attr, format, doc, length, pos, curpar );
|
|---|
| 1724 | #endif
|
|---|
| 1725 | } else if ( tagname == "qt" || tagname == "body" ) {
|
|---|
| 1726 | if ( attr.contains( "bgcolor" ) ) {
|
|---|
| 1727 | QBrush *b = new QBrush( QColor( attr["bgcolor"] ) );
|
|---|
| 1728 | setPaper( b );
|
|---|
| 1729 | }
|
|---|
| 1730 | if ( attr.contains( "background" ) ) {
|
|---|
| 1731 | #ifndef QT_NO_MIME
|
|---|
| 1732 | QImage img;
|
|---|
| 1733 | QString bg = attr["background"];
|
|---|
| 1734 | const QMimeSource* m = factory_->data( bg, contxt );
|
|---|
| 1735 | if ( !m ) {
|
|---|
| 1736 | qWarning("QRichText: no mimesource for %s", bg.latin1() );
|
|---|
| 1737 | } else {
|
|---|
| 1738 | if ( !QImageDrag::decode( m, img ) ) {
|
|---|
| 1739 | qWarning("QTextImage: cannot decode %s", bg.latin1() );
|
|---|
| 1740 | }
|
|---|
| 1741 | }
|
|---|
| 1742 | if ( !img.isNull() ) {
|
|---|
| 1743 | QBrush *b = new QBrush( QColor(), QPixmap( img ) );
|
|---|
| 1744 | setPaper( b );
|
|---|
| 1745 | }
|
|---|
| 1746 | #endif
|
|---|
| 1747 | }
|
|---|
| 1748 | if ( attr.contains( "text" ) ) {
|
|---|
| 1749 | QColor c( attr["text"] );
|
|---|
| 1750 | initag.format.setColor( c );
|
|---|
| 1751 | curtag.format.setColor( c );
|
|---|
| 1752 | bodyText = c;
|
|---|
| 1753 | }
|
|---|
| 1754 | if ( attr.contains( "link" ) )
|
|---|
| 1755 | linkColor = QColor( attr["link"] );
|
|---|
| 1756 | if ( attr.contains( "title" ) )
|
|---|
| 1757 | attribs.replace( "title", attr["title"] );
|
|---|
| 1758 |
|
|---|
| 1759 | if ( textEditMode ) {
|
|---|
| 1760 | if ( attr.contains("style" ) ) {
|
|---|
| 1761 | QString a = attr["style"];
|
|---|
| 1762 | for ( int s = 0; s < a.contains(';')+1; s++ ) {
|
|---|
| 1763 | QString style = a.section( ';', s, s );
|
|---|
| 1764 | if ( style.startsWith("font-size:" ) && style.endsWith("pt") ) {
|
|---|
| 1765 | scaleFontsFactor = double( formatCollection()->defaultFormat()->fn.pointSize() ) /
|
|---|
| 1766 | style.mid( 10, style.length() - 12 ).toInt();
|
|---|
| 1767 | }
|
|---|
| 1768 | }
|
|---|
| 1769 | }
|
|---|
| 1770 | nstyle = 0; // ignore body in textEditMode
|
|---|
| 1771 | }
|
|---|
| 1772 | // end qt- and body-tag handling
|
|---|
| 1773 | } else if ( tagname == "meta" ) {
|
|---|
| 1774 | if ( attr["name"] == "qrichtext" && attr["content"] == "1" )
|
|---|
| 1775 | textEditMode = TRUE;
|
|---|
| 1776 | } else if ( tagname == "title" ) {
|
|---|
| 1777 | QString title;
|
|---|
| 1778 | while ( pos < length ) {
|
|---|
| 1779 | if ( hasPrefix( doc, length, pos, QChar('<') ) && hasPrefix( doc, length, pos+1, QChar('/') ) &&
|
|---|
| 1780 | parseCloseTag( doc, length, pos ) == "title" )
|
|---|
| 1781 | break;
|
|---|
| 1782 | title += doc[ pos ];
|
|---|
| 1783 | ++pos;
|
|---|
| 1784 | }
|
|---|
| 1785 | attribs.replace( "title", title );
|
|---|
| 1786 | }
|
|---|
| 1787 | } // end of well-known tag handling
|
|---|
| 1788 |
|
|---|
| 1789 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 1790 | if ( !custom ) // try generic custom item
|
|---|
| 1791 | custom = sheet_->tag( tagname, attr, contxt, *factory_ , emptyTag, this );
|
|---|
| 1792 | #endif
|
|---|
| 1793 | if ( !nstyle && !custom ) // we have no clue what this tag could be, ignore it
|
|---|
| 1794 | continue;
|
|---|
| 1795 |
|
|---|
| 1796 | if ( custom ) {
|
|---|
| 1797 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 1798 | int index = QMAX( curpar->length(),1) - 1;
|
|---|
| 1799 | QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
|
|---|
| 1800 | curpar->append( QChar('*') );
|
|---|
| 1801 | QTextFormat* f = formatCollection()->format( &format );
|
|---|
| 1802 | curpar->setFormat( index, 1, f );
|
|---|
| 1803 | curpar->at( index )->setCustomItem( custom );
|
|---|
| 1804 | if ( !curtag.anchorHref.isEmpty() )
|
|---|
| 1805 | curpar->at(index)->setAnchor( QString::null, curtag.anchorHref );
|
|---|
| 1806 | if ( !anchorName.isEmpty() ) {
|
|---|
| 1807 | curpar->at(index)->setAnchor( anchorName, curpar->at(index)->anchorHref() );
|
|---|
| 1808 | anchorName = QString::null;
|
|---|
| 1809 | }
|
|---|
| 1810 | registerCustomItem( custom, curpar );
|
|---|
| 1811 | hasNewPar = FALSE;
|
|---|
| 1812 | #endif
|
|---|
| 1813 | } else if ( !emptyTag ) {
|
|---|
| 1814 | /* if we do nesting, push curtag on the stack,
|
|---|
| 1815 | otherwise reinint curag. */
|
|---|
| 1816 | if ( curtag.style->name() != tagname || nstyle->selfNesting() ) {
|
|---|
| 1817 | tags.push( curtag );
|
|---|
| 1818 | } else {
|
|---|
| 1819 | if ( !tags.isEmpty() )
|
|---|
| 1820 | curtag = tags.top();
|
|---|
| 1821 | else
|
|---|
| 1822 | curtag = initag;
|
|---|
| 1823 | }
|
|---|
| 1824 |
|
|---|
| 1825 | curtag.name = tagname;
|
|---|
| 1826 | curtag.style = nstyle;
|
|---|
| 1827 | curtag.name = tagname;
|
|---|
| 1828 | curtag.style = nstyle;
|
|---|
| 1829 | if ( nstyle->whiteSpaceMode() != QStyleSheetItem::WhiteSpaceModeUndefined )
|
|---|
| 1830 | curtag.wsm = nstyle->whiteSpaceMode();
|
|---|
| 1831 |
|
|---|
| 1832 | /* netscape compatibility: eat a newline and only a newline if a pre block starts */
|
|---|
| 1833 | if ( curtag.wsm == QStyleSheetItem::WhiteSpacePre &&
|
|---|
| 1834 | nstyle->displayMode() == QStyleSheetItem::DisplayBlock )
|
|---|
| 1835 | eat( doc, length, pos, '\n' );
|
|---|
| 1836 |
|
|---|
| 1837 | /* ignore whitespace for inline elements if there
|
|---|
| 1838 | was already one*/
|
|---|
| 1839 | if ( !textEditMode &&
|
|---|
| 1840 | (curtag.wsm == QStyleSheetItem::WhiteSpaceNormal
|
|---|
| 1841 | || curtag.wsm == QStyleSheetItem::WhiteSpaceNoWrap)
|
|---|
| 1842 | && ( space || nstyle->displayMode() != QStyleSheetItem::DisplayInline ) )
|
|---|
| 1843 | eatSpace( doc, length, pos );
|
|---|
| 1844 |
|
|---|
| 1845 | curtag.format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
|
|---|
| 1846 | if ( nstyle->isAnchor() ) {
|
|---|
| 1847 | if ( !anchorName.isEmpty() )
|
|---|
| 1848 | anchorName += "#" + attr["name"];
|
|---|
| 1849 | else
|
|---|
| 1850 | anchorName = attr["name"];
|
|---|
| 1851 | curtag.anchorHref = attr["href"];
|
|---|
| 1852 | }
|
|---|
| 1853 |
|
|---|
| 1854 | if ( nstyle->alignment() != QStyleSheetItem::Undefined )
|
|---|
| 1855 | curtag.alignment = nstyle->alignment();
|
|---|
| 1856 |
|
|---|
| 1857 | if ( nstyle->listStyle() != QStyleSheetItem::ListStyleUndefined )
|
|---|
| 1858 | curtag.liststyle = nstyle->listStyle();
|
|---|
| 1859 |
|
|---|
| 1860 | if ( nstyle->displayMode() == QStyleSheetItem::DisplayBlock
|
|---|
| 1861 | || nstyle->displayMode() == QStyleSheetItem::DisplayListItem ) {
|
|---|
| 1862 |
|
|---|
| 1863 | if ( nstyle->name() == "ol" || nstyle->name() == "ul" || nstyle->name() == "li") {
|
|---|
| 1864 | QString type = attr["type"];
|
|---|
| 1865 | if ( !type.isEmpty() ) {
|
|---|
| 1866 | if ( type == "1" ) {
|
|---|
| 1867 | curtag.liststyle = QStyleSheetItem::ListDecimal;
|
|---|
| 1868 | } else if ( type == "a" ) {
|
|---|
| 1869 | curtag.liststyle = QStyleSheetItem::ListLowerAlpha;
|
|---|
| 1870 | } else if ( type == "A" ) {
|
|---|
| 1871 | curtag.liststyle = QStyleSheetItem::ListUpperAlpha;
|
|---|
| 1872 | } else {
|
|---|
| 1873 | type = type.lower();
|
|---|
| 1874 | if ( type == "square" )
|
|---|
| 1875 | curtag.liststyle = QStyleSheetItem::ListSquare;
|
|---|
| 1876 | else if ( type == "disc" )
|
|---|
| 1877 | curtag.liststyle = QStyleSheetItem::ListDisc;
|
|---|
| 1878 | else if ( type == "circle" )
|
|---|
| 1879 | curtag.liststyle = QStyleSheetItem::ListCircle;
|
|---|
| 1880 | }
|
|---|
| 1881 | }
|
|---|
| 1882 | }
|
|---|
| 1883 |
|
|---|
| 1884 |
|
|---|
| 1885 | /* Internally we treat ordered and bullet
|
|---|
| 1886 | lists the same for margin calculations. In
|
|---|
| 1887 | order to have fast pointer compares in the
|
|---|
| 1888 | xMargin() functions we restrict ourselves to
|
|---|
| 1889 | <ol>. Once we calculate the margins in the
|
|---|
| 1890 | parser rathern than later, the unelegance of
|
|---|
| 1891 | this approach goes awy
|
|---|
| 1892 | */
|
|---|
| 1893 | if ( nstyle->name() == "ul" )
|
|---|
| 1894 | curtag.style = sheet_->item( "ol" );
|
|---|
| 1895 |
|
|---|
| 1896 | if ( attr.contains( "align" ) ) {
|
|---|
| 1897 | QString align = attr["align"].lower();
|
|---|
| 1898 | if ( align == "center" )
|
|---|
| 1899 | curtag.alignment = Qt::AlignCenter;
|
|---|
| 1900 | else if ( align == "right" )
|
|---|
| 1901 | curtag.alignment = Qt::AlignRight;
|
|---|
| 1902 | else if ( align == "justify" )
|
|---|
| 1903 | curtag.alignment = Qt::AlignJustify;
|
|---|
| 1904 | }
|
|---|
| 1905 | if ( attr.contains( "dir" ) ) {
|
|---|
| 1906 | QString dir = attr["dir"];
|
|---|
| 1907 | if ( dir == "rtl" )
|
|---|
| 1908 | curtag.direction = QChar::DirR;
|
|---|
| 1909 | else if ( dir == "ltr" )
|
|---|
| 1910 | curtag.direction = QChar::DirL;
|
|---|
| 1911 | }
|
|---|
| 1912 |
|
|---|
| 1913 | NEWPAR;
|
|---|
| 1914 |
|
|---|
| 1915 | if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
|
|---|
| 1916 | if ( attr.contains( "value " ) )
|
|---|
| 1917 | curpar->setListValue( attr["value"].toInt() );
|
|---|
| 1918 | }
|
|---|
| 1919 |
|
|---|
| 1920 | if ( attr.contains( "style" ) ) {
|
|---|
| 1921 | QString a = attr["style"];
|
|---|
| 1922 | bool ok = TRUE;
|
|---|
| 1923 | for ( int s = 0; ok && s < a.contains(';')+1; s++ ) {
|
|---|
| 1924 | QString style = a.section( ';', s, s );
|
|---|
| 1925 | if ( style.startsWith("margin-top:" ) && style.endsWith("px") )
|
|---|
| 1926 | curpar->utm = 1+style.mid(11, style.length() - 13).toInt(&ok);
|
|---|
| 1927 | else if ( style.startsWith("margin-bottom:" ) && style.endsWith("px") )
|
|---|
| 1928 | curpar->ubm = 1+style.mid(14, style.length() - 16).toInt(&ok);
|
|---|
| 1929 | else if ( style.startsWith("margin-left:" ) && style.endsWith("px") )
|
|---|
| 1930 | curpar->ulm = 1+style.mid(12, style.length() - 14).toInt(&ok);
|
|---|
| 1931 | else if ( style.startsWith("margin-right:" ) && style.endsWith("px") )
|
|---|
| 1932 | curpar->urm = 1+style.mid(13, style.length() - 15).toInt(&ok);
|
|---|
| 1933 | else if ( style.startsWith("text-indent:" ) && style.endsWith("px") )
|
|---|
| 1934 | curpar->uflm = 1+style.mid(12, style.length() - 14).toInt(&ok);
|
|---|
| 1935 | }
|
|---|
| 1936 | if ( !ok ) // be pressmistic
|
|---|
| 1937 | curpar->utm = curpar->ubm = curpar->urm = curpar->ulm = 0;
|
|---|
| 1938 | }
|
|---|
| 1939 | }
|
|---|
| 1940 | }
|
|---|
| 1941 | } else {
|
|---|
| 1942 | QString tagname = parseCloseTag( doc, length, pos );
|
|---|
| 1943 | if ( tagname.isEmpty() )
|
|---|
| 1944 | continue; // nothing we could do with this, probably parse error
|
|---|
| 1945 | if ( !sheet_->item( tagname ) ) // ignore unknown tags
|
|---|
| 1946 | continue;
|
|---|
| 1947 | if ( tagname == "li" )
|
|---|
| 1948 | continue;
|
|---|
| 1949 |
|
|---|
| 1950 | // we close a block item. Since the text may continue, we need to have a new paragraph
|
|---|
| 1951 | bool needNewPar = curtag.style->displayMode() == QStyleSheetItem::DisplayBlock
|
|---|
| 1952 | || curtag.style->displayMode() == QStyleSheetItem::DisplayListItem;
|
|---|
| 1953 |
|
|---|
| 1954 |
|
|---|
| 1955 | // html slopiness: handle unbalanched tag closing
|
|---|
| 1956 | while ( curtag.name != tagname ) {
|
|---|
| 1957 | QString msg;
|
|---|
| 1958 | msg.sprintf( "QText Warning: Document not valid ( '%s' not closed before '%s' #%d)",
|
|---|
| 1959 | curtag.name.ascii(), tagname.ascii(), pos);
|
|---|
| 1960 | sheet_->error( msg );
|
|---|
| 1961 | if ( tags.isEmpty() )
|
|---|
| 1962 | break;
|
|---|
| 1963 | curtag = tags.pop();
|
|---|
| 1964 | }
|
|---|
| 1965 |
|
|---|
| 1966 |
|
|---|
| 1967 | // close the tag
|
|---|
| 1968 | if ( !tags.isEmpty() )
|
|---|
| 1969 | curtag = tags.pop();
|
|---|
| 1970 | else
|
|---|
| 1971 | curtag = initag;
|
|---|
| 1972 |
|
|---|
| 1973 | if ( needNewPar ) {
|
|---|
| 1974 | if ( textEditMode && (tagname == "p" || tagname == "div" ) ) // preserve empty paragraphs
|
|---|
| 1975 | hasNewPar = FALSE;
|
|---|
| 1976 | NEWPAR;
|
|---|
| 1977 | }
|
|---|
| 1978 | }
|
|---|
| 1979 | } else {
|
|---|
| 1980 | // normal contents
|
|---|
| 1981 | QString s;
|
|---|
| 1982 | QChar c;
|
|---|
| 1983 | while ( pos < length && !hasPrefix(doc, length, pos, QChar('<') ) ){
|
|---|
| 1984 | if ( textEditMode ) {
|
|---|
| 1985 | // text edit mode: we handle all white space but ignore newlines
|
|---|
| 1986 | c = parseChar( doc, length, pos, QStyleSheetItem::WhiteSpacePre );
|
|---|
| 1987 | if ( c == QChar_linesep )
|
|---|
| 1988 | break;
|
|---|
| 1989 | } else {
|
|---|
| 1990 | int l = pos;
|
|---|
| 1991 | c = parseChar( doc, length, pos, curtag.wsm );
|
|---|
| 1992 |
|
|---|
| 1993 | // in white space pre mode: treat any space as non breakable
|
|---|
| 1994 | // and expand tabs to eight character wide columns.
|
|---|
| 1995 | if ( curtag.wsm == QStyleSheetItem::WhiteSpacePre ) {
|
|---|
| 1996 | if ( c == '\t' ) {
|
|---|
| 1997 | c = ' ';
|
|---|
| 1998 | while( (++tabExpansionColumn)%8 )
|
|---|
| 1999 | s += c;
|
|---|
| 2000 | }
|
|---|
| 2001 | if ( c == QChar_linesep )
|
|---|
| 2002 | tabExpansionColumn = 0;
|
|---|
| 2003 | else
|
|---|
| 2004 | tabExpansionColumn++;
|
|---|
| 2005 |
|
|---|
| 2006 | }
|
|---|
| 2007 | if ( c == ' ' || c == QChar_linesep ) {
|
|---|
| 2008 | /* avoid overlong paragraphs by forcing a new
|
|---|
| 2009 | paragraph after 4096 characters. This case can
|
|---|
| 2010 | occur when loading undiscovered plain text
|
|---|
| 2011 | documents in rich text mode. Instead of hanging
|
|---|
| 2012 | forever, we do the trick.
|
|---|
| 2013 | */
|
|---|
| 2014 | if ( curtag.wsm == QStyleSheetItem::WhiteSpaceNormal && s.length() > 4096 ) do {
|
|---|
| 2015 | if ( doc[l] == '\n' ) {
|
|---|
| 2016 | hasNewPar = FALSE; // for a new paragraph ...
|
|---|
| 2017 | NEWPAR;
|
|---|
| 2018 | hasNewPar = FALSE; // ... and make it non-reusable
|
|---|
| 2019 | c = '\n'; // make sure we break below
|
|---|
| 2020 | break;
|
|---|
| 2021 | }
|
|---|
| 2022 | } while ( ++l < pos );
|
|---|
| 2023 | }
|
|---|
| 2024 | }
|
|---|
| 2025 |
|
|---|
| 2026 | if ( c == '\n' )
|
|---|
| 2027 | break; // break on newlines, pre delievers a QChar_linesep
|
|---|
| 2028 |
|
|---|
| 2029 | bool c_isSpace = c.isSpace() && c.unicode() != 0x00a0U && !textEditMode;
|
|---|
| 2030 |
|
|---|
| 2031 | if ( curtag.wsm == QStyleSheetItem::WhiteSpaceNormal && c_isSpace && space )
|
|---|
| 2032 | continue;
|
|---|
| 2033 | if ( c == '\r' )
|
|---|
| 2034 | continue;
|
|---|
| 2035 | space = c_isSpace;
|
|---|
| 2036 | s += c;
|
|---|
| 2037 | }
|
|---|
| 2038 | if ( !s.isEmpty() && curtag.style->displayMode() != QStyleSheetItem::DisplayNone ) {
|
|---|
| 2039 | hasNewPar = FALSE;
|
|---|
| 2040 | int index = QMAX( curpar->length(),1) - 1;
|
|---|
| 2041 | curpar->append( s );
|
|---|
| 2042 | if (curtag.wsm != QStyleSheetItem::WhiteSpaceNormal) {
|
|---|
| 2043 | QTextString *str = curpar->string();
|
|---|
| 2044 | for (uint i = index; i < index + s.length(); ++i)
|
|---|
| 2045 | str->at(i).nobreak = TRUE;
|
|---|
| 2046 | }
|
|---|
| 2047 |
|
|---|
| 2048 | QTextFormat* f = formatCollection()->format( &curtag.format );
|
|---|
| 2049 | curpar->setFormat( index, s.length(), f, FALSE ); // do not use collection because we have done that already
|
|---|
| 2050 | f->ref += s.length() -1; // that what friends are for...
|
|---|
| 2051 | if ( !curtag.anchorHref.isEmpty() ) {
|
|---|
| 2052 | for ( int i = 0; i < int(s.length()); i++ )
|
|---|
| 2053 | curpar->at(index + i)->setAnchor( QString::null, curtag.anchorHref );
|
|---|
| 2054 | }
|
|---|
| 2055 | if ( !anchorName.isEmpty() ) {
|
|---|
| 2056 | for ( int i = 0; i < int(s.length()); i++ )
|
|---|
| 2057 | curpar->at(index + i)->setAnchor( anchorName, curpar->at(index + i)->anchorHref() );
|
|---|
| 2058 | anchorName = QString::null;
|
|---|
| 2059 | }
|
|---|
| 2060 | }
|
|---|
| 2061 | }
|
|---|
| 2062 | }
|
|---|
| 2063 |
|
|---|
| 2064 | if ( hasNewPar && curpar != fParag && !cursor && stylesPar != curpar ) {
|
|---|
| 2065 | // cleanup unused last paragraphs
|
|---|
| 2066 | curpar = curpar->p;
|
|---|
| 2067 | delete curpar->n;
|
|---|
| 2068 | }
|
|---|
| 2069 |
|
|---|
| 2070 | if ( !anchorName.isEmpty() ) {
|
|---|
| 2071 | curpar->at(curpar->length() - 1)->setAnchor( anchorName, curpar->at( curpar->length() - 1 )->anchorHref() );
|
|---|
| 2072 | anchorName = QString::null;
|
|---|
| 2073 | }
|
|---|
| 2074 |
|
|---|
| 2075 |
|
|---|
| 2076 | setRichTextMarginsInternal( styles, stylesPar );
|
|---|
| 2077 |
|
|---|
| 2078 | if ( cursor ) {
|
|---|
| 2079 | cursor->gotoPreviousLetter();
|
|---|
| 2080 | cursor->remove();
|
|---|
| 2081 | }
|
|---|
| 2082 | delete vec;
|
|---|
| 2083 | }
|
|---|
| 2084 |
|
|---|
| 2085 | void QTextDocument::setRichTextMarginsInternal( QPtrList< QPtrVector<QStyleSheetItem> >& styles, QTextParagraph* stylesPar )
|
|---|
| 2086 | {
|
|---|
| 2087 | // margin and line spacing calculation
|
|---|
| 2088 | QPtrVector<QStyleSheetItem>* prevStyle = 0;
|
|---|
| 2089 | QPtrVector<QStyleSheetItem>* curStyle = styles.first();
|
|---|
| 2090 | QPtrVector<QStyleSheetItem>* nextStyle = styles.next();
|
|---|
| 2091 | while ( stylesPar ) {
|
|---|
| 2092 | if ( !curStyle ) {
|
|---|
| 2093 | stylesPar = stylesPar->next();
|
|---|
| 2094 | prevStyle = curStyle;
|
|---|
| 2095 | curStyle = nextStyle;
|
|---|
| 2096 | nextStyle = styles.next();
|
|---|
| 2097 | continue;
|
|---|
| 2098 | }
|
|---|
| 2099 |
|
|---|
| 2100 | int i, mar;
|
|---|
| 2101 | QStyleSheetItem* mainStyle = curStyle->size() ? (*curStyle)[curStyle->size()-1] : 0;
|
|---|
| 2102 | if ( mainStyle && mainStyle->displayMode() == QStyleSheetItem::DisplayListItem )
|
|---|
| 2103 | stylesPar->setListItem( TRUE );
|
|---|
| 2104 | int numLists = 0;
|
|---|
| 2105 | for ( i = 0; i < (int)curStyle->size(); ++i ) {
|
|---|
| 2106 | if ( (*curStyle)[ i ]->displayMode() == QStyleSheetItem::DisplayBlock
|
|---|
| 2107 | && (*curStyle)[ i ]->listStyle() != QStyleSheetItem::ListStyleUndefined )
|
|---|
| 2108 | numLists++;
|
|---|
| 2109 | }
|
|---|
| 2110 | stylesPar->ldepth = numLists;
|
|---|
| 2111 | if ( stylesPar->next() && nextStyle ) {
|
|---|
| 2112 | // also set the depth of the next paragraph, required for the margin calculation
|
|---|
| 2113 | numLists = 0;
|
|---|
| 2114 | for ( i = 0; i < (int)nextStyle->size(); ++i ) {
|
|---|
| 2115 | if ( (*nextStyle)[ i ]->displayMode() == QStyleSheetItem::DisplayBlock
|
|---|
| 2116 | && (*nextStyle)[ i ]->listStyle() != QStyleSheetItem::ListStyleUndefined )
|
|---|
| 2117 | numLists++;
|
|---|
| 2118 | }
|
|---|
| 2119 | stylesPar->next()->ldepth = numLists;
|
|---|
| 2120 | }
|
|---|
| 2121 |
|
|---|
| 2122 | // do the top margin
|
|---|
| 2123 | QStyleSheetItem* item = mainStyle;
|
|---|
| 2124 | int m;
|
|---|
| 2125 | if (stylesPar->utm > 0 ) {
|
|---|
| 2126 | m = stylesPar->utm-1;
|
|---|
| 2127 | stylesPar->utm = 0;
|
|---|
| 2128 | } else {
|
|---|
| 2129 | m = QMAX(0, item->margin( QStyleSheetItem::MarginTop ) );
|
|---|
| 2130 | if ( stylesPar->ldepth )
|
|---|
| 2131 | if ( item->displayMode() == QStyleSheetItem::DisplayListItem )
|
|---|
| 2132 | m /= stylesPar->ldepth * stylesPar->ldepth;
|
|---|
| 2133 | else
|
|---|
| 2134 | m = 0;
|
|---|
| 2135 | }
|
|---|
| 2136 | for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
|
|---|
| 2137 | item = (*curStyle)[ i ];
|
|---|
| 2138 | if ( prevStyle && i < (int) prevStyle->size() &&
|
|---|
| 2139 | ( item->displayMode() == QStyleSheetItem::DisplayBlock &&
|
|---|
| 2140 | (*prevStyle)[ i ] == item ) )
|
|---|
| 2141 | break;
|
|---|
| 2142 | // emulate CSS2' standard 0 vertical margin for multiple ul or ol tags
|
|---|
| 2143 | if ( item->listStyle() != QStyleSheetItem::ListStyleUndefined &&
|
|---|
| 2144 | ( ( i> 0 && (*curStyle)[ i-1 ] == item ) || (*curStyle)[i+1] == item ) )
|
|---|
| 2145 | continue;
|
|---|
| 2146 | mar = QMAX( 0, item->margin( QStyleSheetItem::MarginTop ) );
|
|---|
| 2147 | m = QMAX( m, mar );
|
|---|
| 2148 | }
|
|---|
| 2149 | stylesPar->utm = m - stylesPar->topMargin();
|
|---|
| 2150 |
|
|---|
| 2151 | // do the bottom margin
|
|---|
| 2152 | item = mainStyle;
|
|---|
| 2153 | if (stylesPar->ubm > 0 ) {
|
|---|
| 2154 | m = stylesPar->ubm-1;
|
|---|
| 2155 | stylesPar->ubm = 0;
|
|---|
| 2156 | } else {
|
|---|
| 2157 | m = QMAX(0, item->margin( QStyleSheetItem::MarginBottom ) );
|
|---|
| 2158 | if ( stylesPar->ldepth )
|
|---|
| 2159 | if ( item->displayMode() == QStyleSheetItem::DisplayListItem )
|
|---|
| 2160 | m /= stylesPar->ldepth * stylesPar->ldepth;
|
|---|
| 2161 | else
|
|---|
| 2162 | m = 0;
|
|---|
| 2163 | }
|
|---|
| 2164 | for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
|
|---|
| 2165 | item = (*curStyle)[ i ];
|
|---|
| 2166 | if ( nextStyle && i < (int) nextStyle->size() &&
|
|---|
| 2167 | ( item->displayMode() == QStyleSheetItem::DisplayBlock &&
|
|---|
| 2168 | (*nextStyle)[ i ] == item ) )
|
|---|
| 2169 | break;
|
|---|
| 2170 | // emulate CSS2' standard 0 vertical margin for multiple ul or ol tags
|
|---|
| 2171 | if ( item->listStyle() != QStyleSheetItem::ListStyleUndefined &&
|
|---|
| 2172 | ( ( i> 0 && (*curStyle)[ i-1 ] == item ) || (*curStyle)[i+1] == item ) )
|
|---|
| 2173 | continue;
|
|---|
| 2174 | mar = QMAX(0, item->margin( QStyleSheetItem::MarginBottom ) );
|
|---|
| 2175 | m = QMAX( m, mar );
|
|---|
| 2176 | }
|
|---|
| 2177 | stylesPar->ubm = m - stylesPar->bottomMargin();
|
|---|
| 2178 |
|
|---|
| 2179 | // do the left margin, simplyfied
|
|---|
| 2180 | item = mainStyle;
|
|---|
| 2181 | if (stylesPar->ulm > 0 ) {
|
|---|
| 2182 | m = stylesPar->ulm-1;
|
|---|
| 2183 | stylesPar->ulm = 0;
|
|---|
| 2184 | } else {
|
|---|
| 2185 | m = QMAX( 0, item->margin( QStyleSheetItem::MarginLeft ) );
|
|---|
| 2186 | }
|
|---|
| 2187 | for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
|
|---|
| 2188 | item = (*curStyle)[ i ];
|
|---|
| 2189 | m += QMAX( 0, item->margin( QStyleSheetItem::MarginLeft ) );
|
|---|
| 2190 | }
|
|---|
| 2191 | stylesPar->ulm = m - stylesPar->leftMargin();
|
|---|
| 2192 |
|
|---|
| 2193 | // do the right margin, simplyfied
|
|---|
| 2194 | item = mainStyle;
|
|---|
| 2195 | if (stylesPar->urm > 0 ) {
|
|---|
| 2196 | m = stylesPar->urm-1;
|
|---|
| 2197 | stylesPar->urm = 0;
|
|---|
| 2198 | } else {
|
|---|
| 2199 | m = QMAX( 0, item->margin( QStyleSheetItem::MarginRight ) );
|
|---|
| 2200 | }
|
|---|
| 2201 | for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
|
|---|
| 2202 | item = (*curStyle)[ i ];
|
|---|
| 2203 | m += QMAX( 0, item->margin( QStyleSheetItem::MarginRight ) );
|
|---|
| 2204 | }
|
|---|
| 2205 | stylesPar->urm = m - stylesPar->rightMargin();
|
|---|
| 2206 |
|
|---|
| 2207 | // do the first line margin, which really should be called text-indent
|
|---|
| 2208 | item = mainStyle;
|
|---|
| 2209 | if (stylesPar->uflm > 0 ) {
|
|---|
| 2210 | m = stylesPar->uflm-1;
|
|---|
| 2211 | stylesPar->uflm = 0;
|
|---|
| 2212 | } else {
|
|---|
| 2213 | m = QMAX( 0, item->margin( QStyleSheetItem::MarginFirstLine ) );
|
|---|
| 2214 | }
|
|---|
| 2215 | for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
|
|---|
| 2216 | item = (*curStyle)[ i ];
|
|---|
| 2217 | mar = QMAX( 0, item->margin( QStyleSheetItem::MarginFirstLine ) );
|
|---|
| 2218 | m = QMAX( m, mar );
|
|---|
| 2219 | }
|
|---|
| 2220 | stylesPar->uflm =m - stylesPar->firstLineMargin();
|
|---|
| 2221 |
|
|---|
| 2222 | // do the bogus line "spacing", which really is just an extra margin
|
|---|
| 2223 | item = mainStyle;
|
|---|
| 2224 | for ( i = (int)curStyle->size() - 1 ; i >= 0; --i ) {
|
|---|
| 2225 | item = (*curStyle)[ i ];
|
|---|
| 2226 | if ( item->lineSpacing() != QStyleSheetItem::Undefined ) {
|
|---|
| 2227 | stylesPar->ulinespacing = item->lineSpacing();
|
|---|
| 2228 | if ( formatCollection() &&
|
|---|
| 2229 | stylesPar->ulinespacing < formatCollection()->defaultFormat()->height() )
|
|---|
| 2230 | stylesPar->ulinespacing += formatCollection()->defaultFormat()->height();
|
|---|
| 2231 | break;
|
|---|
| 2232 | }
|
|---|
| 2233 | }
|
|---|
| 2234 |
|
|---|
| 2235 | stylesPar = stylesPar->next();
|
|---|
| 2236 | prevStyle = curStyle;
|
|---|
| 2237 | curStyle = nextStyle;
|
|---|
| 2238 | nextStyle = styles.next();
|
|---|
| 2239 | }
|
|---|
| 2240 | }
|
|---|
| 2241 |
|
|---|
| 2242 | void QTextDocument::setText( const QString &text, const QString &context )
|
|---|
| 2243 | {
|
|---|
| 2244 | focusIndicator.parag = 0;
|
|---|
| 2245 | selections.clear();
|
|---|
| 2246 | if ( txtFormat == Qt::AutoText && QStyleSheet::mightBeRichText( text ) ||
|
|---|
| 2247 | txtFormat == Qt::RichText )
|
|---|
| 2248 | setRichText( text, context );
|
|---|
| 2249 | else
|
|---|
| 2250 | setPlainText( text );
|
|---|
| 2251 | }
|
|---|
| 2252 |
|
|---|
| 2253 | QString QTextDocument::plainText() const
|
|---|
| 2254 | {
|
|---|
| 2255 | QString buffer;
|
|---|
| 2256 | QString s;
|
|---|
| 2257 | QTextParagraph *p = fParag;
|
|---|
| 2258 | while ( p ) {
|
|---|
| 2259 | if ( !p->mightHaveCustomItems ) {
|
|---|
| 2260 | const QTextString *ts = p->string(); // workaround VC++ and Borland
|
|---|
| 2261 | s = ts->toString(); // with FALSE we don't fix spaces (nbsp)
|
|---|
| 2262 | } else {
|
|---|
| 2263 | for ( int i = 0; i < p->length() - 1; ++i ) {
|
|---|
| 2264 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 2265 | if ( p->at( i )->isCustom() ) {
|
|---|
| 2266 | if ( p->at( i )->customItem()->isNested() ) {
|
|---|
| 2267 | s += "\n";
|
|---|
| 2268 | QTextTable *t = (QTextTable*)p->at( i )->customItem();
|
|---|
| 2269 | QPtrList<QTextTableCell> cells = t->tableCells();
|
|---|
| 2270 | for ( QTextTableCell *c = cells.first(); c; c = cells.next() )
|
|---|
| 2271 | s += c->richText()->plainText() + "\n";
|
|---|
| 2272 | s += "\n";
|
|---|
| 2273 | }
|
|---|
| 2274 | } else
|
|---|
| 2275 | #endif
|
|---|
| 2276 | {
|
|---|
| 2277 | s += p->at( i )->c;
|
|---|
| 2278 | }
|
|---|
| 2279 | }
|
|---|
| 2280 | }
|
|---|
| 2281 | s.remove( s.length() - 1, 1 );
|
|---|
| 2282 | if ( p->next() )
|
|---|
| 2283 | s += "\n";
|
|---|
| 2284 | buffer += s;
|
|---|
| 2285 | p = p->next();
|
|---|
| 2286 | }
|
|---|
| 2287 | return buffer;
|
|---|
| 2288 | }
|
|---|
| 2289 |
|
|---|
| 2290 | static QString align_to_string( int a )
|
|---|
| 2291 | {
|
|---|
| 2292 | if ( a & Qt::AlignRight )
|
|---|
| 2293 | return " align=\"right\"";
|
|---|
| 2294 | if ( a & Qt::AlignHCenter )
|
|---|
| 2295 | return " align=\"center\"";
|
|---|
| 2296 | if ( a & Qt::AlignJustify )
|
|---|
| 2297 | return " align=\"justify\"";
|
|---|
| 2298 | return QString::null;
|
|---|
| 2299 | }
|
|---|
| 2300 |
|
|---|
| 2301 | static QString direction_to_string( int d )
|
|---|
| 2302 | {
|
|---|
| 2303 | if ( d != QChar::DirON )
|
|---|
| 2304 | return ( d == QChar::DirL? " dir=\"ltr\"" : " dir=\"rtl\"" );
|
|---|
| 2305 | return QString::null;
|
|---|
| 2306 | }
|
|---|
| 2307 |
|
|---|
| 2308 | static QString list_value_to_string( int v )
|
|---|
| 2309 | {
|
|---|
| 2310 | if ( v != -1 )
|
|---|
| 2311 | return " listvalue=\"" + QString::number( v ) + "\"";
|
|---|
| 2312 | return QString::null;
|
|---|
| 2313 | }
|
|---|
| 2314 |
|
|---|
| 2315 | static QString list_style_to_string( int v )
|
|---|
| 2316 | {
|
|---|
| 2317 | switch( v ) {
|
|---|
| 2318 | case QStyleSheetItem::ListDecimal: return "\"1\"";
|
|---|
| 2319 | case QStyleSheetItem::ListLowerAlpha: return "\"a\"";
|
|---|
| 2320 | case QStyleSheetItem::ListUpperAlpha: return "\"A\"";
|
|---|
| 2321 | case QStyleSheetItem::ListDisc: return "\"disc\"";
|
|---|
| 2322 | case QStyleSheetItem::ListSquare: return "\"square\"";
|
|---|
| 2323 | case QStyleSheetItem::ListCircle: return "\"circle\"";
|
|---|
| 2324 | default:
|
|---|
| 2325 | return QString::null;
|
|---|
| 2326 | }
|
|---|
| 2327 | }
|
|---|
| 2328 |
|
|---|
| 2329 | static inline bool list_is_ordered( int v )
|
|---|
| 2330 | {
|
|---|
| 2331 | return v == QStyleSheetItem::ListDecimal ||
|
|---|
| 2332 | v == QStyleSheetItem::ListLowerAlpha ||
|
|---|
| 2333 | v == QStyleSheetItem::ListUpperAlpha;
|
|---|
| 2334 | }
|
|---|
| 2335 |
|
|---|
| 2336 |
|
|---|
| 2337 | static QString margin_to_string( QStyleSheetItem* style, int t, int b, int l, int r, int fl )
|
|---|
| 2338 | {
|
|---|
| 2339 | QString s;
|
|---|
| 2340 | if ( l > 0 )
|
|---|
| 2341 | s += QString(!!s?";":"") + "margin-left:" + QString::number(l+QMAX(0,style->margin(QStyleSheetItem::MarginLeft))) + "px";
|
|---|
| 2342 | if ( r > 0 )
|
|---|
| 2343 | s += QString(!!s?";":"") + "margin-right:" + QString::number(r+QMAX(0,style->margin(QStyleSheetItem::MarginRight))) + "px";
|
|---|
| 2344 | if ( t > 0 )
|
|---|
| 2345 | s += QString(!!s?";":"") + "margin-top:" + QString::number(t+QMAX(0,style->margin(QStyleSheetItem::MarginTop))) + "px";
|
|---|
| 2346 | if ( b > 0 )
|
|---|
| 2347 | s += QString(!!s?";":"") + "margin-bottom:" + QString::number(b+QMAX(0,style->margin(QStyleSheetItem::MarginBottom))) + "px";
|
|---|
| 2348 | if ( fl > 0 )
|
|---|
| 2349 | s += QString(!!s?";":"") + "text-indent:" + QString::number(fl+QMAX(0,style->margin(QStyleSheetItem::MarginFirstLine))) + "px";
|
|---|
| 2350 | if ( !!s )
|
|---|
| 2351 | return " style=\"" + s + "\"";
|
|---|
| 2352 | return QString::null;
|
|---|
| 2353 | }
|
|---|
| 2354 |
|
|---|
| 2355 | QString QTextDocument::richText() const
|
|---|
| 2356 | {
|
|---|
| 2357 | QString s = "";
|
|---|
| 2358 | if ( !par ) {
|
|---|
| 2359 | s += "<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body style=\"font-size:" ;
|
|---|
| 2360 | s += QString::number( formatCollection()->defaultFormat()->font().pointSize() );
|
|---|
| 2361 | s += "pt;font-family:";
|
|---|
| 2362 | s += formatCollection()->defaultFormat()->font().family();
|
|---|
| 2363 | s +="\">";
|
|---|
| 2364 | }
|
|---|
| 2365 | QTextParagraph* p = fParag;
|
|---|
| 2366 |
|
|---|
| 2367 | QStyleSheetItem* item_p = styleSheet()->item("p");
|
|---|
| 2368 | QStyleSheetItem* item_div = styleSheet()->item("div");
|
|---|
| 2369 | QStyleSheetItem* item_ul = styleSheet()->item("ul");
|
|---|
| 2370 | QStyleSheetItem* item_ol = styleSheet()->item("ol");
|
|---|
| 2371 | QStyleSheetItem* item_li = styleSheet()->item("li");
|
|---|
| 2372 | if ( !item_p || !item_div || !item_ul || !item_ol || !item_li ) {
|
|---|
| 2373 | qWarning( "QTextEdit: cannot export HTML due to insufficient stylesheet (lack of p, div, ul, ol, or li)" );
|
|---|
| 2374 | return QString::null;
|
|---|
| 2375 | }
|
|---|
| 2376 | int pastListDepth = 0;
|
|---|
| 2377 | int listDepth = 0;
|
|---|
| 2378 | #if 0
|
|---|
| 2379 | int futureListDepth = 0;
|
|---|
| 2380 | #endif
|
|---|
| 2381 | QMemArray<int> listStyles(10);
|
|---|
| 2382 |
|
|---|
| 2383 | while ( p ) {
|
|---|
| 2384 | listDepth = p->listDepth();
|
|---|
| 2385 | if ( listDepth < pastListDepth ) {
|
|---|
| 2386 | for ( int i = pastListDepth; i > listDepth; i-- )
|
|---|
| 2387 | s += list_is_ordered( listStyles[i] ) ? "</ol>" : "</ul>";
|
|---|
| 2388 | s += '\n';
|
|---|
| 2389 | } else if ( listDepth > pastListDepth ) {
|
|---|
| 2390 | s += '\n';
|
|---|
| 2391 | listStyles.resize( QMAX( (int)listStyles.size(), listDepth+1 ) );
|
|---|
| 2392 | QString list_type;
|
|---|
| 2393 | listStyles[listDepth] = p->listStyle();
|
|---|
| 2394 | if ( !list_is_ordered( p->listStyle() ) || item_ol->listStyle() != p->listStyle() )
|
|---|
| 2395 | list_type = " type=" + list_style_to_string( p->listStyle() );
|
|---|
| 2396 | for ( int i = pastListDepth; i < listDepth; i++ ) {
|
|---|
| 2397 | s += list_is_ordered( p->listStyle() ) ? "<ol" : "<ul" ;
|
|---|
| 2398 | s += list_type + ">";
|
|---|
| 2399 | }
|
|---|
| 2400 | } else {
|
|---|
| 2401 | s += '\n';
|
|---|
| 2402 | }
|
|---|
| 2403 |
|
|---|
| 2404 | QString ps = p->richText();
|
|---|
| 2405 |
|
|---|
| 2406 | #if 0
|
|---|
| 2407 | // for the bottom margin we need to know whether we are at the end of a list
|
|---|
| 2408 | futureListDepth = 0;
|
|---|
| 2409 | if ( listDepth > 0 && p->next() )
|
|---|
| 2410 | futureListDepth = p->next()->listDepth();
|
|---|
| 2411 | #endif
|
|---|
| 2412 |
|
|---|
| 2413 | if ( richTextExportStart && richTextExportStart->paragraph() ==p &&
|
|---|
| 2414 | richTextExportStart->index() == 0 )
|
|---|
| 2415 | s += "<!--StartFragment-->";
|
|---|
| 2416 |
|
|---|
| 2417 | if ( p->isListItem() ) {
|
|---|
| 2418 | s += "<li";
|
|---|
| 2419 | if ( p->listStyle() != listStyles[listDepth] )
|
|---|
| 2420 | s += " type=" + list_style_to_string( p->listStyle() );
|
|---|
| 2421 | s +=align_to_string( p->alignment() );
|
|---|
| 2422 | s += margin_to_string( item_li, p->utm, p->ubm, p->ulm, p->urm, p->uflm );
|
|---|
| 2423 | s += list_value_to_string( p->listValue() );
|
|---|
| 2424 | s += direction_to_string( p->direction() );
|
|---|
| 2425 | s +=">";
|
|---|
| 2426 | s += ps;
|
|---|
| 2427 | s += "</li>";
|
|---|
| 2428 | } else if ( p->listDepth() ) {
|
|---|
| 2429 | s += "<div";
|
|---|
| 2430 | s += align_to_string( p->alignment() );
|
|---|
| 2431 | s += margin_to_string( item_div, p->utm, p->ubm, p->ulm, p->urm, p->uflm );
|
|---|
| 2432 | s +=direction_to_string( p->direction() );
|
|---|
| 2433 | s += ">";
|
|---|
| 2434 | s += ps;
|
|---|
| 2435 | s += "</div>";
|
|---|
| 2436 | } else {
|
|---|
| 2437 | // normal paragraph item
|
|---|
| 2438 | s += "<p";
|
|---|
| 2439 | s += align_to_string( p->alignment() );
|
|---|
| 2440 | s += margin_to_string( item_p, p->utm, p->ubm, p->ulm, p->urm, p->uflm );
|
|---|
| 2441 | s +=direction_to_string( p->direction() );
|
|---|
| 2442 | s += ">";
|
|---|
| 2443 | s += ps;
|
|---|
| 2444 | s += "</p>";
|
|---|
| 2445 | }
|
|---|
| 2446 | pastListDepth = listDepth;
|
|---|
| 2447 | p = p->next();
|
|---|
| 2448 | }
|
|---|
| 2449 | while ( listDepth > 0 ) {
|
|---|
| 2450 | s += list_is_ordered( listStyles[listDepth] ) ? "</ol>" : "</ul>";
|
|---|
| 2451 | listDepth--;
|
|---|
| 2452 | }
|
|---|
| 2453 |
|
|---|
| 2454 | if ( !par )
|
|---|
| 2455 | s += "\n</body></html>\n";
|
|---|
| 2456 |
|
|---|
| 2457 | return s;
|
|---|
| 2458 | }
|
|---|
| 2459 |
|
|---|
| 2460 | QString QTextDocument::text() const
|
|---|
| 2461 | {
|
|---|
| 2462 | if ( txtFormat == Qt::AutoText && preferRichText || txtFormat == Qt::RichText )
|
|---|
| 2463 | return richText();
|
|---|
| 2464 | return plainText();
|
|---|
| 2465 | }
|
|---|
| 2466 |
|
|---|
| 2467 | QString QTextDocument::text( int parag ) const
|
|---|
| 2468 | {
|
|---|
| 2469 | QTextParagraph *p = paragAt( parag );
|
|---|
| 2470 | if ( !p )
|
|---|
| 2471 | return QString::null;
|
|---|
| 2472 |
|
|---|
| 2473 | if ( txtFormat == Qt::AutoText && preferRichText || txtFormat == Qt::RichText )
|
|---|
| 2474 | return p->richText();
|
|---|
| 2475 | else
|
|---|
| 2476 | return p->string()->toString();
|
|---|
| 2477 | }
|
|---|
| 2478 |
|
|---|
| 2479 | void QTextDocument::invalidate()
|
|---|
| 2480 | {
|
|---|
| 2481 | QTextParagraph *s = fParag;
|
|---|
| 2482 | while ( s ) {
|
|---|
| 2483 | s->invalidate( 0 );
|
|---|
| 2484 | s = s->next();
|
|---|
| 2485 | }
|
|---|
| 2486 | }
|
|---|
| 2487 |
|
|---|
| 2488 | void QTextDocument::selectionStart( int id, int ¶gId, int &index )
|
|---|
| 2489 | {
|
|---|
| 2490 | QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
|
|---|
| 2491 | if ( it == selections.end() )
|
|---|
| 2492 | return;
|
|---|
| 2493 | QTextDocumentSelection &sel = *it;
|
|---|
| 2494 | paragId = !sel.swapped ? sel.startCursor.paragraph()->paragId() : sel.endCursor.paragraph()->paragId();
|
|---|
| 2495 | index = !sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
|
|---|
| 2496 | }
|
|---|
| 2497 |
|
|---|
| 2498 | QTextCursor QTextDocument::selectionStartCursor( int id)
|
|---|
| 2499 | {
|
|---|
| 2500 | QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
|
|---|
| 2501 | if ( it == selections.end() )
|
|---|
| 2502 | return QTextCursor( this );
|
|---|
| 2503 | QTextDocumentSelection &sel = *it;
|
|---|
| 2504 | if ( sel.swapped )
|
|---|
| 2505 | return sel.endCursor;
|
|---|
| 2506 | return sel.startCursor;
|
|---|
| 2507 | }
|
|---|
| 2508 |
|
|---|
| 2509 | QTextCursor QTextDocument::selectionEndCursor( int id)
|
|---|
| 2510 | {
|
|---|
| 2511 | QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
|
|---|
| 2512 | if ( it == selections.end() )
|
|---|
| 2513 | return QTextCursor( this );
|
|---|
| 2514 | QTextDocumentSelection &sel = *it;
|
|---|
| 2515 | if ( !sel.swapped )
|
|---|
| 2516 | return sel.endCursor;
|
|---|
| 2517 | return sel.startCursor;
|
|---|
| 2518 | }
|
|---|
| 2519 |
|
|---|
| 2520 | void QTextDocument::selectionEnd( int id, int ¶gId, int &index )
|
|---|
| 2521 | {
|
|---|
| 2522 | QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
|
|---|
| 2523 | if ( it == selections.end() )
|
|---|
| 2524 | return;
|
|---|
| 2525 | QTextDocumentSelection &sel = *it;
|
|---|
| 2526 | paragId = sel.swapped ? sel.startCursor.paragraph()->paragId() : sel.endCursor.paragraph()->paragId();
|
|---|
| 2527 | index = sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
|
|---|
| 2528 | }
|
|---|
| 2529 |
|
|---|
| 2530 | void QTextDocument::addSelection( int id )
|
|---|
| 2531 | {
|
|---|
| 2532 | nSelections = QMAX( nSelections, id + 1 );
|
|---|
| 2533 | }
|
|---|
| 2534 |
|
|---|
| 2535 | static void setSelectionEndHelper( int id, QTextDocumentSelection &sel, QTextCursor &start, QTextCursor &end )
|
|---|
| 2536 | {
|
|---|
| 2537 | QTextCursor c1 = start;
|
|---|
| 2538 | QTextCursor c2 = end;
|
|---|
| 2539 | if ( sel.swapped ) {
|
|---|
| 2540 | c1 = end;
|
|---|
| 2541 | c2 = start;
|
|---|
| 2542 | }
|
|---|
| 2543 |
|
|---|
| 2544 | c1.paragraph()->removeSelection( id );
|
|---|
| 2545 | c2.paragraph()->removeSelection( id );
|
|---|
| 2546 | if ( c1.paragraph() != c2.paragraph() ) {
|
|---|
| 2547 | c1.paragraph()->setSelection( id, c1.index(), c1.paragraph()->length() - 1 );
|
|---|
| 2548 | c2.paragraph()->setSelection( id, 0, c2.index() );
|
|---|
| 2549 | } else {
|
|---|
| 2550 | c1.paragraph()->setSelection( id, QMIN( c1.index(), c2.index() ), QMAX( c1.index(), c2.index() ) );
|
|---|
| 2551 | }
|
|---|
| 2552 |
|
|---|
| 2553 | sel.startCursor = start;
|
|---|
| 2554 | sel.endCursor = end;
|
|---|
| 2555 | if ( sel.startCursor.paragraph() == sel.endCursor.paragraph() )
|
|---|
| 2556 | sel.swapped = sel.startCursor.index() > sel.endCursor.index();
|
|---|
| 2557 | }
|
|---|
| 2558 |
|
|---|
| 2559 | bool QTextDocument::setSelectionEnd( int id, const QTextCursor &cursor )
|
|---|
| 2560 | {
|
|---|
| 2561 | QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
|
|---|
| 2562 | if ( it == selections.end() )
|
|---|
| 2563 | return FALSE;
|
|---|
| 2564 | QTextDocumentSelection &sel = *it;
|
|---|
| 2565 |
|
|---|
| 2566 | QTextCursor start = sel.startCursor;
|
|---|
| 2567 | QTextCursor end = cursor;
|
|---|
| 2568 |
|
|---|
| 2569 | if ( start == end ) {
|
|---|
| 2570 | removeSelection( id );
|
|---|
| 2571 | setSelectionStart( id, cursor );
|
|---|
| 2572 | return TRUE;
|
|---|
| 2573 | }
|
|---|
| 2574 |
|
|---|
| 2575 | if ( sel.endCursor.paragraph() == end.paragraph() ) {
|
|---|
| 2576 | setSelectionEndHelper( id, sel, start, end );
|
|---|
| 2577 | return TRUE;
|
|---|
| 2578 | }
|
|---|
| 2579 |
|
|---|
| 2580 | bool inSelection = FALSE;
|
|---|
| 2581 | QTextCursor c( this );
|
|---|
| 2582 | QTextCursor tmp = sel.startCursor;
|
|---|
| 2583 | if ( sel.swapped )
|
|---|
| 2584 | tmp = sel.endCursor;
|
|---|
| 2585 | tmp.restoreState();
|
|---|
| 2586 | QTextCursor tmp2 = cursor;
|
|---|
| 2587 | tmp2.restoreState();
|
|---|
| 2588 | c.setParagraph( tmp.paragraph()->paragId() < tmp2.paragraph()->paragId() ? tmp.paragraph() : tmp2.paragraph() );
|
|---|
| 2589 | bool hadStart = FALSE;
|
|---|
| 2590 | bool hadEnd = FALSE;
|
|---|
| 2591 | bool hadStartParag = FALSE;
|
|---|
| 2592 | bool hadEndParag = FALSE;
|
|---|
| 2593 | bool hadOldStart = FALSE;
|
|---|
| 2594 | bool hadOldEnd = FALSE;
|
|---|
| 2595 | bool leftSelection = FALSE;
|
|---|
| 2596 | sel.swapped = FALSE;
|
|---|
| 2597 | for ( ;; ) {
|
|---|
| 2598 | if ( c == start )
|
|---|
| 2599 | hadStart = TRUE;
|
|---|
| 2600 | if ( c == end )
|
|---|
| 2601 | hadEnd = TRUE;
|
|---|
| 2602 | if ( c.paragraph() == start.paragraph() )
|
|---|
| 2603 | hadStartParag = TRUE;
|
|---|
| 2604 | if ( c.paragraph() == end.paragraph() )
|
|---|
| 2605 | hadEndParag = TRUE;
|
|---|
| 2606 | if ( c == sel.startCursor )
|
|---|
| 2607 | hadOldStart = TRUE;
|
|---|
| 2608 | if ( c == sel.endCursor )
|
|---|
| 2609 | hadOldEnd = TRUE;
|
|---|
| 2610 |
|
|---|
| 2611 | if ( !sel.swapped &&
|
|---|
| 2612 | ( hadEnd && !hadStart ||
|
|---|
| 2613 | hadEnd && hadStart && start.paragraph() == end.paragraph() && start.index() > end.index() ) )
|
|---|
| 2614 | sel.swapped = TRUE;
|
|---|
| 2615 |
|
|---|
| 2616 | if ( c == end && hadStartParag ||
|
|---|
| 2617 | c == start && hadEndParag ) {
|
|---|
| 2618 | QTextCursor tmp = c;
|
|---|
| 2619 | tmp.restoreState();
|
|---|
| 2620 | if ( tmp.paragraph() != c.paragraph() ) {
|
|---|
| 2621 | int sstart = tmp.paragraph()->selectionStart( id );
|
|---|
| 2622 | tmp.paragraph()->removeSelection( id );
|
|---|
| 2623 | tmp.paragraph()->setSelection( id, sstart, tmp.index() );
|
|---|
| 2624 | }
|
|---|
| 2625 | }
|
|---|
| 2626 |
|
|---|
| 2627 | if ( inSelection &&
|
|---|
| 2628 | ( c == end && hadStart || c == start && hadEnd ) )
|
|---|
| 2629 | leftSelection = TRUE;
|
|---|
| 2630 | else if ( !leftSelection && !inSelection && ( hadStart || hadEnd ) )
|
|---|
| 2631 | inSelection = TRUE;
|
|---|
| 2632 |
|
|---|
| 2633 | bool noSelectionAnymore = hadOldStart && hadOldEnd && leftSelection && !inSelection && !c.paragraph()->hasSelection( id ) && c.atParagEnd();
|
|---|
| 2634 | c.paragraph()->removeSelection( id );
|
|---|
| 2635 | if ( inSelection ) {
|
|---|
| 2636 | if ( c.paragraph() == start.paragraph() && start.paragraph() == end.paragraph() ) {
|
|---|
| 2637 | c.paragraph()->setSelection( id, QMIN( start.index(), end.index() ), QMAX( start.index(), end.index() ) );
|
|---|
| 2638 | } else if ( c.paragraph() == start.paragraph() && !hadEndParag ) {
|
|---|
| 2639 | c.paragraph()->setSelection( id, start.index(), c.paragraph()->length() - 1 );
|
|---|
| 2640 | } else if ( c.paragraph() == end.paragraph() && !hadStartParag ) {
|
|---|
| 2641 | c.paragraph()->setSelection( id, end.index(), c.paragraph()->length() - 1 );
|
|---|
| 2642 | } else if ( c.paragraph() == end.paragraph() && hadEndParag ) {
|
|---|
| 2643 | c.paragraph()->setSelection( id, 0, end.index() );
|
|---|
| 2644 | } else if ( c.paragraph() == start.paragraph() && hadStartParag ) {
|
|---|
| 2645 | c.paragraph()->setSelection( id, 0, start.index() );
|
|---|
| 2646 | } else {
|
|---|
| 2647 | c.paragraph()->setSelection( id, 0, c.paragraph()->length() - 1 );
|
|---|
| 2648 | }
|
|---|
| 2649 | }
|
|---|
| 2650 |
|
|---|
| 2651 | if ( leftSelection )
|
|---|
| 2652 | inSelection = FALSE;
|
|---|
| 2653 |
|
|---|
| 2654 | if ( noSelectionAnymore )
|
|---|
| 2655 | break;
|
|---|
| 2656 | // *ugle*hack optimization
|
|---|
| 2657 | QTextParagraph *p = c.paragraph();
|
|---|
| 2658 | if ( p->mightHaveCustomItems || p == start.paragraph() || p == end.paragraph() || p == lastParagraph() ) {
|
|---|
| 2659 | c.gotoNextLetter();
|
|---|
| 2660 | if ( p == lastParagraph() && c.atParagEnd() )
|
|---|
| 2661 | break;
|
|---|
| 2662 | } else {
|
|---|
| 2663 | if ( p->document()->parent() )
|
|---|
| 2664 | do {
|
|---|
| 2665 | c.gotoNextLetter();
|
|---|
| 2666 | } while ( c.paragraph() == p );
|
|---|
| 2667 | else
|
|---|
| 2668 | c.setParagraph( p->next() );
|
|---|
| 2669 | }
|
|---|
| 2670 | }
|
|---|
| 2671 |
|
|---|
| 2672 | if ( !sel.swapped )
|
|---|
| 2673 | sel.startCursor.paragraph()->setSelection( id, sel.startCursor.index(), sel.startCursor.paragraph()->length() - 1 );
|
|---|
| 2674 |
|
|---|
| 2675 | sel.startCursor = start;
|
|---|
| 2676 | sel.endCursor = end;
|
|---|
| 2677 | if ( sel.startCursor.paragraph() == sel.endCursor.paragraph() )
|
|---|
| 2678 | sel.swapped = sel.startCursor.index() > sel.endCursor.index();
|
|---|
| 2679 |
|
|---|
| 2680 | setSelectionEndHelper( id, sel, start, end );
|
|---|
| 2681 |
|
|---|
| 2682 | return TRUE;
|
|---|
| 2683 | }
|
|---|
| 2684 |
|
|---|
| 2685 | void QTextDocument::selectAll( int id )
|
|---|
| 2686 | {
|
|---|
| 2687 | removeSelection( id );
|
|---|
| 2688 |
|
|---|
| 2689 | QTextDocumentSelection sel;
|
|---|
| 2690 | sel.swapped = FALSE;
|
|---|
| 2691 | QTextCursor c( this );
|
|---|
| 2692 |
|
|---|
| 2693 | c.setParagraph( fParag );
|
|---|
| 2694 | c.setIndex( 0 );
|
|---|
| 2695 | sel.startCursor = c;
|
|---|
| 2696 |
|
|---|
| 2697 | c.setParagraph( lParag );
|
|---|
| 2698 | c.setIndex( lParag->length() - 1 );
|
|---|
| 2699 | sel.endCursor = c;
|
|---|
| 2700 |
|
|---|
| 2701 | selections.insert( id, sel );
|
|---|
| 2702 |
|
|---|
| 2703 | QTextParagraph *p = fParag;
|
|---|
| 2704 | while ( p ) {
|
|---|
| 2705 | p->setSelection( id, 0, p->length() - 1 );
|
|---|
| 2706 | p = p->next();
|
|---|
| 2707 | }
|
|---|
| 2708 |
|
|---|
| 2709 | for ( QTextDocument *d = childList.first(); d; d = childList.next() )
|
|---|
| 2710 | d->selectAll( id );
|
|---|
| 2711 | }
|
|---|
| 2712 |
|
|---|
| 2713 | bool QTextDocument::removeSelection( int id )
|
|---|
| 2714 | {
|
|---|
| 2715 | if ( !selections.contains( id ) )
|
|---|
| 2716 | return FALSE;
|
|---|
| 2717 |
|
|---|
| 2718 | QTextDocumentSelection &sel = selections[ id ];
|
|---|
| 2719 |
|
|---|
| 2720 | QTextCursor start = sel.swapped ? sel.endCursor : sel.startCursor;
|
|---|
| 2721 | QTextCursor end = sel.swapped ? sel.startCursor : sel.endCursor;
|
|---|
| 2722 | QTextParagraph* p = 0;
|
|---|
| 2723 | while ( start != end ) {
|
|---|
| 2724 | if ( p != start.paragraph() ) {
|
|---|
| 2725 | p = start.paragraph();
|
|---|
| 2726 | p->removeSelection( id );
|
|---|
| 2727 | //### avoid endless loop by all means necessary, did somebody mention refactoring?
|
|---|
| 2728 | if ( !parent() && p == lParag )
|
|---|
| 2729 | break;
|
|---|
| 2730 | }
|
|---|
| 2731 | start.gotoNextLetter();
|
|---|
| 2732 | }
|
|---|
| 2733 | p = start.paragraph();
|
|---|
| 2734 | p->removeSelection( id );
|
|---|
| 2735 | selections.remove( id );
|
|---|
| 2736 | return TRUE;
|
|---|
| 2737 | }
|
|---|
| 2738 |
|
|---|
| 2739 | QString QTextDocument::selectedText( int id, bool asRichText ) const
|
|---|
| 2740 | {
|
|---|
| 2741 | QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( id );
|
|---|
| 2742 | if ( it == selections.end() )
|
|---|
| 2743 | return QString::null;
|
|---|
| 2744 |
|
|---|
| 2745 | QTextDocumentSelection sel = *it;
|
|---|
| 2746 |
|
|---|
| 2747 |
|
|---|
| 2748 | QTextCursor c1 = sel.startCursor;
|
|---|
| 2749 | QTextCursor c2 = sel.endCursor;
|
|---|
| 2750 | if ( sel.swapped ) {
|
|---|
| 2751 | c2 = sel.startCursor;
|
|---|
| 2752 | c1 = sel.endCursor;
|
|---|
| 2753 | }
|
|---|
| 2754 |
|
|---|
| 2755 | /* 3.0.3 improvement: Make it possible to get a reasonable
|
|---|
| 2756 | selection inside a table. This approach is very conservative:
|
|---|
| 2757 | make sure that both cursors have the same depth level and point
|
|---|
| 2758 | to paragraphs within the same text document.
|
|---|
| 2759 |
|
|---|
| 2760 | Meaning if you select text in two table cells, you will get the
|
|---|
| 2761 | entire table. This is still far better than the 3.0.2, where
|
|---|
| 2762 | you always got the entire table.
|
|---|
| 2763 |
|
|---|
| 2764 | ### Fix this properly when refactoring
|
|---|
| 2765 | */
|
|---|
| 2766 | while ( c2.nestedDepth() > c1.nestedDepth() )
|
|---|
| 2767 | c2.oneUp();
|
|---|
| 2768 | while ( c1.nestedDepth() > c2.nestedDepth() )
|
|---|
| 2769 | c1.oneUp();
|
|---|
| 2770 | while ( c1.nestedDepth() && c2.nestedDepth() &&
|
|---|
| 2771 | c1.paragraph()->document() != c2.paragraph()->document() ) {
|
|---|
| 2772 | c1.oneUp();
|
|---|
| 2773 | c2.oneUp();
|
|---|
| 2774 | }
|
|---|
| 2775 | // do not trust sel_swapped with tables. Fix this properly when refactoring as well
|
|---|
| 2776 | if ( c1.paragraph()->paragId() > c2.paragraph()->paragId() ||
|
|---|
| 2777 | (c1.paragraph() == c2.paragraph() && c1.index() > c2.index() ) ) {
|
|---|
| 2778 | QTextCursor tmp = c1;
|
|---|
| 2779 | c2 = c1;
|
|---|
| 2780 | c1 = tmp;
|
|---|
| 2781 | }
|
|---|
| 2782 |
|
|---|
| 2783 | // end selection 3.0.3 improvement
|
|---|
| 2784 |
|
|---|
| 2785 | if ( asRichText && !parent() ) {
|
|---|
| 2786 | richTextExportStart = &c1;
|
|---|
| 2787 | richTextExportEnd = &c2;
|
|---|
| 2788 |
|
|---|
| 2789 | QString sel = richText();
|
|---|
| 2790 | int from = sel.find( "<!--StartFragment-->" );
|
|---|
| 2791 | if ( from >= 0 ) {
|
|---|
| 2792 | from += 20;
|
|---|
| 2793 | // find the previous span and move it into the start fragment before we clip it
|
|---|
| 2794 | QString prevspan;
|
|---|
| 2795 | int pspan = sel.findRev( "<span", from-21 );
|
|---|
| 2796 | if ( pspan > sel.findRev( "</span", from-21 ) ) {
|
|---|
| 2797 | int spanend = sel.find( '>', pspan );
|
|---|
| 2798 | prevspan = sel.mid( pspan, spanend - pspan + 1 );
|
|---|
| 2799 | }
|
|---|
| 2800 | int to = sel.findRev( "<!--EndFragment-->" );
|
|---|
| 2801 | if ( from <= to )
|
|---|
| 2802 | sel = "<!--StartFragment-->" + prevspan + sel.mid( from, to - from );
|
|---|
| 2803 | }
|
|---|
| 2804 | richTextExportStart = richTextExportEnd = 0;
|
|---|
| 2805 | return sel;
|
|---|
| 2806 | }
|
|---|
| 2807 |
|
|---|
| 2808 | QString s;
|
|---|
| 2809 | if ( c1.paragraph() == c2.paragraph() ) {
|
|---|
| 2810 | QTextParagraph *p = c1.paragraph();
|
|---|
| 2811 | int end = c2.index();
|
|---|
| 2812 | if ( p->at( QMAX( 0, end - 1 ) )->isCustom() )
|
|---|
| 2813 | ++end;
|
|---|
| 2814 | if ( !p->mightHaveCustomItems ) {
|
|---|
| 2815 | s += p->string()->toString().mid( c1.index(), end - c1.index() );
|
|---|
| 2816 | } else {
|
|---|
| 2817 | for ( int i = c1.index(); i < end; ++i ) {
|
|---|
| 2818 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 2819 | if ( p->at( i )->isCustom() ) {
|
|---|
| 2820 | if ( p->at( i )->customItem()->isNested() ) {
|
|---|
| 2821 | s += "\n";
|
|---|
| 2822 | QTextTable *t = (QTextTable*)p->at( i )->customItem();
|
|---|
| 2823 | QPtrList<QTextTableCell> cells = t->tableCells();
|
|---|
| 2824 | for ( QTextTableCell *c = cells.first(); c; c = cells.next() )
|
|---|
| 2825 | s += c->richText()->plainText() + "\n";
|
|---|
| 2826 | s += "\n";
|
|---|
| 2827 | }
|
|---|
| 2828 | } else
|
|---|
| 2829 | #endif
|
|---|
| 2830 | {
|
|---|
| 2831 | s += p->at( i )->c;
|
|---|
| 2832 | }
|
|---|
| 2833 | }
|
|---|
| 2834 | }
|
|---|
| 2835 | } else {
|
|---|
| 2836 | QTextParagraph *p = c1.paragraph();
|
|---|
| 2837 | int start = c1.index();
|
|---|
| 2838 | while ( p ) {
|
|---|
| 2839 | int end = p == c2.paragraph() ? c2.index() : p->length() - 1;
|
|---|
| 2840 | if ( p == c2.paragraph() && p->at( QMAX( 0, end - 1 ) )->isCustom() )
|
|---|
| 2841 | ++end;
|
|---|
| 2842 | if ( !p->mightHaveCustomItems ) {
|
|---|
| 2843 | s += p->string()->toString().mid( start, end - start );
|
|---|
| 2844 | if ( p != c2.paragraph() )
|
|---|
| 2845 | s += "\n";
|
|---|
| 2846 | } else {
|
|---|
| 2847 | for ( int i = start; i < end; ++i ) {
|
|---|
| 2848 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 2849 | if ( p->at( i )->isCustom() ) {
|
|---|
| 2850 | if ( p->at( i )->customItem()->isNested() ) {
|
|---|
| 2851 | s += "\n";
|
|---|
| 2852 | QTextTable *t = (QTextTable*)p->at( i )->customItem();
|
|---|
| 2853 | QPtrList<QTextTableCell> cells = t->tableCells();
|
|---|
| 2854 | for ( QTextTableCell *c = cells.first(); c; c = cells.next() )
|
|---|
| 2855 | s += c->richText()->plainText() + "\n";
|
|---|
| 2856 | s += "\n";
|
|---|
| 2857 | }
|
|---|
| 2858 | } else
|
|---|
| 2859 | #endif
|
|---|
| 2860 | {
|
|---|
| 2861 | s += p->at( i )->c;
|
|---|
| 2862 | }
|
|---|
| 2863 | }
|
|---|
| 2864 | }
|
|---|
| 2865 | start = 0;
|
|---|
| 2866 | if ( p == c2.paragraph() )
|
|---|
| 2867 | break;
|
|---|
| 2868 | p = p->next();
|
|---|
| 2869 | }
|
|---|
| 2870 | }
|
|---|
| 2871 | // ### workaround for plain text export until we get proper
|
|---|
| 2872 | // mime types: turn unicode line seperators into the more
|
|---|
| 2873 | // widely understood \n. Makes copy and pasting code snipplets
|
|---|
| 2874 | // from within Assistent possible
|
|---|
| 2875 | QChar* uc = (QChar*) s.unicode();
|
|---|
| 2876 | for ( uint ii = 0; ii < s.length(); ii++ )
|
|---|
| 2877 | if ( uc[(int)ii] == QChar_linesep )
|
|---|
| 2878 | uc[(int)ii] = QChar('\n');
|
|---|
| 2879 | return s;
|
|---|
| 2880 | }
|
|---|
| 2881 |
|
|---|
| 2882 | void QTextDocument::setFormat( int id, QTextFormat *f, int flags )
|
|---|
| 2883 | {
|
|---|
| 2884 | QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( id );
|
|---|
| 2885 | if ( it == selections.end() )
|
|---|
| 2886 | return;
|
|---|
| 2887 |
|
|---|
| 2888 | QTextDocumentSelection sel = *it;
|
|---|
| 2889 |
|
|---|
| 2890 | QTextCursor c1 = sel.startCursor;
|
|---|
| 2891 | QTextCursor c2 = sel.endCursor;
|
|---|
| 2892 | if ( sel.swapped ) {
|
|---|
| 2893 | c2 = sel.startCursor;
|
|---|
| 2894 | c1 = sel.endCursor;
|
|---|
| 2895 | }
|
|---|
| 2896 |
|
|---|
| 2897 | c2.restoreState();
|
|---|
| 2898 | c1.restoreState();
|
|---|
| 2899 |
|
|---|
| 2900 | if ( c1.paragraph() == c2.paragraph() ) {
|
|---|
| 2901 | c1.paragraph()->setFormat( c1.index(), c2.index() - c1.index(), f, TRUE, flags );
|
|---|
| 2902 | return;
|
|---|
| 2903 | }
|
|---|
| 2904 |
|
|---|
| 2905 | c1.paragraph()->setFormat( c1.index(), c1.paragraph()->length() - c1.index(), f, TRUE, flags );
|
|---|
| 2906 | QTextParagraph *p = c1.paragraph()->next();
|
|---|
| 2907 | while ( p && p != c2.paragraph() ) {
|
|---|
| 2908 | p->setFormat( 0, p->length(), f, TRUE, flags );
|
|---|
| 2909 | p = p->next();
|
|---|
| 2910 | }
|
|---|
| 2911 | c2.paragraph()->setFormat( 0, c2.index(), f, TRUE, flags );
|
|---|
| 2912 | }
|
|---|
| 2913 |
|
|---|
| 2914 | void QTextDocument::removeSelectedText( int id, QTextCursor *cursor )
|
|---|
| 2915 | {
|
|---|
| 2916 | QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
|
|---|
| 2917 | if ( it == selections.end() )
|
|---|
| 2918 | return;
|
|---|
| 2919 |
|
|---|
| 2920 | QTextDocumentSelection sel = *it;
|
|---|
| 2921 | QTextCursor c1 = sel.startCursor;
|
|---|
| 2922 | QTextCursor c2 = sel.endCursor;
|
|---|
| 2923 | if ( sel.swapped ) {
|
|---|
| 2924 | c2 = sel.startCursor;
|
|---|
| 2925 | c1 = sel.endCursor;
|
|---|
| 2926 | }
|
|---|
| 2927 |
|
|---|
| 2928 | // ### no support for editing tables yet
|
|---|
| 2929 | if ( c1.nestedDepth() || c2.nestedDepth() )
|
|---|
| 2930 | return;
|
|---|
| 2931 |
|
|---|
| 2932 | c2.restoreState();
|
|---|
| 2933 | c1.restoreState();
|
|---|
| 2934 |
|
|---|
| 2935 | *cursor = c1;
|
|---|
| 2936 | removeSelection( id );
|
|---|
| 2937 |
|
|---|
| 2938 | if ( c1.paragraph() == c2.paragraph() ) {
|
|---|
| 2939 | c1.paragraph()->remove( c1.index(), c2.index() - c1.index() );
|
|---|
| 2940 | return;
|
|---|
| 2941 | }
|
|---|
| 2942 |
|
|---|
| 2943 | if ( c1.paragraph() == fParag && c1.index() == 0 &&
|
|---|
| 2944 | c2.paragraph() == lParag && c2.index() == lParag->length() - 1 )
|
|---|
| 2945 | cursor->setValid( FALSE );
|
|---|
| 2946 |
|
|---|
| 2947 | bool didGoLeft = FALSE;
|
|---|
| 2948 | if ( c1.index() == 0 && c1.paragraph() != fParag ) {
|
|---|
| 2949 | cursor->gotoPreviousLetter();
|
|---|
| 2950 | didGoLeft = cursor->isValid();
|
|---|
| 2951 | }
|
|---|
| 2952 |
|
|---|
| 2953 | c1.paragraph()->remove( c1.index(), c1.paragraph()->length() - 1 - c1.index() );
|
|---|
| 2954 | QTextParagraph *p = c1.paragraph()->next();
|
|---|
| 2955 | int dy = 0;
|
|---|
| 2956 | QTextParagraph *tmp;
|
|---|
| 2957 | while ( p && p != c2.paragraph() ) {
|
|---|
| 2958 | tmp = p->next();
|
|---|
| 2959 | dy -= p->rect().height();
|
|---|
| 2960 | delete p;
|
|---|
| 2961 | p = tmp;
|
|---|
| 2962 | }
|
|---|
| 2963 | c2.paragraph()->remove( 0, c2.index() );
|
|---|
| 2964 | while ( p ) {
|
|---|
| 2965 | p->move( dy );
|
|---|
| 2966 | p->invalidate( 0 );
|
|---|
| 2967 | p->setEndState( -1 );
|
|---|
| 2968 | p = p->next();
|
|---|
| 2969 | }
|
|---|
| 2970 |
|
|---|
| 2971 |
|
|---|
| 2972 | c1.paragraph()->join( c2.paragraph() );
|
|---|
| 2973 |
|
|---|
| 2974 | if ( didGoLeft )
|
|---|
| 2975 | cursor->gotoNextLetter();
|
|---|
| 2976 | }
|
|---|
| 2977 |
|
|---|
| 2978 | void QTextDocument::indentSelection( int id )
|
|---|
| 2979 | {
|
|---|
| 2980 | QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
|
|---|
| 2981 | if ( it == selections.end() )
|
|---|
| 2982 | return;
|
|---|
| 2983 |
|
|---|
| 2984 | QTextDocumentSelection sel = *it;
|
|---|
| 2985 | QTextParagraph *startParag = sel.startCursor.paragraph();
|
|---|
| 2986 | QTextParagraph *endParag = sel.endCursor.paragraph();
|
|---|
| 2987 | if ( sel.endCursor.paragraph()->paragId() < sel.startCursor.paragraph()->paragId() ) {
|
|---|
| 2988 | endParag = sel.startCursor.paragraph();
|
|---|
| 2989 | startParag = sel.endCursor.paragraph();
|
|---|
| 2990 | }
|
|---|
| 2991 |
|
|---|
| 2992 | QTextParagraph *p = startParag;
|
|---|
| 2993 | while ( p && p != endParag ) {
|
|---|
| 2994 | p->indent();
|
|---|
| 2995 | p = p->next();
|
|---|
| 2996 | }
|
|---|
| 2997 | }
|
|---|
| 2998 |
|
|---|
| 2999 | void QTextDocument::addCommand( QTextCommand *cmd )
|
|---|
| 3000 | {
|
|---|
| 3001 | commandHistory->addCommand( cmd );
|
|---|
| 3002 | }
|
|---|
| 3003 |
|
|---|
| 3004 | QTextCursor *QTextDocument::undo( QTextCursor *c )
|
|---|
| 3005 | {
|
|---|
| 3006 | return commandHistory->undo( c );
|
|---|
| 3007 | }
|
|---|
| 3008 |
|
|---|
| 3009 | QTextCursor *QTextDocument::redo( QTextCursor *c )
|
|---|
| 3010 | {
|
|---|
| 3011 | return commandHistory->redo( c );
|
|---|
| 3012 | }
|
|---|
| 3013 |
|
|---|
| 3014 | bool QTextDocument::find( QTextCursor& cursor, const QString &expr, bool cs, bool wo, bool forward )
|
|---|
| 3015 | {
|
|---|
| 3016 | removeSelection( Standard );
|
|---|
| 3017 | QTextParagraph *p = 0;
|
|---|
| 3018 | if ( expr.isEmpty() )
|
|---|
| 3019 | return FALSE;
|
|---|
| 3020 | for (;;) {
|
|---|
| 3021 | if ( p != cursor.paragraph() ) {
|
|---|
| 3022 | p = cursor.paragraph();
|
|---|
| 3023 | QString s = cursor.paragraph()->string()->toString();
|
|---|
| 3024 | int start = cursor.index();
|
|---|
| 3025 | for ( ;; ) {
|
|---|
| 3026 | int res = forward ? s.find( expr, start, cs ) : s.findRev( expr, start, cs );
|
|---|
| 3027 | int end = res + expr.length();
|
|---|
| 3028 | if ( res == -1 || ( !forward && start <= res ) )
|
|---|
| 3029 | break;
|
|---|
| 3030 | if ( !wo || ( ( res == 0 || s[ res - 1 ].isSpace() || s[ res - 1 ].isPunct() ) &&
|
|---|
| 3031 | ( end == (int)s.length() || s[ end ].isSpace() || s[ end ].isPunct() ) ) ) {
|
|---|
| 3032 | removeSelection( Standard );
|
|---|
| 3033 | cursor.setIndex( forward ? end : res );
|
|---|
| 3034 | setSelectionStart( Standard, cursor );
|
|---|
| 3035 | cursor.setIndex( forward ? res : end );
|
|---|
| 3036 | setSelectionEnd( Standard, cursor );
|
|---|
| 3037 | if ( !forward )
|
|---|
| 3038 | cursor.setIndex( res );
|
|---|
| 3039 | return TRUE;
|
|---|
| 3040 | }
|
|---|
| 3041 | start = res + (forward ? 1 : -1);
|
|---|
| 3042 | }
|
|---|
| 3043 | }
|
|---|
| 3044 | if ( forward ) {
|
|---|
| 3045 | if ( cursor.paragraph() == lastParagraph() && cursor.atParagEnd() )
|
|---|
| 3046 | break;
|
|---|
| 3047 | cursor.gotoNextLetter();
|
|---|
| 3048 | } else {
|
|---|
| 3049 | if ( cursor.paragraph() == firstParagraph() && cursor.atParagStart() )
|
|---|
| 3050 | break;
|
|---|
| 3051 | cursor.gotoPreviousLetter();
|
|---|
| 3052 | }
|
|---|
| 3053 | }
|
|---|
| 3054 | return FALSE;
|
|---|
| 3055 | }
|
|---|
| 3056 |
|
|---|
| 3057 | void QTextDocument::setTextFormat( Qt::TextFormat f )
|
|---|
| 3058 | {
|
|---|
| 3059 | txtFormat = f;
|
|---|
| 3060 | if ( fParag == lParag && fParag->length() <= 1 )
|
|---|
| 3061 | fParag->rtext = ( f == Qt::RichText );
|
|---|
| 3062 | }
|
|---|
| 3063 |
|
|---|
| 3064 | Qt::TextFormat QTextDocument::textFormat() const
|
|---|
| 3065 | {
|
|---|
| 3066 | return txtFormat;
|
|---|
| 3067 | }
|
|---|
| 3068 |
|
|---|
| 3069 | bool QTextDocument::inSelection( int selId, const QPoint &pos ) const
|
|---|
| 3070 | {
|
|---|
| 3071 | QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( selId );
|
|---|
| 3072 | if ( it == selections.end() )
|
|---|
| 3073 | return FALSE;
|
|---|
| 3074 |
|
|---|
| 3075 | QTextDocumentSelection sel = *it;
|
|---|
| 3076 | QTextParagraph *startParag = sel.startCursor.paragraph();
|
|---|
| 3077 | QTextParagraph *endParag = sel.endCursor.paragraph();
|
|---|
| 3078 | if ( sel.startCursor.paragraph() == sel.endCursor.paragraph() &&
|
|---|
| 3079 | sel.startCursor.paragraph()->selectionStart( selId ) == sel.endCursor.paragraph()->selectionEnd( selId ) )
|
|---|
| 3080 | return FALSE;
|
|---|
| 3081 | if ( sel.endCursor.paragraph()->paragId() < sel.startCursor.paragraph()->paragId() ) {
|
|---|
| 3082 | endParag = sel.startCursor.paragraph();
|
|---|
| 3083 | startParag = sel.endCursor.paragraph();
|
|---|
| 3084 | }
|
|---|
| 3085 |
|
|---|
| 3086 | QTextParagraph *p = startParag;
|
|---|
| 3087 | while ( p ) {
|
|---|
| 3088 | if ( p->rect().contains( pos ) ) {
|
|---|
| 3089 | bool inSel = FALSE;
|
|---|
| 3090 | int selStart = p->selectionStart( selId );
|
|---|
| 3091 | int selEnd = p->selectionEnd( selId );
|
|---|
| 3092 | int y = 0;
|
|---|
| 3093 | int h = 0;
|
|---|
| 3094 | for ( int i = 0; i < p->length(); ++i ) {
|
|---|
| 3095 | if ( i == selStart )
|
|---|
| 3096 | inSel = TRUE;
|
|---|
| 3097 | if ( i == selEnd )
|
|---|
| 3098 | break;
|
|---|
| 3099 | if ( p->at( i )->lineStart ) {
|
|---|
| 3100 | y = (*p->lineStarts.find( i ))->y;
|
|---|
| 3101 | h = (*p->lineStarts.find( i ))->h;
|
|---|
| 3102 | }
|
|---|
| 3103 | if ( pos.y() - p->rect().y() >= y && pos.y() - p->rect().y() <= y + h ) {
|
|---|
| 3104 | if ( inSel && pos.x() >= p->at( i )->x &&
|
|---|
| 3105 | pos.x() <= p->at( i )->x + p->at( i )->format()->width( p->at( i )->c ) )
|
|---|
| 3106 | return TRUE;
|
|---|
| 3107 | }
|
|---|
| 3108 | }
|
|---|
| 3109 | }
|
|---|
| 3110 | if ( pos.y() < p->rect().y() )
|
|---|
| 3111 | break;
|
|---|
| 3112 | if ( p == endParag )
|
|---|
| 3113 | break;
|
|---|
| 3114 | p = p->next();
|
|---|
| 3115 | }
|
|---|
| 3116 |
|
|---|
| 3117 | return FALSE;
|
|---|
| 3118 | }
|
|---|
| 3119 |
|
|---|
| 3120 | void QTextDocument::doLayout( QPainter *p, int w )
|
|---|
| 3121 | {
|
|---|
| 3122 | minw = wused = 0;
|
|---|
| 3123 | if ( !is_printer( p ) )
|
|---|
| 3124 | p = 0;
|
|---|
| 3125 | withoutDoubleBuffer = ( p != 0 );
|
|---|
| 3126 | QPainter * oldPainter = QTextFormat::painter();
|
|---|
| 3127 | QTextFormat::setPainter( p );
|
|---|
| 3128 | flow_->setWidth( w );
|
|---|
| 3129 | cw = w;
|
|---|
| 3130 | vw = w;
|
|---|
| 3131 | QTextParagraph *parag = fParag;
|
|---|
| 3132 | while ( parag ) {
|
|---|
| 3133 | parag->invalidate( 0 );
|
|---|
| 3134 | if ( p )
|
|---|
| 3135 | parag->adjustToPainter( p );
|
|---|
| 3136 | parag->format();
|
|---|
| 3137 | parag = parag->next();
|
|---|
| 3138 | }
|
|---|
| 3139 | QTextFormat::setPainter( oldPainter );
|
|---|
| 3140 | }
|
|---|
| 3141 |
|
|---|
| 3142 | QPixmap *QTextDocument::bufferPixmap( const QSize &s )
|
|---|
| 3143 | {
|
|---|
| 3144 | if ( !buf_pixmap )
|
|---|
| 3145 | buf_pixmap = new QPixmap( s.expandedTo( QSize(1,1) ) );
|
|---|
| 3146 | else if ( buf_pixmap->size() != s )
|
|---|
| 3147 | buf_pixmap->resize( s.expandedTo( buf_pixmap->size() ) );
|
|---|
| 3148 | return buf_pixmap;
|
|---|
| 3149 | }
|
|---|
| 3150 |
|
|---|
| 3151 | void QTextDocument::draw( QPainter *p, const QRect &rect, const QColorGroup &cg, const QBrush *paper )
|
|---|
| 3152 | {
|
|---|
| 3153 | if ( !firstParagraph() )
|
|---|
| 3154 | return;
|
|---|
| 3155 |
|
|---|
| 3156 | if ( paper ) {
|
|---|
| 3157 | p->setBrushOrigin( -int( p->translationX() ),
|
|---|
| 3158 | -int( p->translationY() ) );
|
|---|
| 3159 |
|
|---|
| 3160 | p->fillRect( rect, *paper );
|
|---|
| 3161 | }
|
|---|
| 3162 |
|
|---|
| 3163 | QPainter * oldPainter = QTextFormat::painter();
|
|---|
| 3164 | QTextFormat::setPainter( p );
|
|---|
| 3165 |
|
|---|
| 3166 | if ( formatCollection()->defaultFormat()->color() != cg.text() )
|
|---|
| 3167 | setDefaultFormat( formatCollection()->defaultFormat()->font(), cg.text() );
|
|---|
| 3168 |
|
|---|
| 3169 | QTextParagraph *parag = firstParagraph();
|
|---|
| 3170 | while ( parag ) {
|
|---|
| 3171 | if ( !parag->isValid() )
|
|---|
| 3172 | parag->format();
|
|---|
| 3173 | int y = parag->rect().y();
|
|---|
| 3174 | QRect pr( parag->rect() );
|
|---|
| 3175 | pr.setX( 0 );
|
|---|
| 3176 | pr.setWidth( QWIDGETSIZE_MAX );
|
|---|
| 3177 | if ( !rect.isNull() && !rect.intersects( pr ) ) {
|
|---|
| 3178 | parag = parag->next();
|
|---|
| 3179 | continue;
|
|---|
| 3180 | }
|
|---|
| 3181 | p->translate( 0, y );
|
|---|
| 3182 | if ( rect.isValid() )
|
|---|
| 3183 | parag->paint( *p, cg, 0, FALSE, rect.x(), rect.y(), rect.width(), rect.height() );
|
|---|
| 3184 | else
|
|---|
| 3185 | parag->paint( *p, cg, 0, FALSE );
|
|---|
| 3186 | p->translate( 0, -y );
|
|---|
| 3187 | parag = parag->next();
|
|---|
| 3188 | if ( !flow()->isEmpty() )
|
|---|
| 3189 | flow()->drawFloatingItems( p, rect.x(), rect.y(), rect.width(), rect.height(), cg, FALSE );
|
|---|
| 3190 | }
|
|---|
| 3191 | QTextFormat::setPainter(oldPainter);
|
|---|
| 3192 | }
|
|---|
| 3193 |
|
|---|
| 3194 | void QTextDocument::drawParagraph( QPainter *p, QTextParagraph *parag, int cx, int cy, int cw, int ch,
|
|---|
| 3195 | QPixmap *&doubleBuffer, const QColorGroup &cg,
|
|---|
| 3196 | bool drawCursor, QTextCursor *cursor, bool resetChanged )
|
|---|
| 3197 | {
|
|---|
| 3198 | QPainter *painter = 0;
|
|---|
| 3199 | if ( resetChanged )
|
|---|
| 3200 | parag->setChanged( FALSE );
|
|---|
| 3201 | QRect ir( parag->rect() );
|
|---|
| 3202 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 3203 | if (!parag->tableCell())
|
|---|
| 3204 | #endif
|
|---|
| 3205 | ir.setWidth(width());
|
|---|
| 3206 |
|
|---|
| 3207 | bool uDoubleBuffer = useDoubleBuffer( parag, p );
|
|---|
| 3208 |
|
|---|
| 3209 | if ( uDoubleBuffer ) {
|
|---|
| 3210 | painter = new QPainter;
|
|---|
| 3211 | if ( cx >= 0 && cy >= 0 )
|
|---|
| 3212 | ir = ir.intersect( QRect( cx, cy, cw, ch ) );
|
|---|
| 3213 | if ( !doubleBuffer ||
|
|---|
| 3214 | ir.width() > doubleBuffer->width() ||
|
|---|
| 3215 | ir.height() > doubleBuffer->height() ) {
|
|---|
| 3216 | doubleBuffer = bufferPixmap( ir.size() );
|
|---|
| 3217 | painter->begin( doubleBuffer );
|
|---|
| 3218 | } else {
|
|---|
| 3219 | painter->begin( doubleBuffer );
|
|---|
| 3220 | }
|
|---|
| 3221 | } else {
|
|---|
| 3222 | painter = p;
|
|---|
| 3223 | painter->translate( ir.x(), ir.y() );
|
|---|
| 3224 | }
|
|---|
| 3225 |
|
|---|
| 3226 | painter->setBrushOrigin( -ir.x(), -ir.y() );
|
|---|
| 3227 |
|
|---|
| 3228 | if ( uDoubleBuffer || is_printer( painter ) )
|
|---|
| 3229 | painter->fillRect( QRect( 0, 0, ir.width(), ir.height() ), parag->backgroundBrush( cg ) );
|
|---|
| 3230 | else if ( cursor && cursor->paragraph() == parag )
|
|---|
| 3231 | painter->fillRect( QRect( parag->at( cursor->index() )->x, 0, 2, ir.height() ),
|
|---|
| 3232 | parag->backgroundBrush( cg ) );
|
|---|
| 3233 |
|
|---|
| 3234 | painter->translate( -( ir.x() - parag->rect().x() ),
|
|---|
| 3235 | -( ir.y() - parag->rect().y() ) );
|
|---|
| 3236 | parag->paint( *painter, cg, drawCursor ? cursor : 0, TRUE, cx, cy, cw, ch );
|
|---|
| 3237 |
|
|---|
| 3238 | if ( uDoubleBuffer ) {
|
|---|
| 3239 | delete painter;
|
|---|
| 3240 | painter = 0;
|
|---|
| 3241 | p->drawPixmap( ir.topLeft(), *doubleBuffer, QRect( QPoint( 0, 0 ), ir.size() ) );
|
|---|
| 3242 | } else {
|
|---|
| 3243 | painter->translate( -ir.x(), -ir.y() );
|
|---|
| 3244 | }
|
|---|
| 3245 |
|
|---|
| 3246 | parag->document()->nextDoubleBuffered = FALSE;
|
|---|
| 3247 | }
|
|---|
| 3248 |
|
|---|
| 3249 | QTextParagraph *QTextDocument::draw( QPainter *p, int cx, int cy, int cw, int ch, const QColorGroup &cg,
|
|---|
| 3250 | bool onlyChanged, bool drawCursor, QTextCursor *cursor, bool resetChanged )
|
|---|
| 3251 | {
|
|---|
| 3252 | if ( withoutDoubleBuffer || par && par->withoutDoubleBuffer ) {
|
|---|
| 3253 | withoutDoubleBuffer = TRUE;
|
|---|
| 3254 | QRect r;
|
|---|
| 3255 | draw( p, r, cg );
|
|---|
| 3256 | return 0;
|
|---|
| 3257 | }
|
|---|
| 3258 | withoutDoubleBuffer = FALSE;
|
|---|
| 3259 |
|
|---|
| 3260 | if ( !firstParagraph() )
|
|---|
| 3261 | return 0;
|
|---|
| 3262 |
|
|---|
| 3263 | QPainter * oldPainter = QTextFormat::painter();
|
|---|
| 3264 | QTextFormat::setPainter( p );
|
|---|
| 3265 | if ( formatCollection()->defaultFormat()->color() != cg.text() )
|
|---|
| 3266 | setDefaultFormat( formatCollection()->defaultFormat()->font(), cg.text() );
|
|---|
| 3267 |
|
|---|
| 3268 | if ( cx < 0 && cy < 0 ) {
|
|---|
| 3269 | cx = 0;
|
|---|
| 3270 | cy = 0;
|
|---|
| 3271 | cw = width();
|
|---|
| 3272 | ch = height();
|
|---|
| 3273 | }
|
|---|
| 3274 |
|
|---|
| 3275 | QTextParagraph *lastFormatted = 0;
|
|---|
| 3276 | QTextParagraph *parag = firstParagraph();
|
|---|
| 3277 |
|
|---|
| 3278 | QPixmap *doubleBuffer = 0;
|
|---|
| 3279 |
|
|---|
| 3280 | while ( parag ) {
|
|---|
| 3281 | lastFormatted = parag;
|
|---|
| 3282 | if ( !parag->isValid() )
|
|---|
| 3283 | parag->format();
|
|---|
| 3284 |
|
|---|
| 3285 | QRect pr = parag->rect();
|
|---|
| 3286 | pr.setWidth( parag->document()->width() );
|
|---|
| 3287 | if ( pr.y() > cy + ch )
|
|---|
| 3288 | goto floating;
|
|---|
| 3289 | QRect clipr( cx, cy, cw, ch );
|
|---|
| 3290 | if ( !pr.intersects( clipr ) || ( onlyChanged && !parag->hasChanged() ) ) {
|
|---|
| 3291 | pr.setWidth( parag->document()->width() );
|
|---|
| 3292 | parag = parag->next();
|
|---|
| 3293 | continue;
|
|---|
| 3294 | }
|
|---|
| 3295 |
|
|---|
| 3296 | drawParagraph( p, parag, cx, cy, cw, ch, doubleBuffer, cg, drawCursor, cursor, resetChanged );
|
|---|
| 3297 | parag = parag->next();
|
|---|
| 3298 | }
|
|---|
| 3299 |
|
|---|
| 3300 | parag = lastParagraph();
|
|---|
| 3301 |
|
|---|
| 3302 | floating:
|
|---|
| 3303 | if ( parag->rect().y() + parag->rect().height() < parag->document()->height() ) {
|
|---|
| 3304 | if ( !parag->document()->parent() ) {
|
|---|
| 3305 | QRect fillRect = QRect( 0, parag->rect().y() + parag->rect().height(), parag->document()->width(),
|
|---|
| 3306 | parag->document()->height() - ( parag->rect().y() + parag->rect().height() ) );
|
|---|
| 3307 | if ( QRect( cx, cy, cw, ch ).intersects( fillRect ) )
|
|---|
| 3308 | p->fillRect( fillRect, cg.brush( QColorGroup::Base ) );
|
|---|
| 3309 | }
|
|---|
| 3310 | if ( !flow()->isEmpty() ) {
|
|---|
| 3311 | QRect cr( cx, cy, cw, ch );
|
|---|
| 3312 | flow()->drawFloatingItems( p, cr.x(), cr.y(), cr.width(), cr.height(), cg, FALSE );
|
|---|
| 3313 | }
|
|---|
| 3314 | }
|
|---|
| 3315 |
|
|---|
| 3316 | if ( buf_pixmap && buf_pixmap->height() > 300 ) {
|
|---|
| 3317 | delete buf_pixmap;
|
|---|
| 3318 | buf_pixmap = 0;
|
|---|
| 3319 | }
|
|---|
| 3320 |
|
|---|
| 3321 | QTextFormat::setPainter(oldPainter);
|
|---|
| 3322 | return lastFormatted;
|
|---|
| 3323 | }
|
|---|
| 3324 |
|
|---|
| 3325 | /*
|
|---|
| 3326 | #### this function only sets the default font size in the format collection
|
|---|
| 3327 | */
|
|---|
| 3328 | void QTextDocument::setDefaultFormat( const QFont &font, const QColor &color )
|
|---|
| 3329 | {
|
|---|
| 3330 | bool reformat = font != fCollection->defaultFormat()->font();
|
|---|
| 3331 | for ( QTextDocument *d = childList.first(); d; d = childList.next() )
|
|---|
| 3332 | d->setDefaultFormat( font, color );
|
|---|
| 3333 | fCollection->updateDefaultFormat( font, color, sheet_ );
|
|---|
| 3334 |
|
|---|
| 3335 | if ( !reformat )
|
|---|
| 3336 | return;
|
|---|
| 3337 | tStopWidth = formatCollection()->defaultFormat()->width( 'x' ) * 8;
|
|---|
| 3338 |
|
|---|
| 3339 | // invalidate paragraphs and custom items
|
|---|
| 3340 | QTextParagraph *p = fParag;
|
|---|
| 3341 | while ( p ) {
|
|---|
| 3342 | p->invalidate( 0 );
|
|---|
| 3343 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 3344 | for ( int i = 0; i < p->length() - 1; ++i )
|
|---|
| 3345 | if ( p->at( i )->isCustom() )
|
|---|
| 3346 | p->at( i )->customItem()->invalidate();
|
|---|
| 3347 | #endif
|
|---|
| 3348 | p = p->next();
|
|---|
| 3349 | }
|
|---|
| 3350 | }
|
|---|
| 3351 |
|
|---|
| 3352 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 3353 | void QTextDocument::registerCustomItem( QTextCustomItem *i, QTextParagraph *p )
|
|---|
| 3354 | {
|
|---|
| 3355 | if ( i && i->placement() != QTextCustomItem::PlaceInline ) {
|
|---|
| 3356 | flow_->registerFloatingItem( i );
|
|---|
| 3357 | p->registerFloatingItem( i );
|
|---|
| 3358 | i->setParagraph( p );
|
|---|
| 3359 | }
|
|---|
| 3360 | p->mightHaveCustomItems = mightHaveCustomItems = TRUE;
|
|---|
| 3361 | }
|
|---|
| 3362 |
|
|---|
| 3363 | void QTextDocument::unregisterCustomItem( QTextCustomItem *i, QTextParagraph *p )
|
|---|
| 3364 | {
|
|---|
| 3365 | p->unregisterFloatingItem( i );
|
|---|
| 3366 | i->setParagraph( 0 );
|
|---|
| 3367 | flow_->unregisterFloatingItem( i );
|
|---|
| 3368 | }
|
|---|
| 3369 | #endif
|
|---|
| 3370 |
|
|---|
| 3371 | bool QTextDocument::hasFocusParagraph() const
|
|---|
| 3372 | {
|
|---|
| 3373 | return !!focusIndicator.parag;
|
|---|
| 3374 | }
|
|---|
| 3375 |
|
|---|
| 3376 | QString QTextDocument::focusHref() const
|
|---|
| 3377 | {
|
|---|
| 3378 | return focusIndicator.href;
|
|---|
| 3379 | }
|
|---|
| 3380 |
|
|---|
| 3381 | QString QTextDocument::focusName() const
|
|---|
| 3382 | {
|
|---|
| 3383 | return focusIndicator.name;
|
|---|
| 3384 | }
|
|---|
| 3385 |
|
|---|
| 3386 | bool QTextDocument::focusNextPrevChild( bool next )
|
|---|
| 3387 | {
|
|---|
| 3388 | if ( !focusIndicator.parag ) {
|
|---|
| 3389 | if ( next ) {
|
|---|
| 3390 | focusIndicator.parag = fParag;
|
|---|
| 3391 | focusIndicator.start = 0;
|
|---|
| 3392 | focusIndicator.len = 0;
|
|---|
| 3393 | } else {
|
|---|
| 3394 | focusIndicator.parag = lParag;
|
|---|
| 3395 | focusIndicator.start = lParag->length();
|
|---|
| 3396 | focusIndicator.len = 0;
|
|---|
| 3397 | }
|
|---|
| 3398 | } else {
|
|---|
| 3399 | focusIndicator.parag->setChanged( TRUE );
|
|---|
| 3400 | }
|
|---|
| 3401 | focusIndicator.href = QString::null;
|
|---|
| 3402 | focusIndicator.name = QString::null;
|
|---|
| 3403 |
|
|---|
| 3404 | if ( next ) {
|
|---|
| 3405 | QTextParagraph *p = focusIndicator.parag;
|
|---|
| 3406 | int index = focusIndicator.start + focusIndicator.len;
|
|---|
| 3407 | while ( p ) {
|
|---|
| 3408 | for ( int i = index; i < p->length(); ++i ) {
|
|---|
| 3409 | if ( p->at( i )->isAnchor() ) {
|
|---|
| 3410 | p->setChanged( TRUE );
|
|---|
| 3411 | focusIndicator.parag = p;
|
|---|
| 3412 | focusIndicator.start = i;
|
|---|
| 3413 | focusIndicator.len = 0;
|
|---|
| 3414 | focusIndicator.href = p->at( i )->anchorHref();
|
|---|
| 3415 | focusIndicator.name = p->at( i )->anchorName();
|
|---|
| 3416 | while ( i < p->length() ) {
|
|---|
| 3417 | if ( !p->at( i )->isAnchor() )
|
|---|
| 3418 | return TRUE;
|
|---|
| 3419 | focusIndicator.len++;
|
|---|
| 3420 | i++;
|
|---|
| 3421 | }
|
|---|
| 3422 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 3423 | } else if ( p->at( i )->isCustom() ) {
|
|---|
| 3424 | if ( p->at( i )->customItem()->isNested() ) {
|
|---|
| 3425 | QTextTable *t = (QTextTable*)p->at( i )->customItem();
|
|---|
| 3426 | QPtrList<QTextTableCell> cells = t->tableCells();
|
|---|
| 3427 | // first try to continue
|
|---|
| 3428 | QTextTableCell *c;
|
|---|
| 3429 | bool resetCells = TRUE;
|
|---|
| 3430 | for ( c = cells.first(); c; c = cells.next() ) {
|
|---|
| 3431 | if ( c->richText()->hasFocusParagraph() ) {
|
|---|
| 3432 | if ( c->richText()->focusNextPrevChild( next ) ) {
|
|---|
| 3433 | p->setChanged( TRUE );
|
|---|
| 3434 | focusIndicator.parag = p;
|
|---|
| 3435 | focusIndicator.start = i;
|
|---|
| 3436 | focusIndicator.len = 0;
|
|---|
| 3437 | focusIndicator.href = c->richText()->focusHref();
|
|---|
| 3438 | focusIndicator.name = c->richText()->focusName();
|
|---|
| 3439 | return TRUE;
|
|---|
| 3440 | } else {
|
|---|
| 3441 | resetCells = FALSE;
|
|---|
| 3442 | c = cells.next();
|
|---|
| 3443 | break;
|
|---|
| 3444 | }
|
|---|
| 3445 | }
|
|---|
| 3446 | }
|
|---|
| 3447 | // now really try
|
|---|
| 3448 | if ( resetCells )
|
|---|
| 3449 | c = cells.first();
|
|---|
| 3450 | for ( ; c; c = cells.next() ) {
|
|---|
| 3451 | if ( c->richText()->focusNextPrevChild( next ) ) {
|
|---|
| 3452 | p->setChanged( TRUE );
|
|---|
| 3453 | focusIndicator.parag = p;
|
|---|
| 3454 | focusIndicator.start = i;
|
|---|
| 3455 | focusIndicator.len = 0;
|
|---|
| 3456 | focusIndicator.href = c->richText()->focusHref();
|
|---|
| 3457 | focusIndicator.name = c->richText()->focusName();
|
|---|
| 3458 | return TRUE;
|
|---|
| 3459 | }
|
|---|
| 3460 | }
|
|---|
| 3461 | }
|
|---|
| 3462 | #endif
|
|---|
| 3463 | }
|
|---|
| 3464 | }
|
|---|
| 3465 | index = 0;
|
|---|
| 3466 | p = p->next();
|
|---|
| 3467 | }
|
|---|
| 3468 | } else {
|
|---|
| 3469 | QTextParagraph *p = focusIndicator.parag;
|
|---|
| 3470 | int index = focusIndicator.start - 1;
|
|---|
| 3471 | if ( focusIndicator.len == 0 && index < focusIndicator.parag->length() - 1 )
|
|---|
| 3472 | index++;
|
|---|
| 3473 | while ( p ) {
|
|---|
| 3474 | for ( int i = index; i >= 0; --i ) {
|
|---|
| 3475 | if ( p->at( i )->isAnchor() ) {
|
|---|
| 3476 | p->setChanged( TRUE );
|
|---|
| 3477 | focusIndicator.parag = p;
|
|---|
| 3478 | focusIndicator.start = i;
|
|---|
| 3479 | focusIndicator.len = 0;
|
|---|
| 3480 | focusIndicator.href = p->at( i )->anchorHref();
|
|---|
| 3481 | focusIndicator.name = p->at( i )->anchorName();
|
|---|
| 3482 | while ( i >= -1 ) {
|
|---|
| 3483 | if ( i < 0 || !p->at( i )->isAnchor() ) {
|
|---|
| 3484 | focusIndicator.start++;
|
|---|
| 3485 | return TRUE;
|
|---|
| 3486 | }
|
|---|
| 3487 | if ( i < 0 )
|
|---|
| 3488 | break;
|
|---|
| 3489 | focusIndicator.len++;
|
|---|
| 3490 | focusIndicator.start--;
|
|---|
| 3491 | i--;
|
|---|
| 3492 | }
|
|---|
| 3493 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 3494 | } else if ( p->at( i )->isCustom() ) {
|
|---|
| 3495 | if ( p->at( i )->customItem()->isNested() ) {
|
|---|
| 3496 | QTextTable *t = (QTextTable*)p->at( i )->customItem();
|
|---|
| 3497 | QPtrList<QTextTableCell> cells = t->tableCells();
|
|---|
| 3498 | // first try to continue
|
|---|
| 3499 | QTextTableCell *c;
|
|---|
| 3500 | bool resetCells = TRUE;
|
|---|
| 3501 | for ( c = cells.last(); c; c = cells.prev() ) {
|
|---|
| 3502 | if ( c->richText()->hasFocusParagraph() ) {
|
|---|
| 3503 | if ( c->richText()->focusNextPrevChild( next ) ) {
|
|---|
| 3504 | p->setChanged( TRUE );
|
|---|
| 3505 | focusIndicator.parag = p;
|
|---|
| 3506 | focusIndicator.start = i;
|
|---|
| 3507 | focusIndicator.len = 0;
|
|---|
| 3508 | focusIndicator.href = c->richText()->focusHref();
|
|---|
| 3509 | focusIndicator.name = c->richText()->focusName();
|
|---|
| 3510 | return TRUE;
|
|---|
| 3511 | } else {
|
|---|
| 3512 | resetCells = FALSE;
|
|---|
| 3513 | c = cells.prev();
|
|---|
| 3514 | break;
|
|---|
| 3515 | }
|
|---|
| 3516 | }
|
|---|
| 3517 | if ( cells.at() == 0 )
|
|---|
| 3518 | break;
|
|---|
| 3519 | }
|
|---|
| 3520 | // now really try
|
|---|
| 3521 | if ( resetCells )
|
|---|
| 3522 | c = cells.last();
|
|---|
| 3523 | for ( ; c; c = cells.prev() ) {
|
|---|
| 3524 | if ( c->richText()->focusNextPrevChild( next ) ) {
|
|---|
| 3525 | p->setChanged( TRUE );
|
|---|
| 3526 | focusIndicator.parag = p;
|
|---|
| 3527 | focusIndicator.start = i;
|
|---|
| 3528 | focusIndicator.len = 0;
|
|---|
| 3529 | focusIndicator.href = c->richText()->focusHref();
|
|---|
| 3530 | focusIndicator.name = c->richText()->focusName();
|
|---|
| 3531 | return TRUE;
|
|---|
| 3532 | }
|
|---|
| 3533 | if ( cells.at() == 0 )
|
|---|
| 3534 | break;
|
|---|
| 3535 | }
|
|---|
| 3536 | }
|
|---|
| 3537 | #endif
|
|---|
| 3538 | }
|
|---|
| 3539 | }
|
|---|
| 3540 | p = p->prev();
|
|---|
| 3541 | if ( p )
|
|---|
| 3542 | index = p->length() - 1;
|
|---|
| 3543 | }
|
|---|
| 3544 | }
|
|---|
| 3545 |
|
|---|
| 3546 | focusIndicator.parag = 0;
|
|---|
| 3547 |
|
|---|
| 3548 | return FALSE;
|
|---|
| 3549 | }
|
|---|
| 3550 |
|
|---|
| 3551 | int QTextDocument::length() const
|
|---|
| 3552 | {
|
|---|
| 3553 | int l = -1;
|
|---|
| 3554 | QTextParagraph *p = fParag;
|
|---|
| 3555 | while ( p ) {
|
|---|
| 3556 | l += p->length();
|
|---|
| 3557 | p = p->next();
|
|---|
| 3558 | }
|
|---|
| 3559 | return QMAX(0,l);
|
|---|
| 3560 | }
|
|---|
| 3561 |
|
|---|
| 3562 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 3563 |
|
|---|
| 3564 | int QTextFormat::width( const QChar &c ) const
|
|---|
| 3565 | {
|
|---|
| 3566 | if ( c.unicode() == 0xad ) // soft hyphen
|
|---|
| 3567 | return 0;
|
|---|
| 3568 | if ( !pntr || !pntr->isActive() ) {
|
|---|
| 3569 | if ( c == '\t' )
|
|---|
| 3570 | return fm.width( ' ' );
|
|---|
| 3571 | if ( ha == AlignNormal ) {
|
|---|
| 3572 | int w;
|
|---|
| 3573 | if ( c.row() )
|
|---|
| 3574 | w = fm.width( c );
|
|---|
| 3575 | else
|
|---|
| 3576 | w = widths[ c.unicode() ];
|
|---|
| 3577 | if ( w == 0 && !c.row() ) {
|
|---|
| 3578 | w = fm.width( c );
|
|---|
| 3579 | ( (QTextFormat*)this )->widths[ c.unicode() ] = w;
|
|---|
| 3580 | }
|
|---|
| 3581 | return w;
|
|---|
| 3582 | } else {
|
|---|
| 3583 | QFont f( fn );
|
|---|
| 3584 | if ( usePixelSizes )
|
|---|
| 3585 | f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
|
|---|
| 3586 | else
|
|---|
| 3587 | f.setPointSize( ( f.pointSize() * 2 ) / 3 );
|
|---|
| 3588 | QFontMetrics fm_( f );
|
|---|
| 3589 | return fm_.width( c );
|
|---|
| 3590 | }
|
|---|
| 3591 | }
|
|---|
| 3592 |
|
|---|
| 3593 | QFont f( fn );
|
|---|
| 3594 | if ( ha != AlignNormal ) {
|
|---|
| 3595 | if ( usePixelSizes )
|
|---|
| 3596 | f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
|
|---|
| 3597 | else
|
|---|
| 3598 | f.setPointSize( ( f.pointSize() * 2 ) / 3 );
|
|---|
| 3599 | }
|
|---|
| 3600 | applyFont( f );
|
|---|
| 3601 |
|
|---|
| 3602 | return pntr_fm->width( c );
|
|---|
| 3603 | }
|
|---|
| 3604 |
|
|---|
| 3605 | int QTextFormat::width( const QString &str, int pos ) const
|
|---|
| 3606 | {
|
|---|
| 3607 | int w = 0;
|
|---|
| 3608 | if ( str.unicode()[ pos ].unicode() == 0xad )
|
|---|
| 3609 | return w;
|
|---|
| 3610 | if ( !pntr || !pntr->isActive() ) {
|
|---|
| 3611 | if ( ha == AlignNormal ) {
|
|---|
| 3612 | w = fm.charWidth( str, pos );
|
|---|
| 3613 | } else {
|
|---|
| 3614 | QFont f( fn );
|
|---|
| 3615 | if ( usePixelSizes )
|
|---|
| 3616 | f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
|
|---|
| 3617 | else
|
|---|
| 3618 | f.setPointSize( ( f.pointSize() * 2 ) / 3 );
|
|---|
| 3619 | QFontMetrics fm_( f );
|
|---|
| 3620 | w = fm_.charWidth( str, pos );
|
|---|
| 3621 | }
|
|---|
| 3622 | } else {
|
|---|
| 3623 | QFont f( fn );
|
|---|
| 3624 | if ( ha != AlignNormal ) {
|
|---|
| 3625 | if ( usePixelSizes )
|
|---|
| 3626 | f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
|
|---|
| 3627 | else
|
|---|
| 3628 | f.setPointSize( ( f.pointSize() * 2 ) / 3 );
|
|---|
| 3629 | }
|
|---|
| 3630 | applyFont( f );
|
|---|
| 3631 | w = pntr_fm->charWidth( str, pos );
|
|---|
| 3632 | }
|
|---|
| 3633 | return w;
|
|---|
| 3634 | }
|
|---|
| 3635 |
|
|---|
| 3636 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 3637 |
|
|---|
| 3638 | QTextString::QTextString()
|
|---|
| 3639 | {
|
|---|
| 3640 | bidiDirty = TRUE;
|
|---|
| 3641 | bidi = FALSE;
|
|---|
| 3642 | rightToLeft = FALSE;
|
|---|
| 3643 | dir = QChar::DirON;
|
|---|
| 3644 | }
|
|---|
| 3645 |
|
|---|
| 3646 | QTextString::QTextString( const QTextString &s )
|
|---|
| 3647 | {
|
|---|
| 3648 | bidiDirty = TRUE;
|
|---|
| 3649 | bidi = s.bidi;
|
|---|
| 3650 | rightToLeft = s.rightToLeft;
|
|---|
| 3651 | dir = s.dir;
|
|---|
| 3652 | data = s.data;
|
|---|
| 3653 | data.detach();
|
|---|
| 3654 | for ( int i = 0; i < (int)data.size(); ++i ) {
|
|---|
| 3655 | QTextFormat *f = data[i].format();
|
|---|
| 3656 | if ( f )
|
|---|
| 3657 | f->addRef();
|
|---|
| 3658 | }
|
|---|
| 3659 | }
|
|---|
| 3660 |
|
|---|
| 3661 | void QTextString::insert( int index, const QString &s, QTextFormat *f )
|
|---|
| 3662 | {
|
|---|
| 3663 | insert( index, s.unicode(), s.length(), f );
|
|---|
| 3664 | }
|
|---|
| 3665 |
|
|---|
| 3666 | void QTextString::insert( int index, const QChar *unicode, int len, QTextFormat *f )
|
|---|
| 3667 | {
|
|---|
| 3668 | int os = data.size();
|
|---|
| 3669 | data.resize( data.size() + len, QGArray::SpeedOptim );
|
|---|
| 3670 | if ( index < os ) {
|
|---|
| 3671 | memmove( data.data() + index + len, data.data() + index,
|
|---|
| 3672 | sizeof( QTextStringChar ) * ( os - index ) );
|
|---|
| 3673 | }
|
|---|
| 3674 | QTextStringChar *ch = data.data() + index;
|
|---|
| 3675 | for ( int i = 0; i < len; ++i ) {
|
|---|
| 3676 | ch->x = 0;
|
|---|
| 3677 | ch->lineStart = 0;
|
|---|
| 3678 | ch->d.format = 0;
|
|---|
| 3679 | ch->nobreak = FALSE;
|
|---|
| 3680 | ch->type = QTextStringChar::Regular;
|
|---|
| 3681 | ch->d.format = f;
|
|---|
| 3682 | ch->rightToLeft = 0;
|
|---|
| 3683 | ch->c = unicode[i];
|
|---|
| 3684 | ++ch;
|
|---|
| 3685 | }
|
|---|
| 3686 | bidiDirty = TRUE;
|
|---|
| 3687 | }
|
|---|
| 3688 |
|
|---|
| 3689 | QTextString::~QTextString()
|
|---|
| 3690 | {
|
|---|
| 3691 | clear();
|
|---|
| 3692 | }
|
|---|
| 3693 |
|
|---|
| 3694 | void QTextString::insert( int index, QTextStringChar *c, bool doAddRefFormat )
|
|---|
| 3695 | {
|
|---|
| 3696 | int os = data.size();
|
|---|
| 3697 | data.resize( data.size() + 1, QGArray::SpeedOptim );
|
|---|
| 3698 | if ( index < os ) {
|
|---|
| 3699 | memmove( data.data() + index + 1, data.data() + index,
|
|---|
| 3700 | sizeof( QTextStringChar ) * ( os - index ) );
|
|---|
| 3701 | }
|
|---|
| 3702 | QTextStringChar &ch = data[ (int)index ];
|
|---|
| 3703 | ch.c = c->c;
|
|---|
| 3704 | ch.x = 0;
|
|---|
| 3705 | ch.lineStart = 0;
|
|---|
| 3706 | ch.rightToLeft = 0;
|
|---|
| 3707 | ch.d.format = 0;
|
|---|
| 3708 | ch.type = QTextStringChar::Regular;
|
|---|
| 3709 | ch.nobreak = FALSE;
|
|---|
| 3710 | if ( doAddRefFormat && c->format() )
|
|---|
| 3711 | c->format()->addRef();
|
|---|
| 3712 | ch.setFormat( c->format() );
|
|---|
| 3713 | bidiDirty = TRUE;
|
|---|
| 3714 | }
|
|---|
| 3715 |
|
|---|
| 3716 | void QTextString::truncate( int index )
|
|---|
| 3717 | {
|
|---|
| 3718 | index = QMAX( index, 0 );
|
|---|
| 3719 | index = QMIN( index, (int)data.size() - 1 );
|
|---|
| 3720 | if ( index < (int)data.size() ) {
|
|---|
| 3721 | for ( int i = index + 1; i < (int)data.size(); ++i ) {
|
|---|
| 3722 | QTextStringChar &ch = data[ i ];
|
|---|
| 3723 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 3724 | if ( !(ch.type == QTextStringChar::Regular) ) {
|
|---|
| 3725 | delete ch.customItem();
|
|---|
| 3726 | if ( ch.d.custom->format )
|
|---|
| 3727 | ch.d.custom->format->removeRef();
|
|---|
| 3728 | delete ch.d.custom;
|
|---|
| 3729 | ch.d.custom = 0;
|
|---|
| 3730 | } else
|
|---|
| 3731 | #endif
|
|---|
| 3732 | if ( ch.format() ) {
|
|---|
| 3733 | ch.format()->removeRef();
|
|---|
| 3734 | }
|
|---|
| 3735 | }
|
|---|
| 3736 | }
|
|---|
| 3737 | data.truncate( index );
|
|---|
| 3738 | bidiDirty = TRUE;
|
|---|
| 3739 | }
|
|---|
| 3740 |
|
|---|
| 3741 | void QTextString::remove( int index, int len )
|
|---|
| 3742 | {
|
|---|
| 3743 | for ( int i = index; i < (int)data.size() && i - index < len; ++i ) {
|
|---|
| 3744 | QTextStringChar &ch = data[ i ];
|
|---|
| 3745 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 3746 | if ( !(ch.type == QTextStringChar::Regular) ) {
|
|---|
| 3747 | delete ch.customItem();
|
|---|
| 3748 | if ( ch.d.custom->format )
|
|---|
| 3749 | ch.d.custom->format->removeRef();
|
|---|
| 3750 | delete ch.d.custom;
|
|---|
| 3751 | ch.d.custom = 0;
|
|---|
| 3752 | } else
|
|---|
| 3753 | #endif
|
|---|
| 3754 | if ( ch.format() ) {
|
|---|
| 3755 | ch.format()->removeRef();
|
|---|
| 3756 | }
|
|---|
| 3757 | }
|
|---|
| 3758 | memmove( data.data() + index, data.data() + index + len,
|
|---|
| 3759 | sizeof( QTextStringChar ) * ( data.size() - index - len ) );
|
|---|
| 3760 | data.resize( data.size() - len, QGArray::SpeedOptim );
|
|---|
| 3761 | bidiDirty = TRUE;
|
|---|
| 3762 | }
|
|---|
| 3763 |
|
|---|
| 3764 | void QTextString::clear()
|
|---|
| 3765 | {
|
|---|
| 3766 | for ( int i = 0; i < (int)data.count(); ++i ) {
|
|---|
| 3767 | QTextStringChar &ch = data[ i ];
|
|---|
| 3768 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 3769 | if ( !(ch.type == QTextStringChar::Regular) ) {
|
|---|
| 3770 | if ( ch.customItem() && ch.customItem()->placement() == QTextCustomItem::PlaceInline )
|
|---|
| 3771 | delete ch.customItem();
|
|---|
| 3772 | if ( ch.d.custom->format )
|
|---|
| 3773 | ch.d.custom->format->removeRef();
|
|---|
| 3774 | delete ch.d.custom;
|
|---|
| 3775 | ch.d.custom = 0;
|
|---|
| 3776 | } else
|
|---|
| 3777 | #endif
|
|---|
| 3778 | if ( ch.format() ) {
|
|---|
| 3779 | ch.format()->removeRef();
|
|---|
| 3780 | }
|
|---|
| 3781 | }
|
|---|
| 3782 | data.resize( 0 );
|
|---|
| 3783 | bidiDirty = TRUE;
|
|---|
| 3784 | }
|
|---|
| 3785 |
|
|---|
| 3786 | void QTextString::setFormat( int index, QTextFormat *f, bool useCollection )
|
|---|
| 3787 | {
|
|---|
| 3788 | QTextStringChar &ch = data[ index ];
|
|---|
| 3789 | if ( useCollection && ch.format() )
|
|---|
| 3790 | ch.format()->removeRef();
|
|---|
| 3791 | ch.setFormat( f );
|
|---|
| 3792 | }
|
|---|
| 3793 |
|
|---|
| 3794 | void QTextString::checkBidi() const
|
|---|
| 3795 | {
|
|---|
| 3796 | QTextString *that = (QTextString *)this;
|
|---|
| 3797 | that->bidiDirty = FALSE;
|
|---|
| 3798 | int length = data.size();
|
|---|
| 3799 | if ( !length ) {
|
|---|
| 3800 | that->bidi = FALSE;
|
|---|
| 3801 | that->rightToLeft = dir == QChar::DirR;
|
|---|
| 3802 | return;
|
|---|
| 3803 | }
|
|---|
| 3804 | const QTextStringChar *start = data.data();
|
|---|
| 3805 | const QTextStringChar *end = start + length;
|
|---|
| 3806 |
|
|---|
| 3807 | // determines the properties we need for layouting
|
|---|
| 3808 | QTextEngine textEngine( toString(), 0 );
|
|---|
| 3809 | textEngine.itemize(QTextEngine::SingleLine);
|
|---|
| 3810 | const QCharAttributes *ca = textEngine.attributes() + length-1;
|
|---|
| 3811 | QTextStringChar *ch = (QTextStringChar *)end - 1;
|
|---|
| 3812 | QScriptItem *item = &textEngine.items[textEngine.items.size()-1];
|
|---|
| 3813 | unsigned char bidiLevel = item->analysis.bidiLevel;
|
|---|
| 3814 | if ( bidiLevel )
|
|---|
| 3815 | that->bidi = TRUE;
|
|---|
| 3816 | int pos = length-1;
|
|---|
| 3817 | while ( ch >= start ) {
|
|---|
| 3818 | if ( item->position > pos ) {
|
|---|
| 3819 | --item;
|
|---|
| 3820 | Q_ASSERT( item >= &textEngine.items[0] );
|
|---|
| 3821 | Q_ASSERT( item < &textEngine.items[textEngine.items.size()] );
|
|---|
| 3822 | bidiLevel = item->analysis.bidiLevel;
|
|---|
| 3823 | if ( bidiLevel )
|
|---|
| 3824 | that->bidi = TRUE;
|
|---|
| 3825 | }
|
|---|
| 3826 | ch->softBreak = ca->softBreak;
|
|---|
| 3827 | ch->whiteSpace = ca->whiteSpace;
|
|---|
| 3828 | ch->charStop = ca->charStop;
|
|---|
| 3829 | ch->wordStop = ca->wordStop;
|
|---|
| 3830 | ch->bidiLevel = bidiLevel;
|
|---|
| 3831 | ch->rightToLeft = (bidiLevel%2);
|
|---|
| 3832 | --ch;
|
|---|
| 3833 | --ca;
|
|---|
| 3834 | --pos;
|
|---|
| 3835 | }
|
|---|
| 3836 |
|
|---|
| 3837 | if ( dir == QChar::DirR ) {
|
|---|
| 3838 | that->bidi = TRUE;
|
|---|
| 3839 | that->rightToLeft = TRUE;
|
|---|
| 3840 | } else if ( dir == QChar::DirL ) {
|
|---|
| 3841 | that->rightToLeft = FALSE;
|
|---|
| 3842 | } else {
|
|---|
| 3843 | that->rightToLeft = (textEngine.items[0].analysis.bidiLevel % 2);
|
|---|
| 3844 | }
|
|---|
| 3845 | }
|
|---|
| 3846 |
|
|---|
| 3847 | void QTextDocument::setStyleSheet( QStyleSheet *s )
|
|---|
| 3848 | {
|
|---|
| 3849 | if ( !s )
|
|---|
| 3850 | return;
|
|---|
| 3851 | sheet_ = s;
|
|---|
| 3852 | list_tm = list_bm = par_tm = par_bm = 12;
|
|---|
| 3853 | list_lm = 40;
|
|---|
| 3854 | li_tm = li_bm = 0;
|
|---|
| 3855 | QStyleSheetItem* item = s->item( "ol" );
|
|---|
| 3856 | if ( item ) {
|
|---|
| 3857 | list_tm = QMAX(0,item->margin( QStyleSheetItem::MarginTop ));
|
|---|
| 3858 | list_bm = QMAX(0,item->margin( QStyleSheetItem::MarginBottom ));
|
|---|
| 3859 | list_lm = QMAX(0,item->margin( QStyleSheetItem::MarginLeft ));
|
|---|
| 3860 | }
|
|---|
| 3861 | if ( (item = s->item( "li" ) ) ) {
|
|---|
| 3862 | li_tm = QMAX(0,item->margin( QStyleSheetItem::MarginTop ));
|
|---|
| 3863 | li_bm = QMAX(0,item->margin( QStyleSheetItem::MarginBottom ));
|
|---|
| 3864 | }
|
|---|
| 3865 | if ( (item = s->item( "p" ) ) ) {
|
|---|
| 3866 | par_tm = QMAX(0,item->margin( QStyleSheetItem::MarginTop ));
|
|---|
| 3867 | par_bm = QMAX(0,item->margin( QStyleSheetItem::MarginBottom ));
|
|---|
| 3868 | }
|
|---|
| 3869 | }
|
|---|
| 3870 |
|
|---|
| 3871 | void QTextDocument::setUnderlineLinks( bool b ) {
|
|---|
| 3872 | underlLinks = b;
|
|---|
| 3873 | for ( QTextDocument *d = childList.first(); d; d = childList.next() )
|
|---|
| 3874 | d->setUnderlineLinks( b );
|
|---|
| 3875 | }
|
|---|
| 3876 |
|
|---|
| 3877 | void QTextStringChar::setFormat( QTextFormat *f )
|
|---|
| 3878 | {
|
|---|
| 3879 | if ( type == Regular ) {
|
|---|
| 3880 | d.format = f;
|
|---|
| 3881 | } else {
|
|---|
| 3882 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 3883 | if ( !d.custom ) {
|
|---|
| 3884 | d.custom = new CustomData;
|
|---|
| 3885 | d.custom->custom = 0;
|
|---|
| 3886 | }
|
|---|
| 3887 | d.custom->format = f;
|
|---|
| 3888 | #endif
|
|---|
| 3889 | }
|
|---|
| 3890 | }
|
|---|
| 3891 |
|
|---|
| 3892 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 3893 | void QTextStringChar::setCustomItem( QTextCustomItem *i )
|
|---|
| 3894 | {
|
|---|
| 3895 | if ( type == Regular ) {
|
|---|
| 3896 | QTextFormat *f = format();
|
|---|
| 3897 | d.custom = new CustomData;
|
|---|
| 3898 | d.custom->format = f;
|
|---|
| 3899 | } else {
|
|---|
| 3900 | delete d.custom->custom;
|
|---|
| 3901 | }
|
|---|
| 3902 | d.custom->custom = i;
|
|---|
| 3903 | type = (type == Anchor ? CustomAnchor : Custom);
|
|---|
| 3904 | }
|
|---|
| 3905 |
|
|---|
| 3906 | void QTextStringChar::loseCustomItem()
|
|---|
| 3907 | {
|
|---|
| 3908 | if ( type == Custom ) {
|
|---|
| 3909 | QTextFormat *f = d.custom->format;
|
|---|
| 3910 | d.custom->custom = 0;
|
|---|
| 3911 | delete d.custom;
|
|---|
| 3912 | type = Regular;
|
|---|
| 3913 | d.format = f;
|
|---|
| 3914 | } else if ( type == CustomAnchor ) {
|
|---|
| 3915 | d.custom->custom = 0;
|
|---|
| 3916 | type = Anchor;
|
|---|
| 3917 | }
|
|---|
| 3918 | }
|
|---|
| 3919 |
|
|---|
| 3920 | #endif
|
|---|
| 3921 |
|
|---|
| 3922 | QString QTextStringChar::anchorName() const
|
|---|
| 3923 | {
|
|---|
| 3924 | if ( type == Regular )
|
|---|
| 3925 | return QString::null;
|
|---|
| 3926 | else
|
|---|
| 3927 | return d.custom->anchorName;
|
|---|
| 3928 | }
|
|---|
| 3929 |
|
|---|
| 3930 | QString QTextStringChar::anchorHref() const
|
|---|
| 3931 | {
|
|---|
| 3932 | if ( type == Regular )
|
|---|
| 3933 | return QString::null;
|
|---|
| 3934 | else
|
|---|
| 3935 | return d.custom->anchorHref;
|
|---|
| 3936 | }
|
|---|
| 3937 |
|
|---|
| 3938 | void QTextStringChar::setAnchor( const QString& name, const QString& href )
|
|---|
| 3939 | {
|
|---|
| 3940 | if ( type == Regular ) {
|
|---|
| 3941 | QTextFormat *f = format();
|
|---|
| 3942 | d.custom = new CustomData;
|
|---|
| 3943 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 3944 | d.custom->custom = 0;
|
|---|
| 3945 | #endif
|
|---|
| 3946 | d.custom->format = f;
|
|---|
| 3947 | type = Anchor;
|
|---|
| 3948 | } else if ( type == Custom ) {
|
|---|
| 3949 | type = CustomAnchor;
|
|---|
| 3950 | }
|
|---|
| 3951 | d.custom->anchorName = name;
|
|---|
| 3952 | d.custom->anchorHref = href;
|
|---|
| 3953 | }
|
|---|
| 3954 |
|
|---|
| 3955 |
|
|---|
| 3956 | int QTextString::width( int idx ) const
|
|---|
| 3957 | {
|
|---|
| 3958 | int w = 0;
|
|---|
| 3959 | QTextStringChar *c = &at( idx );
|
|---|
| 3960 | if ( !c->charStop || c->c.unicode() == 0xad || c->c.unicode() == 0x2028 )
|
|---|
| 3961 | return 0;
|
|---|
| 3962 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 3963 | if( c->isCustom() ) {
|
|---|
| 3964 | if( c->customItem()->placement() == QTextCustomItem::PlaceInline )
|
|---|
| 3965 | w = c->customItem()->width;
|
|---|
| 3966 | } else
|
|---|
| 3967 | #endif
|
|---|
| 3968 | {
|
|---|
| 3969 | int r = c->c.row();
|
|---|
| 3970 | if(r < 0x06 || (r > 0x1f && !(r > 0xd7 && r < 0xe0))) {
|
|---|
| 3971 | w = c->format()->width( c->c );
|
|---|
| 3972 | } else {
|
|---|
| 3973 | // complex text. We need some hacks to get the right metric here
|
|---|
| 3974 | QString str;
|
|---|
| 3975 | int pos = 0;
|
|---|
| 3976 | if( idx > 8 )
|
|---|
| 3977 | pos = idx - 8;
|
|---|
| 3978 | int off = idx - pos;
|
|---|
| 3979 | int end = QMIN( length(), idx + 8 );
|
|---|
| 3980 | str.setLength( end-pos );
|
|---|
| 3981 | QChar *uc = (QChar *)str.unicode();
|
|---|
| 3982 | while ( pos < end ) {
|
|---|
| 3983 | *(uc++) = at(pos).c;
|
|---|
| 3984 | pos++;
|
|---|
| 3985 | }
|
|---|
| 3986 | w = c->format()->width( str, off );
|
|---|
| 3987 | }
|
|---|
| 3988 | }
|
|---|
| 3989 | return w;
|
|---|
| 3990 | }
|
|---|
| 3991 |
|
|---|
| 3992 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 3993 |
|
|---|
| 3994 | QTextParagraph::QTextParagraph( QTextDocument *d, QTextParagraph *pr, QTextParagraph *nx, bool updateIds )
|
|---|
| 3995 | : p( pr ), n( nx ), docOrPseudo( d ),
|
|---|
| 3996 | changed(FALSE), firstFormat(TRUE), firstPProcess(TRUE), needPreProcess(FALSE), fullWidth(TRUE),
|
|---|
| 3997 | lastInFrame(FALSE), visible(TRUE), breakable(TRUE), movedDown(FALSE),
|
|---|
| 3998 | mightHaveCustomItems(FALSE), hasdoc( d != 0 ), litem(FALSE), rtext(FALSE),
|
|---|
| 3999 | align( 0 ), lstyle( QStyleSheetItem::ListDisc ), invalid( 0 ), mSelections( 0 ),
|
|---|
| 4000 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 4001 | mFloatingItems( 0 ),
|
|---|
| 4002 | #endif
|
|---|
| 4003 | utm( 0 ), ubm( 0 ), ulm( 0 ), urm( 0 ), uflm( 0 ), ulinespacing( 0 ),
|
|---|
| 4004 | tabStopWidth(0), minwidth(0), tArray(0), eData( 0 ), ldepth( 0 )
|
|---|
| 4005 | {
|
|---|
| 4006 | lstyle = QStyleSheetItem::ListDisc;
|
|---|
| 4007 | if ( !hasdoc )
|
|---|
| 4008 | docOrPseudo = new QTextParagraphPseudoDocument;
|
|---|
| 4009 | bgcol = 0;
|
|---|
| 4010 | list_val = -1;
|
|---|
| 4011 | paintdevice = 0;
|
|---|
| 4012 | QTextFormat* defFormat = formatCollection()->defaultFormat();
|
|---|
| 4013 | if ( !hasdoc ) {
|
|---|
| 4014 | tabStopWidth = defFormat->width( 'x' ) * 8;
|
|---|
| 4015 | pseudoDocument()->commandHistory = new QTextCommandHistory( 100 );
|
|---|
| 4016 | }
|
|---|
| 4017 |
|
|---|
| 4018 | if ( p )
|
|---|
| 4019 | p->n = this;
|
|---|
| 4020 | if ( n )
|
|---|
| 4021 | n->p = this;
|
|---|
| 4022 |
|
|---|
| 4023 | if ( !p && hasdoc )
|
|---|
| 4024 | document()->setFirstParagraph( this );
|
|---|
| 4025 | if ( !n && hasdoc )
|
|---|
| 4026 | document()->setLastParagraph( this );
|
|---|
| 4027 |
|
|---|
| 4028 | state = -1;
|
|---|
| 4029 |
|
|---|
| 4030 | if ( p )
|
|---|
| 4031 | id = p->id + 1;
|
|---|
| 4032 | else
|
|---|
| 4033 | id = 0;
|
|---|
| 4034 | if ( n && updateIds ) {
|
|---|
| 4035 | QTextParagraph *s = n;
|
|---|
| 4036 | while ( s ) {
|
|---|
| 4037 | s->id = s->p->id + 1;
|
|---|
| 4038 | s->invalidateStyleCache();
|
|---|
| 4039 | s = s->n;
|
|---|
| 4040 | }
|
|---|
| 4041 | }
|
|---|
| 4042 |
|
|---|
| 4043 | str = new QTextString();
|
|---|
| 4044 | QChar ch(' ');
|
|---|
| 4045 | str->insert( 0, &ch, 1, formatCollection()->defaultFormat() );
|
|---|
| 4046 | }
|
|---|
| 4047 |
|
|---|
| 4048 | QTextParagraph::~QTextParagraph()
|
|---|
| 4049 | {
|
|---|
| 4050 | delete str;
|
|---|
| 4051 | if ( hasdoc ) {
|
|---|
| 4052 | register QTextDocument *doc = document();
|
|---|
| 4053 | if ( this == doc->minwParag ) {
|
|---|
| 4054 | doc->minwParag = 0;
|
|---|
| 4055 | doc->minw = 0;
|
|---|
| 4056 | }
|
|---|
| 4057 | if ( this == doc->curParag )
|
|---|
| 4058 | doc->curParag = 0;
|
|---|
| 4059 | } else {
|
|---|
| 4060 | delete pseudoDocument();
|
|---|
| 4061 | }
|
|---|
| 4062 | delete [] tArray;
|
|---|
| 4063 | delete eData;
|
|---|
| 4064 | QMap<int, QTextLineStart*>::Iterator it = lineStarts.begin();
|
|---|
| 4065 | for ( ; it != lineStarts.end(); ++it )
|
|---|
| 4066 | delete *it;
|
|---|
| 4067 | if ( mSelections )
|
|---|
| 4068 | delete mSelections;
|
|---|
| 4069 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 4070 | if ( mFloatingItems )
|
|---|
| 4071 | delete mFloatingItems;
|
|---|
| 4072 | #endif
|
|---|
| 4073 | if ( p )
|
|---|
| 4074 | p->setNext( n );
|
|---|
| 4075 | if ( n )
|
|---|
| 4076 | n->setPrev( p );
|
|---|
| 4077 | }
|
|---|
| 4078 |
|
|---|
| 4079 | void QTextParagraph::setNext( QTextParagraph *s )
|
|---|
| 4080 | {
|
|---|
| 4081 | n = s;
|
|---|
| 4082 | if ( !n && hasdoc )
|
|---|
| 4083 | document()->setLastParagraph( this );
|
|---|
| 4084 | }
|
|---|
| 4085 |
|
|---|
| 4086 | void QTextParagraph::setPrev( QTextParagraph *s )
|
|---|
| 4087 | {
|
|---|
| 4088 | p = s;
|
|---|
| 4089 | if ( !p && hasdoc )
|
|---|
| 4090 | document()->setFirstParagraph( this );
|
|---|
| 4091 | }
|
|---|
| 4092 |
|
|---|
| 4093 | void QTextParagraph::invalidate( int chr )
|
|---|
| 4094 | {
|
|---|
| 4095 | if ( invalid < 0 )
|
|---|
| 4096 | invalid = chr;
|
|---|
| 4097 | else
|
|---|
| 4098 | invalid = QMIN( invalid, chr );
|
|---|
| 4099 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 4100 | if ( mFloatingItems ) {
|
|---|
| 4101 | for ( QTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() )
|
|---|
| 4102 | i->ypos = -1;
|
|---|
| 4103 | }
|
|---|
| 4104 | #endif
|
|---|
| 4105 | invalidateStyleCache();
|
|---|
| 4106 | }
|
|---|
| 4107 |
|
|---|
| 4108 | void QTextParagraph::invalidateStyleCache()
|
|---|
| 4109 | {
|
|---|
| 4110 | if ( list_val < 0 )
|
|---|
| 4111 | list_val = -1;
|
|---|
| 4112 | }
|
|---|
| 4113 |
|
|---|
| 4114 |
|
|---|
| 4115 | void QTextParagraph::insert( int index, const QString &s )
|
|---|
| 4116 | {
|
|---|
| 4117 | insert( index, s.unicode(), s.length() );
|
|---|
| 4118 | }
|
|---|
| 4119 |
|
|---|
| 4120 | void QTextParagraph::insert( int index, const QChar *unicode, int len )
|
|---|
| 4121 | {
|
|---|
| 4122 | if ( hasdoc && !document()->useFormatCollection() && document()->preProcessor() )
|
|---|
| 4123 | str->insert( index, unicode, len,
|
|---|
| 4124 | document()->preProcessor()->format( QTextPreProcessor::Standard ) );
|
|---|
| 4125 | else
|
|---|
| 4126 | str->insert( index, unicode, len, formatCollection()->defaultFormat() );
|
|---|
| 4127 | invalidate( index );
|
|---|
| 4128 | needPreProcess = TRUE;
|
|---|
| 4129 | }
|
|---|
| 4130 |
|
|---|
| 4131 | void QTextParagraph::truncate( int index )
|
|---|
| 4132 | {
|
|---|
| 4133 | str->truncate( index );
|
|---|
| 4134 | insert( length(), " " );
|
|---|
| 4135 | needPreProcess = TRUE;
|
|---|
| 4136 | }
|
|---|
| 4137 |
|
|---|
| 4138 | void QTextParagraph::remove( int index, int len )
|
|---|
| 4139 | {
|
|---|
| 4140 | if ( index + len - str->length() > 0 )
|
|---|
| 4141 | return;
|
|---|
| 4142 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 4143 | for ( int i = index; i < index + len; ++i ) {
|
|---|
| 4144 | QTextStringChar *c = at( i );
|
|---|
| 4145 | if ( hasdoc && c->isCustom() ) {
|
|---|
| 4146 | document()->unregisterCustomItem( c->customItem(), this );
|
|---|
| 4147 | }
|
|---|
| 4148 | }
|
|---|
| 4149 | #endif
|
|---|
| 4150 | str->remove( index, len );
|
|---|
| 4151 | invalidate( 0 );
|
|---|
| 4152 | needPreProcess = TRUE;
|
|---|
| 4153 | }
|
|---|
| 4154 |
|
|---|
| 4155 | void QTextParagraph::join( QTextParagraph *s )
|
|---|
| 4156 | {
|
|---|
| 4157 | int oh = r.height() + s->r.height();
|
|---|
| 4158 | n = s->n;
|
|---|
| 4159 | if ( n )
|
|---|
| 4160 | n->p = this;
|
|---|
| 4161 | else if ( hasdoc )
|
|---|
| 4162 | document()->setLastParagraph( this );
|
|---|
| 4163 |
|
|---|
| 4164 | int start = str->length();
|
|---|
| 4165 | if ( length() > 0 && at( length() - 1 )->c == ' ' ) {
|
|---|
| 4166 | remove( length() - 1, 1 );
|
|---|
| 4167 | --start;
|
|---|
| 4168 | }
|
|---|
| 4169 | append( s->str->toString(), TRUE );
|
|---|
| 4170 |
|
|---|
| 4171 | for ( int i = 0; i < s->length(); ++i ) {
|
|---|
| 4172 | if ( !hasdoc || document()->useFormatCollection() ) {
|
|---|
| 4173 | s->str->at( i ).format()->addRef();
|
|---|
| 4174 | str->setFormat( i + start, s->str->at( i ).format(), TRUE );
|
|---|
| 4175 | }
|
|---|
| 4176 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 4177 | if ( s->str->at( i ).isCustom() ) {
|
|---|
| 4178 | QTextCustomItem * item = s->str->at( i ).customItem();
|
|---|
| 4179 | str->at( i + start ).setCustomItem( item );
|
|---|
| 4180 | s->str->at( i ).loseCustomItem();
|
|---|
| 4181 | if ( hasdoc ) {
|
|---|
| 4182 | document()->unregisterCustomItem( item, s );
|
|---|
| 4183 | document()->registerCustomItem( item, this );
|
|---|
| 4184 | }
|
|---|
| 4185 | }
|
|---|
| 4186 | if ( s->str->at( i ).isAnchor() ) {
|
|---|
| 4187 | str->at( i + start ).setAnchor( s->str->at( i ).anchorName(),
|
|---|
| 4188 | s->str->at( i ).anchorHref() );
|
|---|
| 4189 | }
|
|---|
| 4190 | #endif
|
|---|
| 4191 | }
|
|---|
| 4192 |
|
|---|
| 4193 | if ( !extraData() && s->extraData() ) {
|
|---|
| 4194 | setExtraData( s->extraData() );
|
|---|
| 4195 | s->setExtraData( 0 );
|
|---|
| 4196 | } else if ( extraData() && s->extraData() ) {
|
|---|
| 4197 | extraData()->join( s->extraData() );
|
|---|
| 4198 | }
|
|---|
| 4199 | delete s;
|
|---|
| 4200 | invalidate( 0 );
|
|---|
| 4201 | r.setHeight( oh );
|
|---|
| 4202 | needPreProcess = TRUE;
|
|---|
| 4203 | if ( n ) {
|
|---|
| 4204 | QTextParagraph *s = n;
|
|---|
| 4205 | s->invalidate( 0 );
|
|---|
| 4206 | while ( s ) {
|
|---|
| 4207 | s->id = s->p->id + 1;
|
|---|
| 4208 | s->state = -1;
|
|---|
| 4209 | s->needPreProcess = TRUE;
|
|---|
| 4210 | s->changed = TRUE;
|
|---|
| 4211 | s->invalidateStyleCache();
|
|---|
| 4212 | s = s->n;
|
|---|
| 4213 | }
|
|---|
| 4214 | }
|
|---|
| 4215 | format();
|
|---|
| 4216 | state = -1;
|
|---|
| 4217 | }
|
|---|
| 4218 |
|
|---|
| 4219 | void QTextParagraph::move( int &dy )
|
|---|
| 4220 | {
|
|---|
| 4221 | if ( dy == 0 )
|
|---|
| 4222 | return;
|
|---|
| 4223 | changed = TRUE;
|
|---|
| 4224 | r.moveBy( 0, dy );
|
|---|
| 4225 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 4226 | if ( mFloatingItems ) {
|
|---|
| 4227 | for ( QTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() )
|
|---|
| 4228 | i->ypos += dy;
|
|---|
| 4229 | }
|
|---|
| 4230 | #endif
|
|---|
| 4231 | if ( p )
|
|---|
| 4232 | p->lastInFrame = TRUE;
|
|---|
| 4233 |
|
|---|
| 4234 | // do page breaks if required
|
|---|
| 4235 | if ( hasdoc && document()->isPageBreakEnabled() ) {
|
|---|
| 4236 | int shift;
|
|---|
| 4237 | if ( ( shift = document()->formatter()->formatVertically( document(), this ) ) ) {
|
|---|
| 4238 | if ( p )
|
|---|
| 4239 | p->setChanged( TRUE );
|
|---|
| 4240 | dy += shift;
|
|---|
| 4241 | }
|
|---|
| 4242 | }
|
|---|
| 4243 | }
|
|---|
| 4244 |
|
|---|
| 4245 | void QTextParagraph::format( int start, bool doMove )
|
|---|
| 4246 | {
|
|---|
| 4247 | if ( !str || str->length() == 0 || !formatter() )
|
|---|
| 4248 | return;
|
|---|
| 4249 |
|
|---|
| 4250 | if ( hasdoc &&
|
|---|
| 4251 | document()->preProcessor() &&
|
|---|
| 4252 | ( needPreProcess || state == -1 ) )
|
|---|
| 4253 | document()->preProcessor()->process( document(), this, invalid <= 0 ? 0 : invalid );
|
|---|
| 4254 | needPreProcess = FALSE;
|
|---|
| 4255 |
|
|---|
| 4256 | if ( invalid == -1 )
|
|---|
| 4257 | return;
|
|---|
| 4258 |
|
|---|
| 4259 | r.moveTopLeft( QPoint( documentX(), p ? p->r.y() + p->r.height() : documentY() ) );
|
|---|
| 4260 | if ( p )
|
|---|
| 4261 | p->lastInFrame = FALSE;
|
|---|
| 4262 |
|
|---|
| 4263 | movedDown = FALSE;
|
|---|
| 4264 | bool formattedAgain = FALSE;
|
|---|
| 4265 |
|
|---|
| 4266 | formatAgain:
|
|---|
| 4267 |
|
|---|
| 4268 | r.setWidth( documentWidth() );
|
|---|
| 4269 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 4270 | if ( hasdoc && mFloatingItems ) {
|
|---|
| 4271 | for ( QTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() ) {
|
|---|
| 4272 | i->ypos = r.y();
|
|---|
| 4273 | if ( i->placement() == QTextCustomItem::PlaceRight ) {
|
|---|
| 4274 | i->xpos = r.x() + r.width() - i->width;
|
|---|
| 4275 | }
|
|---|
| 4276 | }
|
|---|
| 4277 | }
|
|---|
| 4278 | #endif
|
|---|
| 4279 | QMap<int, QTextLineStart*> oldLineStarts = lineStarts;
|
|---|
| 4280 | lineStarts.clear();
|
|---|
| 4281 | int y = formatter()->format( document(), this, start, oldLineStarts );
|
|---|
| 4282 |
|
|---|
| 4283 |
|
|---|
| 4284 | r.setWidth( QMAX( r.width(), formatter()->minimumWidth() ) );
|
|---|
| 4285 |
|
|---|
| 4286 |
|
|---|
| 4287 | QMap<int, QTextLineStart*>::Iterator it = oldLineStarts.begin();
|
|---|
| 4288 |
|
|---|
| 4289 | for ( ; it != oldLineStarts.end(); ++it )
|
|---|
| 4290 | delete *it;
|
|---|
| 4291 |
|
|---|
| 4292 | if ( !hasdoc ) { // qt_format_text bounding rect handling
|
|---|
| 4293 | it = lineStarts.begin();
|
|---|
| 4294 | int usedw = 0;
|
|---|
| 4295 | for ( ; it != lineStarts.end(); ++it )
|
|---|
| 4296 | usedw = QMAX( usedw, (*it)->w );
|
|---|
| 4297 | if ( r.width() <= 0 ) {
|
|---|
| 4298 | // if the user specifies an invalid rect, this means that the
|
|---|
| 4299 | // bounding box should grow to the width that the text actually
|
|---|
| 4300 | // needs
|
|---|
| 4301 | r.setWidth( usedw );
|
|---|
| 4302 | } else {
|
|---|
| 4303 | r.setWidth( QMIN( usedw, r.width() ) );
|
|---|
| 4304 | }
|
|---|
| 4305 | }
|
|---|
| 4306 |
|
|---|
| 4307 | if ( y != r.height() )
|
|---|
| 4308 | r.setHeight( y );
|
|---|
| 4309 |
|
|---|
| 4310 | if ( !visible ) {
|
|---|
| 4311 | r.setHeight( 0 );
|
|---|
| 4312 | } else {
|
|---|
| 4313 | int minw = minwidth = formatter()->minimumWidth();
|
|---|
| 4314 | int wused = formatter()->widthUsed();
|
|---|
| 4315 | wused = QMAX( minw, wused );
|
|---|
| 4316 | if ( hasdoc ) {
|
|---|
| 4317 | document()->setMinimumWidth( minw, wused, this );
|
|---|
| 4318 | } else {
|
|---|
| 4319 | pseudoDocument()->minw = QMAX( pseudoDocument()->minw, minw );
|
|---|
| 4320 | pseudoDocument()->wused = QMAX( pseudoDocument()->wused, wused );
|
|---|
| 4321 | }
|
|---|
| 4322 | }
|
|---|
| 4323 |
|
|---|
| 4324 | // do page breaks if required
|
|---|
| 4325 | if ( hasdoc && document()->isPageBreakEnabled() ) {
|
|---|
| 4326 | int shift = document()->formatter()->formatVertically( document(), this );
|
|---|
| 4327 | if ( shift && !formattedAgain ) {
|
|---|
| 4328 | formattedAgain = TRUE;
|
|---|
| 4329 | goto formatAgain;
|
|---|
| 4330 | }
|
|---|
| 4331 | }
|
|---|
| 4332 |
|
|---|
| 4333 | if ( n && doMove && n->invalid == -1 && r.y() + r.height() != n->r.y() ) {
|
|---|
| 4334 | int dy = ( r.y() + r.height() ) - n->r.y();
|
|---|
| 4335 | QTextParagraph *s = n;
|
|---|
| 4336 | bool makeInvalid = p && p->lastInFrame;
|
|---|
| 4337 | while ( s && dy ) {
|
|---|
| 4338 | if ( !s->isFullWidth() )
|
|---|
| 4339 | makeInvalid = TRUE;
|
|---|
| 4340 | if ( makeInvalid )
|
|---|
| 4341 | s->invalidate( 0 );
|
|---|
| 4342 | s->move( dy );
|
|---|
| 4343 | if ( s->lastInFrame )
|
|---|
| 4344 | makeInvalid = TRUE;
|
|---|
| 4345 | s = s->n;
|
|---|
| 4346 | }
|
|---|
| 4347 | }
|
|---|
| 4348 |
|
|---|
| 4349 | firstFormat = FALSE;
|
|---|
| 4350 | changed = TRUE;
|
|---|
| 4351 | invalid = -1;
|
|---|
| 4352 | //##### string()->setTextChanged( FALSE );
|
|---|
| 4353 | }
|
|---|
| 4354 |
|
|---|
| 4355 | int QTextParagraph::lineHeightOfChar( int i, int *bl, int *y ) const
|
|---|
| 4356 | {
|
|---|
| 4357 | if ( !isValid() )
|
|---|
| 4358 | ( (QTextParagraph*)this )->format();
|
|---|
| 4359 |
|
|---|
| 4360 | QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.end();
|
|---|
| 4361 | --it;
|
|---|
| 4362 | for ( ;; ) {
|
|---|
| 4363 | if ( i >= it.key() ) {
|
|---|
| 4364 | if ( bl )
|
|---|
| 4365 | *bl = ( *it )->baseLine;
|
|---|
| 4366 | if ( y )
|
|---|
| 4367 | *y = ( *it )->y;
|
|---|
| 4368 | return ( *it )->h;
|
|---|
| 4369 | }
|
|---|
| 4370 | if ( it == lineStarts.begin() )
|
|---|
| 4371 | break;
|
|---|
| 4372 | --it;
|
|---|
| 4373 | }
|
|---|
| 4374 |
|
|---|
| 4375 | qWarning( "QTextParagraph::lineHeightOfChar: couldn't find lh for %d", i );
|
|---|
| 4376 | return 15;
|
|---|
| 4377 | }
|
|---|
| 4378 |
|
|---|
| 4379 | QTextStringChar *QTextParagraph::lineStartOfChar( int i, int *index, int *line ) const
|
|---|
| 4380 | {
|
|---|
| 4381 | if ( !isValid() )
|
|---|
| 4382 | ( (QTextParagraph*)this )->format();
|
|---|
| 4383 |
|
|---|
| 4384 | int l = (int)lineStarts.count() - 1;
|
|---|
| 4385 | QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.end();
|
|---|
| 4386 | --it;
|
|---|
| 4387 | for ( ;; ) {
|
|---|
| 4388 | if ( i >= it.key() ) {
|
|---|
| 4389 | if ( index )
|
|---|
| 4390 | *index = it.key();
|
|---|
| 4391 | if ( line )
|
|---|
| 4392 | *line = l;
|
|---|
| 4393 | return &str->at( it.key() );
|
|---|
| 4394 | }
|
|---|
| 4395 | if ( it == lineStarts.begin() )
|
|---|
| 4396 | break;
|
|---|
| 4397 | --it;
|
|---|
| 4398 | --l;
|
|---|
| 4399 | }
|
|---|
| 4400 |
|
|---|
| 4401 | qWarning( "QTextParagraph::lineStartOfChar: couldn't find %d", i );
|
|---|
| 4402 | return 0;
|
|---|
| 4403 | }
|
|---|
| 4404 |
|
|---|
| 4405 | int QTextParagraph::lines() const
|
|---|
| 4406 | {
|
|---|
| 4407 | if ( !isValid() )
|
|---|
| 4408 | ( (QTextParagraph*)this )->format();
|
|---|
| 4409 |
|
|---|
| 4410 | return (int)lineStarts.count();
|
|---|
| 4411 | }
|
|---|
| 4412 |
|
|---|
| 4413 | QTextStringChar *QTextParagraph::lineStartOfLine( int line, int *index ) const
|
|---|
| 4414 | {
|
|---|
| 4415 | if ( !isValid() )
|
|---|
| 4416 | ( (QTextParagraph*)this )->format();
|
|---|
| 4417 |
|
|---|
| 4418 | if ( line >= 0 && line < (int)lineStarts.count() ) {
|
|---|
| 4419 | QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.begin();
|
|---|
| 4420 | while ( line-- > 0 )
|
|---|
| 4421 | ++it;
|
|---|
| 4422 | int i = it.key();
|
|---|
| 4423 | if ( index )
|
|---|
| 4424 | *index = i;
|
|---|
| 4425 | return &str->at( i );
|
|---|
| 4426 | }
|
|---|
| 4427 |
|
|---|
| 4428 | qWarning( "QTextParagraph::lineStartOfLine: couldn't find %d", line );
|
|---|
| 4429 | return 0;
|
|---|
| 4430 | }
|
|---|
| 4431 |
|
|---|
| 4432 | int QTextParagraph::leftGap() const
|
|---|
| 4433 | {
|
|---|
| 4434 | if ( !isValid() )
|
|---|
| 4435 | ( (QTextParagraph*)this )->format();
|
|---|
| 4436 |
|
|---|
| 4437 | if ( str->length() == 0)
|
|---|
| 4438 | return 0;
|
|---|
| 4439 |
|
|---|
| 4440 | int line = 0;
|
|---|
| 4441 | int x = str->length() ? str->at(0).x : 0; /* set x to x of first char */
|
|---|
| 4442 | if ( str->isBidi() ) {
|
|---|
| 4443 | for ( int i = 1; i < str->length()-1; ++i )
|
|---|
| 4444 | x = QMIN(x, str->at(i).x);
|
|---|
| 4445 | return x;
|
|---|
| 4446 | }
|
|---|
| 4447 |
|
|---|
| 4448 | QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.begin();
|
|---|
| 4449 | while (line < (int)lineStarts.count()) {
|
|---|
| 4450 | int i = it.key(); /* char index */
|
|---|
| 4451 | x = QMIN(x, str->at(i).x);
|
|---|
| 4452 | ++it;
|
|---|
| 4453 | ++line;
|
|---|
| 4454 | }
|
|---|
| 4455 | return x;
|
|---|
| 4456 | }
|
|---|
| 4457 |
|
|---|
| 4458 | void QTextParagraph::setFormat( int index, int len, QTextFormat *f, bool useCollection, int flags )
|
|---|
| 4459 | {
|
|---|
| 4460 | if ( !f )
|
|---|
| 4461 | return;
|
|---|
| 4462 | if ( index < 0 )
|
|---|
| 4463 | index = 0;
|
|---|
| 4464 | if ( index > str->length() - 1 )
|
|---|
| 4465 | index = str->length() - 1;
|
|---|
| 4466 | if ( index + len >= str->length() )
|
|---|
| 4467 | len = str->length() - index;
|
|---|
| 4468 |
|
|---|
| 4469 | QTextFormatCollection *fc = 0;
|
|---|
| 4470 | if ( useCollection )
|
|---|
| 4471 | fc = formatCollection();
|
|---|
| 4472 | QTextFormat *of;
|
|---|
| 4473 | for ( int i = 0; i < len; ++i ) {
|
|---|
| 4474 | of = str->at( i + index ).format();
|
|---|
| 4475 | if ( !changed && ( !of || f->key() != of->key() ) )
|
|---|
| 4476 | changed = TRUE;
|
|---|
| 4477 | if ( invalid == -1 &&
|
|---|
| 4478 | ( f->font().family() != of->font().family() ||
|
|---|
| 4479 | f->font().pointSize() != of->font().pointSize() ||
|
|---|
| 4480 | f->font().weight() != of->font().weight() ||
|
|---|
| 4481 | f->font().italic() != of->font().italic() ||
|
|---|
| 4482 | f->vAlign() != of->vAlign() ) ) {
|
|---|
| 4483 | invalidate( 0 );
|
|---|
| 4484 | }
|
|---|
| 4485 | if ( flags == -1 || flags == QTextFormat::Format || !fc ) {
|
|---|
| 4486 | if ( fc )
|
|---|
| 4487 | f = fc->format( f );
|
|---|
| 4488 | str->setFormat( i + index, f, useCollection );
|
|---|
| 4489 | } else {
|
|---|
| 4490 | QTextFormat *fm = fc->format( of, f, flags );
|
|---|
| 4491 | str->setFormat( i + index, fm, useCollection );
|
|---|
| 4492 | }
|
|---|
| 4493 | }
|
|---|
| 4494 | }
|
|---|
| 4495 |
|
|---|
| 4496 | void QTextParagraph::indent( int *oldIndent, int *newIndent )
|
|---|
| 4497 | {
|
|---|
| 4498 | if ( !hasdoc || !document()->indent() || isListItem() ) {
|
|---|
| 4499 | if ( oldIndent )
|
|---|
| 4500 | *oldIndent = 0;
|
|---|
| 4501 | if ( newIndent )
|
|---|
| 4502 | *newIndent = 0;
|
|---|
| 4503 | if ( oldIndent && newIndent )
|
|---|
| 4504 | *newIndent = *oldIndent;
|
|---|
| 4505 | return;
|
|---|
| 4506 | }
|
|---|
| 4507 | document()->indent()->indent( document(), this, oldIndent, newIndent );
|
|---|
| 4508 | }
|
|---|
| 4509 |
|
|---|
| 4510 | void QTextParagraph::paint( QPainter &painter, const QColorGroup &cg, QTextCursor *cursor, bool drawSelections,
|
|---|
| 4511 | int clipx, int clipy, int clipw, int cliph )
|
|---|
| 4512 | {
|
|---|
| 4513 | if ( !visible )
|
|---|
| 4514 | return;
|
|---|
| 4515 | int i, y, h, baseLine, xstart, xend = 0;
|
|---|
| 4516 | i = y =h = baseLine = 0;
|
|---|
| 4517 | QRect cursorRect;
|
|---|
| 4518 | drawSelections &= ( mSelections != 0 );
|
|---|
| 4519 | // macintosh full-width selection style
|
|---|
| 4520 | bool fullWidthStyle = QApplication::style().styleHint(QStyle::SH_RichText_FullWidthSelection);
|
|---|
| 4521 | int fullSelectionWidth = 0;
|
|---|
| 4522 | if ( drawSelections && fullWidthStyle )
|
|---|
| 4523 | fullSelectionWidth = (hasdoc ? document()->width() : r.width());
|
|---|
| 4524 |
|
|---|
| 4525 | QString qstr = str->toString();
|
|---|
| 4526 | // ### workaround so that \n are not drawn, actually this should
|
|---|
| 4527 | // be fixed in QFont somewhere (under Windows you get ugly boxes
|
|---|
| 4528 | // otherwise)
|
|---|
| 4529 | QChar* uc = (QChar*) qstr.unicode();
|
|---|
| 4530 | for ( uint ii = 0; ii < qstr.length(); ii++ )
|
|---|
| 4531 | if ( uc[(int)ii]== '\n' || uc[(int)ii] == '\t' )
|
|---|
| 4532 | uc[(int)ii] = 0x20;
|
|---|
| 4533 |
|
|---|
| 4534 | int line = -1;
|
|---|
| 4535 | int paintStart = 0;
|
|---|
| 4536 | QTextStringChar *chr = 0;
|
|---|
| 4537 | QTextStringChar *nextchr = at( 0 );
|
|---|
| 4538 | for ( i = 0; i < length(); i++ ) {
|
|---|
| 4539 | chr = nextchr;
|
|---|
| 4540 | if ( i < length()-1 )
|
|---|
| 4541 | nextchr = at( i+1 );
|
|---|
| 4542 |
|
|---|
| 4543 | // we flush at end of document
|
|---|
| 4544 | bool flush = (i == length()-1);
|
|---|
| 4545 | bool ignoreSoftHyphen = FALSE;
|
|---|
| 4546 | if ( !flush ) {
|
|---|
| 4547 | // we flush at end of line
|
|---|
| 4548 | flush |= nextchr->lineStart;
|
|---|
| 4549 | // we flush on format changes
|
|---|
| 4550 | flush |= ( nextchr->format() != chr->format() );
|
|---|
| 4551 | // we flush on link changes
|
|---|
| 4552 | flush |= ( nextchr->isLink() != chr->isLink() );
|
|---|
| 4553 | // we flush on start of run
|
|---|
| 4554 | flush |= ( nextchr->bidiLevel != chr->bidiLevel );
|
|---|
| 4555 | // we flush on bidi changes
|
|---|
| 4556 | flush |= ( nextchr->rightToLeft != chr->rightToLeft );
|
|---|
| 4557 | // we flush before and after tabs
|
|---|
| 4558 | flush |= ( chr->c == '\t' || nextchr->c == '\t' );
|
|---|
| 4559 | // we flush on soft hypens
|
|---|
| 4560 | if (chr->c.unicode() == 0xad) {
|
|---|
| 4561 | flush = TRUE;
|
|---|
| 4562 | if (!nextchr->lineStart)
|
|---|
| 4563 | ignoreSoftHyphen = TRUE;
|
|---|
| 4564 | }
|
|---|
| 4565 | // we flush on custom items
|
|---|
| 4566 | flush |= chr->isCustom();
|
|---|
| 4567 | // we flush before custom items
|
|---|
| 4568 | flush |= nextchr->isCustom();
|
|---|
| 4569 | // when painting justified, we flush on spaces
|
|---|
| 4570 | if ((alignment() & Qt::AlignJustify) == Qt::AlignJustify )
|
|---|
| 4571 | flush |= chr->whiteSpace;
|
|---|
| 4572 | }
|
|---|
| 4573 |
|
|---|
| 4574 | // init a new line
|
|---|
| 4575 | if ( chr->lineStart ) {
|
|---|
| 4576 | ++line;
|
|---|
| 4577 | paintStart = i;
|
|---|
| 4578 | lineInfo( line, y, h, baseLine );
|
|---|
| 4579 | if ( clipy != -1 && cliph != 0 && y + r.y() - h > clipy + cliph ) { // outside clip area, leave
|
|---|
| 4580 | break;
|
|---|
| 4581 | }
|
|---|
| 4582 |
|
|---|
| 4583 | // if this is the first line and we are a list item, draw the the bullet label
|
|---|
| 4584 | if ( line == 0 && isListItem() ) {
|
|---|
| 4585 | int x = chr->x;
|
|---|
| 4586 | if (str->isBidi()) {
|
|---|
| 4587 | if (str->isRightToLeft()) {
|
|---|
| 4588 | x = chr->x + str->width(0);
|
|---|
| 4589 | for (int k = 1; k < length(); ++k) {
|
|---|
| 4590 | if (str->at(k).lineStart)
|
|---|
| 4591 | break;
|
|---|
| 4592 | x = QMAX(x, str->at(k).x + str->width(k));
|
|---|
| 4593 | }
|
|---|
| 4594 | } else {
|
|---|
| 4595 | x = chr->x;
|
|---|
| 4596 | for (int k = 1; k < length(); ++k) {
|
|---|
| 4597 | if (str->at(k).lineStart)
|
|---|
| 4598 | break;
|
|---|
| 4599 | x = QMIN(x, str->at(k).x);
|
|---|
| 4600 | }
|
|---|
| 4601 | }
|
|---|
| 4602 | }
|
|---|
| 4603 | drawLabel( &painter, x, y, 0, 0, baseLine, cg );
|
|---|
| 4604 | }
|
|---|
| 4605 | }
|
|---|
| 4606 |
|
|---|
| 4607 | // check for cursor mark
|
|---|
| 4608 | if ( cursor && this == cursor->paragraph() && i == cursor->index() ) {
|
|---|
| 4609 | QTextStringChar *c = i == 0 ? chr : chr - 1;
|
|---|
| 4610 | cursorRect.setRect( cursor->x() , y + baseLine - c->format()->ascent(),
|
|---|
| 4611 | 1, c->format()->height() );
|
|---|
| 4612 | }
|
|---|
| 4613 |
|
|---|
| 4614 | if ( flush ) { // something changed, draw what we have so far
|
|---|
| 4615 | if ( chr->rightToLeft ) {
|
|---|
| 4616 | xstart = chr->x;
|
|---|
| 4617 | xend = at( paintStart )->x + str->width( paintStart );
|
|---|
| 4618 | } else {
|
|---|
| 4619 | xstart = at( paintStart )->x;
|
|---|
| 4620 | xend = chr->x;
|
|---|
| 4621 | if ( i < length() - 1 ) {
|
|---|
| 4622 | if ( !str->at( i + 1 ).lineStart &&
|
|---|
| 4623 | str->at( i + 1 ).rightToLeft == chr->rightToLeft )
|
|---|
| 4624 | xend = str->at( i + 1 ).x;
|
|---|
| 4625 | else
|
|---|
| 4626 | xend += str->width( i );
|
|---|
| 4627 | }
|
|---|
| 4628 | }
|
|---|
| 4629 |
|
|---|
| 4630 | if ( (clipx == -1 || clipw <= 0 || (xend >= clipx && xstart <= clipx + clipw)) &&
|
|---|
| 4631 | ( clipy == -1 || clipy < y+r.y()+h ) ) {
|
|---|
| 4632 | if ( !chr->isCustom() )
|
|---|
| 4633 | drawString( painter, qstr, paintStart, i - paintStart + (ignoreSoftHyphen ? 0 : 1), xstart, y,
|
|---|
| 4634 | baseLine, xend-xstart, h, drawSelections, fullSelectionWidth,
|
|---|
| 4635 | chr, cg, chr->rightToLeft );
|
|---|
| 4636 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 4637 | else if ( chr->customItem()->placement() == QTextCustomItem::PlaceInline ) {
|
|---|
| 4638 | bool inSelection = FALSE;
|
|---|
| 4639 | if (drawSelections) {
|
|---|
| 4640 | QMap<int, QTextParagraphSelection>::ConstIterator it = mSelections->find( QTextDocument::Standard );
|
|---|
| 4641 | inSelection = (it != mSelections->end() && (*it).start <= i && (*it).end > i);
|
|---|
| 4642 | }
|
|---|
| 4643 | chr->customItem()->draw( &painter, chr->x, y,
|
|---|
| 4644 | clipx == -1 ? clipx : (clipx - r.x()),
|
|---|
| 4645 | clipy == -1 ? clipy : (clipy - r.y()),
|
|---|
| 4646 | clipw, cliph, cg, inSelection );
|
|---|
| 4647 | }
|
|---|
| 4648 | #endif
|
|---|
| 4649 | }
|
|---|
| 4650 | paintStart = i+1;
|
|---|
| 4651 | }
|
|---|
| 4652 |
|
|---|
| 4653 | }
|
|---|
| 4654 |
|
|---|
| 4655 | // time to draw the cursor
|
|---|
| 4656 | const int cursor_extent = 4;
|
|---|
| 4657 | if ( !cursorRect.isNull() && cursor &&
|
|---|
| 4658 | ((clipx == -1 || clipw == -1) || (cursorRect.right()+cursor_extent >= clipx && cursorRect.left()-cursor_extent <= clipx + clipw)) ) {
|
|---|
| 4659 | painter.fillRect( cursorRect, cg.color( QColorGroup::Text ) );
|
|---|
| 4660 | painter.save();
|
|---|
| 4661 | if ( string()->isBidi() ) {
|
|---|
| 4662 | if ( at( cursor->index() )->rightToLeft ) {
|
|---|
| 4663 | painter.setPen( Qt::black );
|
|---|
| 4664 | painter.drawLine( cursorRect.x(), cursorRect.y(), cursorRect.x() - cursor_extent / 2, cursorRect.y() + cursor_extent / 2 );
|
|---|
| 4665 | painter.drawLine( cursorRect.x(), cursorRect.y() + cursor_extent, cursorRect.x() - cursor_extent / 2, cursorRect.y() + cursor_extent / 2 );
|
|---|
| 4666 | } else {
|
|---|
| 4667 | painter.setPen( Qt::black );
|
|---|
| 4668 | painter.drawLine( cursorRect.x(), cursorRect.y(), cursorRect.x() + cursor_extent / 2, cursorRect.y() + cursor_extent / 2 );
|
|---|
| 4669 | painter.drawLine( cursorRect.x(), cursorRect.y() + cursor_extent, cursorRect.x() + cursor_extent / 2, cursorRect.y() + cursor_extent / 2 );
|
|---|
| 4670 | }
|
|---|
| 4671 | }
|
|---|
| 4672 | painter.restore();
|
|---|
| 4673 | }
|
|---|
| 4674 | }
|
|---|
| 4675 |
|
|---|
| 4676 | //#define BIDI_DEBUG
|
|---|
| 4677 |
|
|---|
| 4678 | void QTextParagraph::setColorForSelection( QColor &color, QPainter &painter,
|
|---|
| 4679 | const QColorGroup& cg, int selection )
|
|---|
| 4680 | {
|
|---|
| 4681 | if (selection < 0)
|
|---|
| 4682 | return;
|
|---|
| 4683 | color = ( hasdoc && selection != QTextDocument::Standard ) ?
|
|---|
| 4684 | document()->selectionColor( selection ) :
|
|---|
| 4685 | cg.color( QColorGroup::Highlight );
|
|---|
| 4686 | if ( selection == QTextDocument::IMCompositionText ) {
|
|---|
| 4687 | int h1, s1, v1, h2, s2, v2;
|
|---|
| 4688 | cg.color( QColorGroup::Base ).hsv( &h1, &s1, &v1 );
|
|---|
| 4689 | cg.color( QColorGroup::Background ).hsv( &h2, &s2, &v2 );
|
|---|
| 4690 | color.setHsv( h1, s1, ( v1 + v2 ) / 2 );
|
|---|
| 4691 | painter.setPen( cg.color( QColorGroup::Text ) );
|
|---|
| 4692 | } else if ( selection == QTextDocument::IMSelectionText ) {
|
|---|
| 4693 | color = cg.color( QColorGroup::Dark );
|
|---|
| 4694 | painter.setPen( cg.color( QColorGroup::BrightText ) );
|
|---|
| 4695 | } else if ( !hasdoc || document()->invertSelectionText( selection ) ) {
|
|---|
| 4696 | painter.setPen( cg.color( QColorGroup::HighlightedText ) );
|
|---|
| 4697 | }
|
|---|
| 4698 | }
|
|---|
| 4699 |
|
|---|
| 4700 | void QTextParagraph::drawString( QPainter &painter, const QString &str, int start, int len, int xstart,
|
|---|
| 4701 | int y, int baseLine, int w, int h, bool drawSelections, int fullSelectionWidth,
|
|---|
| 4702 | QTextStringChar *formatChar, const QColorGroup& cg,
|
|---|
| 4703 | bool rightToLeft )
|
|---|
| 4704 | {
|
|---|
| 4705 | bool plainText = hasdoc ? document()->textFormat() == Qt::PlainText : FALSE;
|
|---|
| 4706 | QTextFormat* format = formatChar->format();
|
|---|
| 4707 |
|
|---|
| 4708 | if ( !plainText || hasdoc && format->color() != document()->formatCollection()->defaultFormat()->color() )
|
|---|
| 4709 | painter.setPen( QPen( format->color() ) );
|
|---|
| 4710 | else
|
|---|
| 4711 | painter.setPen( cg.text() );
|
|---|
| 4712 | painter.setFont( format->font() );
|
|---|
| 4713 |
|
|---|
| 4714 | if ( hasdoc && formatChar->isAnchor() && !formatChar->anchorHref().isEmpty() ) {
|
|---|
| 4715 | if ( format->useLinkColor() )
|
|---|
| 4716 | painter.setPen(document()->linkColor.isValid() ? document()->linkColor : cg.link());
|
|---|
| 4717 | if ( document()->underlineLinks() ) {
|
|---|
| 4718 | QFont fn = format->font();
|
|---|
| 4719 | fn.setUnderline( TRUE );
|
|---|
| 4720 | painter.setFont( fn );
|
|---|
| 4721 | }
|
|---|
| 4722 | }
|
|---|
| 4723 |
|
|---|
| 4724 | QPainter::TextDirection dir = rightToLeft ? QPainter::RTL : QPainter::LTR;
|
|---|
| 4725 |
|
|---|
| 4726 | int real_length = len;
|
|---|
| 4727 | if (len && dir != QPainter::RTL && start + len == length() ) // don't draw the last character (trailing space)
|
|---|
| 4728 | len--;
|
|---|
| 4729 | if (len && str.unicode()[start+len-1] == QChar_linesep)
|
|---|
| 4730 | len--;
|
|---|
| 4731 |
|
|---|
| 4732 |
|
|---|
| 4733 | QTextFormat::VerticalAlignment vAlign = format->vAlign();
|
|---|
| 4734 | if ( vAlign != QTextFormat::AlignNormal ) {
|
|---|
| 4735 | // sub or superscript
|
|---|
| 4736 | QFont f( painter.font() );
|
|---|
| 4737 | if ( format->fontSizesInPixels() )
|
|---|
| 4738 | f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
|
|---|
| 4739 | else
|
|---|
| 4740 | f.setPointSize( ( f.pointSize() * 2 ) / 3 );
|
|---|
| 4741 | painter.setFont( f );
|
|---|
| 4742 | int h = painter.fontMetrics().height();
|
|---|
| 4743 | baseLine += (vAlign == QTextFormat::AlignSubScript) ? h/6 : -h/2;
|
|---|
| 4744 | }
|
|---|
| 4745 |
|
|---|
| 4746 | bool allSelected = FALSE;
|
|---|
| 4747 | if (drawSelections) {
|
|---|
| 4748 | QMap<int, QTextParagraphSelection>::ConstIterator it = mSelections->find( QTextDocument::Standard );
|
|---|
| 4749 | allSelected = (it != mSelections->end() && (*it).start <= start && (*it).end >= start+len);
|
|---|
| 4750 | }
|
|---|
| 4751 | if (!allSelected)
|
|---|
| 4752 | painter.drawText(xstart, y + baseLine, str, start, len, dir);
|
|---|
| 4753 |
|
|---|
| 4754 | #ifdef BIDI_DEBUG
|
|---|
| 4755 | painter.save();
|
|---|
| 4756 | painter.setPen ( Qt::red );
|
|---|
| 4757 | painter.drawLine( xstart, y, xstart, y + baseLine );
|
|---|
| 4758 | painter.drawLine( xstart, y + baseLine/2, xstart + 10, y + baseLine/2 );
|
|---|
| 4759 | int w = 0;
|
|---|
| 4760 | int i = 0;
|
|---|
| 4761 | while( i < len )
|
|---|
| 4762 | w += painter.fontMetrics().charWidth( str, start + i++ );
|
|---|
| 4763 | painter.setPen ( Qt::blue );
|
|---|
| 4764 | painter.drawLine( xstart + w - 1, y, xstart + w - 1, y + baseLine );
|
|---|
| 4765 | painter.drawLine( xstart + w - 1, y + baseLine/2, xstart + w - 1 - 10, y + baseLine/2 );
|
|---|
| 4766 | painter.restore();
|
|---|
| 4767 | #endif
|
|---|
| 4768 |
|
|---|
| 4769 | // check if we are in a selection and draw it
|
|---|
| 4770 | if (drawSelections) {
|
|---|
| 4771 | QMap<int, QTextParagraphSelection>::ConstIterator it = mSelections->end();
|
|---|
| 4772 | while ( it != mSelections->begin() ) {
|
|---|
| 4773 | --it;
|
|---|
| 4774 | int selStart = (*it).start;
|
|---|
| 4775 | int selEnd = (*it).end;
|
|---|
| 4776 | int tmpw = w;
|
|---|
| 4777 |
|
|---|
| 4778 | selStart = QMAX(selStart, start);
|
|---|
| 4779 | int real_selEnd = QMIN(selEnd, start+real_length);
|
|---|
| 4780 | selEnd = QMIN(selEnd, start+len);
|
|---|
| 4781 | bool extendRight = FALSE;
|
|---|
| 4782 | bool extendLeft = FALSE;
|
|---|
| 4783 | bool selWrap = (real_selEnd == length()-1 && n && n->hasSelection(it.key()));
|
|---|
| 4784 | if (selWrap || this->str->at(real_selEnd).lineStart) {
|
|---|
| 4785 | extendRight = (fullSelectionWidth != 0);
|
|---|
| 4786 | if (!extendRight && !rightToLeft)
|
|---|
| 4787 | tmpw += painter.fontMetrics().width(' ');
|
|---|
| 4788 | }
|
|---|
| 4789 | if (fullSelectionWidth && (selStart == 0 || this->str->at(selStart).lineStart)) {
|
|---|
| 4790 | extendLeft = TRUE;
|
|---|
| 4791 | }
|
|---|
| 4792 | if (this->str->isRightToLeft() != rightToLeft)
|
|---|
| 4793 | extendLeft = extendRight = FALSE;
|
|---|
| 4794 |
|
|---|
| 4795 | if (this->str->isRightToLeft()) {
|
|---|
| 4796 | bool tmp = extendLeft;
|
|---|
| 4797 | extendLeft = extendRight;
|
|---|
| 4798 | extendRight = tmp;
|
|---|
| 4799 | }
|
|---|
| 4800 |
|
|---|
| 4801 | if (selStart < real_selEnd ||
|
|---|
| 4802 | selWrap && fullSelectionWidth && extendRight &&
|
|---|
| 4803 | // don't draw the standard selection on a printer=
|
|---|
| 4804 | (it.key() != QTextDocument::Standard || !is_printer( &painter))) {
|
|---|
| 4805 | int selection = it.key();
|
|---|
| 4806 | QColor color;
|
|---|
| 4807 | setColorForSelection( color, painter, cg, selection );
|
|---|
| 4808 | if (selStart != start || selEnd != start + len || selWrap) {
|
|---|
| 4809 | // have to clip
|
|---|
| 4810 | painter.save();
|
|---|
| 4811 | int cs, ce;
|
|---|
| 4812 | if (rightToLeft) {
|
|---|
| 4813 | cs = (selEnd != start + len) ?
|
|---|
| 4814 | this->str->at(this->str->previousCursorPosition(selEnd)).x : xstart;
|
|---|
| 4815 | ce = (selStart != start) ?
|
|---|
| 4816 | this->str->at(this->str->previousCursorPosition(selStart)).x : xstart+tmpw;
|
|---|
| 4817 | } else {
|
|---|
| 4818 | cs = (selStart != start) ? this->str->at(selStart).x : xstart;
|
|---|
| 4819 | ce = (selEnd != start + len) ? this->str->at(selEnd).x : xstart+tmpw;
|
|---|
| 4820 | }
|
|---|
| 4821 | QRect r(cs, y, ce-cs, h);
|
|---|
| 4822 | if (extendLeft)
|
|---|
| 4823 | r.setLeft(0);
|
|---|
| 4824 | if (extendRight)
|
|---|
| 4825 | r.setRight(fullSelectionWidth);
|
|---|
| 4826 | QRegion reg(r);
|
|---|
| 4827 | if ( painter.hasClipping() )
|
|---|
| 4828 | reg &= painter.clipRegion(QPainter::CoordPainter);
|
|---|
| 4829 | painter.setClipRegion(reg, QPainter::CoordPainter);
|
|---|
| 4830 | }
|
|---|
| 4831 | int xleft = xstart;
|
|---|
| 4832 | if ( extendLeft ) {
|
|---|
| 4833 | tmpw += xstart;
|
|---|
| 4834 | xleft = 0;
|
|---|
| 4835 | }
|
|---|
| 4836 | if ( extendRight )
|
|---|
| 4837 | tmpw = fullSelectionWidth - xleft;
|
|---|
| 4838 | painter.fillRect( xleft, y, tmpw, h, color );
|
|---|
| 4839 | painter.drawText( xstart, y + baseLine, str, start, len, dir );
|
|---|
| 4840 | if (selStart != start || selEnd != start + len || selWrap)
|
|---|
| 4841 | painter.restore();
|
|---|
| 4842 | }
|
|---|
| 4843 | }
|
|---|
| 4844 | }
|
|---|
| 4845 |
|
|---|
| 4846 | if ( format->isMisspelled() ) {
|
|---|
| 4847 | painter.save();
|
|---|
| 4848 | painter.setPen( QPen( Qt::red, 1, Qt::DotLine ) );
|
|---|
| 4849 | painter.drawLine( xstart, y + baseLine + 1, xstart + w, y + baseLine + 1 );
|
|---|
| 4850 | painter.restore();
|
|---|
| 4851 | }
|
|---|
| 4852 |
|
|---|
| 4853 | if ( hasdoc && formatChar->isAnchor() && !formatChar->anchorHref().isEmpty() &&
|
|---|
| 4854 | document()->focusIndicator.parag == this &&
|
|---|
| 4855 | ( document()->focusIndicator.start >= start &&
|
|---|
| 4856 | document()->focusIndicator.start + document()->focusIndicator.len <= start + len ||
|
|---|
| 4857 | document()->focusIndicator.start <= start &&
|
|---|
| 4858 | document()->focusIndicator.start + document()->focusIndicator.len >= start + len ) )
|
|---|
| 4859 | painter.drawWinFocusRect( QRect( xstart, y, w, h ) );
|
|---|
| 4860 | }
|
|---|
| 4861 |
|
|---|
| 4862 | void QTextParagraph::drawLabel( QPainter* p, int x, int y, int w, int h, int base, const QColorGroup& cg )
|
|---|
| 4863 | {
|
|---|
| 4864 | QRect r ( x, y, w, h );
|
|---|
| 4865 | QStyleSheetItem::ListStyle s = listStyle();
|
|---|
| 4866 |
|
|---|
| 4867 | p->save();
|
|---|
| 4868 | QTextFormat *format = at( 0 )->format();
|
|---|
| 4869 | if ( format ) {
|
|---|
| 4870 | p->setPen( format->color() );
|
|---|
| 4871 | p->setFont( format->font() );
|
|---|
| 4872 | }
|
|---|
| 4873 | QFontMetrics fm( p->fontMetrics() );
|
|---|
| 4874 | int size = fm.lineSpacing() / 3;
|
|---|
| 4875 |
|
|---|
| 4876 | bool rtl = str->isRightToLeft();
|
|---|
| 4877 |
|
|---|
| 4878 | switch ( s ) {
|
|---|
| 4879 | case QStyleSheetItem::ListDecimal:
|
|---|
| 4880 | case QStyleSheetItem::ListLowerAlpha:
|
|---|
| 4881 | case QStyleSheetItem::ListUpperAlpha:
|
|---|
| 4882 | {
|
|---|
| 4883 | if ( list_val == -1 ) { // uninitialised list value, calcluate the right one
|
|---|
| 4884 | int depth = listDepth();
|
|---|
| 4885 | list_val--;
|
|---|
| 4886 | // ### evil, square and expensive. This needs to be done when formatting, not when painting
|
|---|
| 4887 | QTextParagraph* s = prev();
|
|---|
| 4888 | int depth_s;
|
|---|
| 4889 | while ( s && (depth_s = s->listDepth()) >= depth ) {
|
|---|
| 4890 | if ( depth_s == depth && s->isListItem() )
|
|---|
| 4891 | list_val--;
|
|---|
| 4892 | s = s->prev();
|
|---|
| 4893 | }
|
|---|
| 4894 | }
|
|---|
| 4895 |
|
|---|
| 4896 | int n = list_val;
|
|---|
| 4897 | if ( n < -1 )
|
|---|
| 4898 | n = -n - 1;
|
|---|
| 4899 | QString l;
|
|---|
| 4900 | switch ( s ) {
|
|---|
| 4901 | case QStyleSheetItem::ListLowerAlpha:
|
|---|
| 4902 | if ( n < 27 ) {
|
|---|
| 4903 | l = QChar( ('a' + (char) (n-1)));
|
|---|
| 4904 | break;
|
|---|
| 4905 | }
|
|---|
| 4906 | case QStyleSheetItem::ListUpperAlpha:
|
|---|
| 4907 | if ( n < 27 ) {
|
|---|
| 4908 | l = QChar( ('A' + (char) (n-1)));
|
|---|
| 4909 | break;
|
|---|
| 4910 | }
|
|---|
| 4911 | break;
|
|---|
| 4912 | default: //QStyleSheetItem::ListDecimal:
|
|---|
| 4913 | l.setNum( n );
|
|---|
| 4914 | break;
|
|---|
| 4915 | }
|
|---|
| 4916 | if (rtl)
|
|---|
| 4917 | l.prepend(" .");
|
|---|
| 4918 | else
|
|---|
| 4919 | l += QString::fromLatin1(". ");
|
|---|
| 4920 | int x = ( rtl ? r.left() : r.right() - fm.width(l));
|
|---|
| 4921 | p->drawText( x, r.top() + base, l );
|
|---|
| 4922 | }
|
|---|
| 4923 | break;
|
|---|
| 4924 | case QStyleSheetItem::ListSquare:
|
|---|
| 4925 | {
|
|---|
| 4926 | int x = rtl ? r.left() + size : r.right() - size*2;
|
|---|
| 4927 | QRect er( x, r.top() + fm.height() / 2 - size / 2, size, size );
|
|---|
| 4928 | p->fillRect( er , cg.brush( QColorGroup::Text ) );
|
|---|
| 4929 | }
|
|---|
| 4930 | break;
|
|---|
| 4931 | case QStyleSheetItem::ListCircle:
|
|---|
| 4932 | {
|
|---|
| 4933 | int x = rtl ? r.left() + size : r.right() - size*2;
|
|---|
| 4934 | QRect er( x, r.top() + fm.height() / 2 - size / 2, size, size);
|
|---|
| 4935 | p->drawEllipse( er );
|
|---|
| 4936 | }
|
|---|
| 4937 | break;
|
|---|
| 4938 | case QStyleSheetItem::ListDisc:
|
|---|
| 4939 | default:
|
|---|
| 4940 | {
|
|---|
| 4941 | p->setBrush( cg.brush( QColorGroup::Text ));
|
|---|
| 4942 | int x = rtl ? r.left() + size : r.right() - size*2;
|
|---|
| 4943 | QRect er( x, r.top() + fm.height() / 2 - size / 2, size, size);
|
|---|
| 4944 | p->drawEllipse( er );
|
|---|
| 4945 | p->setBrush( Qt::NoBrush );
|
|---|
| 4946 | }
|
|---|
| 4947 | break;
|
|---|
| 4948 | }
|
|---|
| 4949 |
|
|---|
| 4950 | p->restore();
|
|---|
| 4951 | }
|
|---|
| 4952 |
|
|---|
| 4953 | #ifndef QT_NO_DATASTREAM
|
|---|
| 4954 | void QTextParagraph::readStyleInformation( QDataStream& stream )
|
|---|
| 4955 | {
|
|---|
| 4956 | int int_align, int_lstyle;
|
|---|
| 4957 | uchar uchar_litem, uchar_rtext, uchar_dir;
|
|---|
| 4958 | stream >> int_align >> int_lstyle >> utm >> ubm >> ulm >> urm >> uflm
|
|---|
| 4959 | >> ulinespacing >> ldepth >> uchar_litem >> uchar_rtext >> uchar_dir;
|
|---|
| 4960 | align = int_align; lstyle = (QStyleSheetItem::ListStyle) int_lstyle;
|
|---|
| 4961 | litem = uchar_litem; rtext = uchar_rtext; str->setDirection( (QChar::Direction)uchar_dir );
|
|---|
| 4962 | QTextParagraph* s = prev() ? prev() : this;
|
|---|
| 4963 | while ( s ) {
|
|---|
| 4964 | s->invalidate( 0 );
|
|---|
| 4965 | s = s->next();
|
|---|
| 4966 | }
|
|---|
| 4967 | }
|
|---|
| 4968 |
|
|---|
| 4969 | void QTextParagraph::writeStyleInformation( QDataStream& stream ) const
|
|---|
| 4970 | {
|
|---|
| 4971 | stream << (int) align << (int) lstyle << utm << ubm << ulm << urm << uflm << ulinespacing << ldepth << (uchar)litem << (uchar)rtext << (uchar)str->direction();
|
|---|
| 4972 | }
|
|---|
| 4973 | #endif
|
|---|
| 4974 |
|
|---|
| 4975 |
|
|---|
| 4976 | void QTextParagraph::setListItem( bool li )
|
|---|
| 4977 | {
|
|---|
| 4978 | if ( (bool)litem == li )
|
|---|
| 4979 | return;
|
|---|
| 4980 | litem = li;
|
|---|
| 4981 | changed = TRUE;
|
|---|
| 4982 | QTextParagraph* s = prev() ? prev() : this;
|
|---|
| 4983 | while ( s ) {
|
|---|
| 4984 | s->invalidate( 0 );
|
|---|
| 4985 | s = s->next();
|
|---|
| 4986 | }
|
|---|
| 4987 | }
|
|---|
| 4988 |
|
|---|
| 4989 | void QTextParagraph::setListDepth( int depth ) {
|
|---|
| 4990 | if ( !hasdoc || depth == ldepth )
|
|---|
| 4991 | return;
|
|---|
| 4992 | ldepth = depth;
|
|---|
| 4993 | QTextParagraph* s = prev() ? prev() : this;
|
|---|
| 4994 | while ( s ) {
|
|---|
| 4995 | s->invalidate( 0 );
|
|---|
| 4996 | s = s->next();
|
|---|
| 4997 | }
|
|---|
| 4998 | }
|
|---|
| 4999 |
|
|---|
| 5000 | int *QTextParagraph::tabArray() const
|
|---|
| 5001 | {
|
|---|
| 5002 | int *ta = tArray;
|
|---|
| 5003 | if ( !ta && hasdoc )
|
|---|
| 5004 | ta = document()->tabArray();
|
|---|
| 5005 | return ta;
|
|---|
| 5006 | }
|
|---|
| 5007 |
|
|---|
| 5008 | int QTextParagraph::nextTab( int, int x )
|
|---|
| 5009 | {
|
|---|
| 5010 | int *ta = tArray;
|
|---|
| 5011 | if ( hasdoc ) {
|
|---|
| 5012 | if ( !ta )
|
|---|
| 5013 | ta = document()->tabArray();
|
|---|
| 5014 | tabStopWidth = document()->tabStopWidth();
|
|---|
| 5015 | }
|
|---|
| 5016 | if ( ta ) {
|
|---|
| 5017 | int i = 0;
|
|---|
| 5018 | while ( ta[ i ] ) {
|
|---|
| 5019 | if ( ta[ i ] >= x )
|
|---|
| 5020 | return tArray[ i ];
|
|---|
| 5021 | ++i;
|
|---|
| 5022 | }
|
|---|
| 5023 | return tArray[ 0 ];
|
|---|
| 5024 | } else {
|
|---|
| 5025 | int d;
|
|---|
| 5026 | if ( tabStopWidth != 0 )
|
|---|
| 5027 | d = x / tabStopWidth;
|
|---|
| 5028 | else
|
|---|
| 5029 | return x;
|
|---|
| 5030 | return tabStopWidth * ( d + 1 );
|
|---|
| 5031 | }
|
|---|
| 5032 | }
|
|---|
| 5033 |
|
|---|
| 5034 | void QTextParagraph::adjustToPainter( QPainter *p )
|
|---|
| 5035 | {
|
|---|
| 5036 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 5037 | for ( int i = 0; i < length(); ++i ) {
|
|---|
| 5038 | if ( at( i )->isCustom() )
|
|---|
| 5039 | at( i )->customItem()->adjustToPainter( p );
|
|---|
| 5040 | }
|
|---|
| 5041 | #endif
|
|---|
| 5042 | }
|
|---|
| 5043 |
|
|---|
| 5044 | QTextFormatCollection *QTextParagraph::formatCollection() const
|
|---|
| 5045 | {
|
|---|
| 5046 | if ( hasdoc )
|
|---|
| 5047 | return document()->formatCollection();
|
|---|
| 5048 | QTextFormatCollection* fc = &pseudoDocument()->collection;
|
|---|
| 5049 | if ( paintdevice != fc->paintDevice() )
|
|---|
| 5050 | fc->setPaintDevice( paintdevice );
|
|---|
| 5051 | return fc;
|
|---|
| 5052 | }
|
|---|
| 5053 |
|
|---|
| 5054 | QString QTextParagraph::richText() const
|
|---|
| 5055 | {
|
|---|
| 5056 | QString s;
|
|---|
| 5057 | QTextStringChar *formatChar = 0;
|
|---|
| 5058 | QString spaces;
|
|---|
| 5059 | bool doStart = richTextExportStart && richTextExportStart->paragraph() == this;
|
|---|
| 5060 | bool doEnd = richTextExportEnd && richTextExportEnd->paragraph() == this;
|
|---|
| 5061 | int i;
|
|---|
| 5062 | for ( i = 0; i < length()-1; ++i ) {
|
|---|
| 5063 | if ( doStart && i && richTextExportStart->index() == i )
|
|---|
| 5064 | s += "<!--StartFragment-->";
|
|---|
| 5065 | if ( doEnd && richTextExportEnd->index() == i )
|
|---|
| 5066 | s += "<!--EndFragment-->";
|
|---|
| 5067 | QTextStringChar *c = &str->at( i );
|
|---|
| 5068 | if ( c->isAnchor() && !c->anchorName().isEmpty() ) {
|
|---|
| 5069 | if ( c->anchorName().contains( '#' ) ) {
|
|---|
| 5070 | QStringList l = QStringList::split( '#', c->anchorName() );
|
|---|
| 5071 | for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it )
|
|---|
| 5072 | s += "<a name=\"" + *it + "\"></a>";
|
|---|
| 5073 | } else {
|
|---|
| 5074 | s += "<a name=\"" + c->anchorName() + "\"></a>";
|
|---|
| 5075 | }
|
|---|
| 5076 | }
|
|---|
| 5077 | if ( !formatChar ) {
|
|---|
| 5078 | s += c->format()->makeFormatChangeTags( formatCollection()->defaultFormat(),
|
|---|
| 5079 | 0, QString::null, c->anchorHref() );
|
|---|
| 5080 | formatChar = c;
|
|---|
| 5081 | } else if ( ( formatChar->format()->key() != c->format()->key() ) ||
|
|---|
| 5082 | (c->anchorHref() != formatChar->anchorHref() ) ) {
|
|---|
| 5083 | s += c->format()->makeFormatChangeTags( formatCollection()->defaultFormat(),
|
|---|
| 5084 | formatChar->format() , formatChar->anchorHref(), c->anchorHref() );
|
|---|
| 5085 | formatChar = c;
|
|---|
| 5086 | }
|
|---|
| 5087 | if ( c->c == '<' )
|
|---|
| 5088 | s += "<";
|
|---|
| 5089 | else if ( c->c == '>' )
|
|---|
| 5090 | s += ">";
|
|---|
| 5091 | else if ( c->c =='&' )
|
|---|
| 5092 | s += "&";
|
|---|
| 5093 | else if ( c->c =='\"' )
|
|---|
| 5094 | s += """;
|
|---|
| 5095 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 5096 | else if ( c->isCustom() )
|
|---|
| 5097 | s += c->customItem()->richText();
|
|---|
| 5098 | #endif
|
|---|
| 5099 | else if ( c->c == '\n' || c->c == QChar_linesep )
|
|---|
| 5100 | s += "<br />"; // space on purpose for compatibility with Netscape, Lynx & Co.
|
|---|
| 5101 | else
|
|---|
| 5102 | s += c->c;
|
|---|
| 5103 | }
|
|---|
| 5104 | if ( doEnd && richTextExportEnd->index() == i )
|
|---|
| 5105 | s += "<!--EndFragment-->";
|
|---|
| 5106 | if ( formatChar )
|
|---|
| 5107 | s += formatChar->format()->makeFormatEndTags( formatCollection()->defaultFormat(), formatChar->anchorHref() );
|
|---|
| 5108 | return s;
|
|---|
| 5109 | }
|
|---|
| 5110 |
|
|---|
| 5111 | void QTextParagraph::addCommand( QTextCommand *cmd )
|
|---|
| 5112 | {
|
|---|
| 5113 | if ( !hasdoc )
|
|---|
| 5114 | pseudoDocument()->commandHistory->addCommand( cmd );
|
|---|
| 5115 | else
|
|---|
| 5116 | document()->commands()->addCommand( cmd );
|
|---|
| 5117 | }
|
|---|
| 5118 |
|
|---|
| 5119 | QTextCursor *QTextParagraph::undo( QTextCursor *c )
|
|---|
| 5120 | {
|
|---|
| 5121 | if ( !hasdoc )
|
|---|
| 5122 | return pseudoDocument()->commandHistory->undo( c );
|
|---|
| 5123 | return document()->commands()->undo( c );
|
|---|
| 5124 | }
|
|---|
| 5125 |
|
|---|
| 5126 | QTextCursor *QTextParagraph::redo( QTextCursor *c )
|
|---|
| 5127 | {
|
|---|
| 5128 | if ( !hasdoc )
|
|---|
| 5129 | return pseudoDocument()->commandHistory->redo( c );
|
|---|
| 5130 | return document()->commands()->redo( c );
|
|---|
| 5131 | }
|
|---|
| 5132 |
|
|---|
| 5133 | int QTextParagraph::topMargin() const
|
|---|
| 5134 | {
|
|---|
| 5135 | int m = 0;
|
|---|
| 5136 | if ( rtext ) {
|
|---|
| 5137 | m = isListItem() ? (document()->li_tm/QMAX(1,listDepth()*listDepth())) :
|
|---|
| 5138 | ( listDepth() ? 0 : document()->par_tm );
|
|---|
| 5139 | if ( listDepth() == 1 &&( !prev() || prev()->listDepth() < listDepth() ) )
|
|---|
| 5140 | m = QMAX( m, document()->list_tm );
|
|---|
| 5141 | }
|
|---|
| 5142 | m += utm;
|
|---|
| 5143 | return scale( m, QTextFormat::painter() );
|
|---|
| 5144 | }
|
|---|
| 5145 |
|
|---|
| 5146 | int QTextParagraph::bottomMargin() const
|
|---|
| 5147 | {
|
|---|
| 5148 | int m = 0;
|
|---|
| 5149 | if ( rtext ) {
|
|---|
| 5150 | m = isListItem() ? (document()->li_bm/QMAX(1,listDepth()*listDepth())) :
|
|---|
| 5151 | ( listDepth() ? 0 : document()->par_bm );
|
|---|
| 5152 | if ( listDepth() == 1 &&( !next() || next()->listDepth() < listDepth() ) )
|
|---|
| 5153 | m = QMAX( m, document()->list_bm );
|
|---|
| 5154 | }
|
|---|
| 5155 | m += ubm;
|
|---|
| 5156 | return scale( m, QTextFormat::painter() );
|
|---|
| 5157 | }
|
|---|
| 5158 |
|
|---|
| 5159 | int QTextParagraph::leftMargin() const
|
|---|
| 5160 | {
|
|---|
| 5161 | int m = ulm;
|
|---|
| 5162 | if ( listDepth() && !string()->isRightToLeft() )
|
|---|
| 5163 | m += listDepth() * document()->list_lm;
|
|---|
| 5164 | return scale( m, QTextFormat::painter() );
|
|---|
| 5165 | }
|
|---|
| 5166 |
|
|---|
| 5167 | int QTextParagraph::firstLineMargin() const
|
|---|
| 5168 | {
|
|---|
| 5169 | int m = uflm;
|
|---|
| 5170 | return scale( m, QTextFormat::painter() );
|
|---|
| 5171 | }
|
|---|
| 5172 |
|
|---|
| 5173 | int QTextParagraph::rightMargin() const
|
|---|
| 5174 | {
|
|---|
| 5175 | int m = urm;
|
|---|
| 5176 | if ( listDepth() && string()->isRightToLeft() )
|
|---|
| 5177 | m += listDepth() * document()->list_lm;
|
|---|
| 5178 | return scale( m, QTextFormat::painter() );
|
|---|
| 5179 | }
|
|---|
| 5180 |
|
|---|
| 5181 | int QTextParagraph::lineSpacing() const
|
|---|
| 5182 | {
|
|---|
| 5183 | int l = ulinespacing;
|
|---|
| 5184 | l = scale( l, QTextFormat::painter() );
|
|---|
| 5185 | return l;
|
|---|
| 5186 | }
|
|---|
| 5187 |
|
|---|
| 5188 | void QTextParagraph::copyParagData( QTextParagraph *parag )
|
|---|
| 5189 | {
|
|---|
| 5190 | rtext = parag->rtext;
|
|---|
| 5191 | lstyle = parag->lstyle;
|
|---|
| 5192 | ldepth = parag->ldepth;
|
|---|
| 5193 | litem = parag->litem;
|
|---|
| 5194 | align = parag->align;
|
|---|
| 5195 | utm = parag->utm;
|
|---|
| 5196 | ubm = parag->ubm;
|
|---|
| 5197 | urm = parag->urm;
|
|---|
| 5198 | ulm = parag->ulm;
|
|---|
| 5199 | uflm = parag->uflm;
|
|---|
| 5200 | ulinespacing = parag->ulinespacing;
|
|---|
| 5201 | QColor *c = parag->backgroundColor();
|
|---|
| 5202 | if ( c )
|
|---|
| 5203 | setBackgroundColor( *c );
|
|---|
| 5204 | str->setDirection( parag->str->direction() );
|
|---|
| 5205 | }
|
|---|
| 5206 |
|
|---|
| 5207 | void QTextParagraph::show()
|
|---|
| 5208 | {
|
|---|
| 5209 | if ( visible || !hasdoc )
|
|---|
| 5210 | return;
|
|---|
| 5211 | visible = TRUE;
|
|---|
| 5212 | }
|
|---|
| 5213 |
|
|---|
| 5214 | void QTextParagraph::hide()
|
|---|
| 5215 | {
|
|---|
| 5216 | if ( !visible || !hasdoc )
|
|---|
| 5217 | return;
|
|---|
| 5218 | visible = FALSE;
|
|---|
| 5219 | }
|
|---|
| 5220 |
|
|---|
| 5221 | void QTextParagraph::setDirection( QChar::Direction d )
|
|---|
| 5222 | {
|
|---|
| 5223 | if ( str && str->direction() != d ) {
|
|---|
| 5224 | str->setDirection( d );
|
|---|
| 5225 | invalidate( 0 );
|
|---|
| 5226 | }
|
|---|
| 5227 | }
|
|---|
| 5228 |
|
|---|
| 5229 | QChar::Direction QTextParagraph::direction() const
|
|---|
| 5230 | {
|
|---|
| 5231 | return (str ? str->direction() : QChar::DirON );
|
|---|
| 5232 | }
|
|---|
| 5233 |
|
|---|
| 5234 | void QTextParagraph::setChanged( bool b, bool recursive )
|
|---|
| 5235 | {
|
|---|
| 5236 | changed = b;
|
|---|
| 5237 | if ( recursive ) {
|
|---|
| 5238 | if ( document() && document()->parentParagraph() )
|
|---|
| 5239 | document()->parentParagraph()->setChanged( b, recursive );
|
|---|
| 5240 | }
|
|---|
| 5241 | }
|
|---|
| 5242 |
|
|---|
| 5243 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 5244 |
|
|---|
| 5245 |
|
|---|
| 5246 | QTextPreProcessor::QTextPreProcessor()
|
|---|
| 5247 | {
|
|---|
| 5248 | }
|
|---|
| 5249 |
|
|---|
| 5250 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 5251 |
|
|---|
| 5252 | QTextFormatter::QTextFormatter()
|
|---|
| 5253 | : thisminw(0), thiswused(0), wrapEnabled( TRUE ), wrapColumn( -1 ), biw( FALSE )
|
|---|
| 5254 | {
|
|---|
| 5255 | }
|
|---|
| 5256 |
|
|---|
| 5257 | QTextLineStart *QTextFormatter::formatLine( QTextParagraph *parag, QTextString *string, QTextLineStart *line,
|
|---|
| 5258 | QTextStringChar *startChar, QTextStringChar *lastChar, int align, int space )
|
|---|
| 5259 | {
|
|---|
| 5260 | if ( lastChar < startChar )
|
|---|
| 5261 | return new QTextLineStart;
|
|---|
| 5262 | #ifndef QT_NO_COMPLEXTEXT
|
|---|
| 5263 | if( string->isBidi() )
|
|---|
| 5264 | return bidiReorderLine( parag, string, line, startChar, lastChar, align, space );
|
|---|
| 5265 | #endif
|
|---|
| 5266 | int start = (startChar - &string->at(0));
|
|---|
| 5267 | int last = (lastChar - &string->at(0) );
|
|---|
| 5268 |
|
|---|
| 5269 | // ignore white space at the end of the line.
|
|---|
| 5270 | QTextStringChar *ch = lastChar;
|
|---|
| 5271 | while ( ch > startChar && ch->whiteSpace ) {
|
|---|
| 5272 | space += ch->format()->width( ' ' );
|
|---|
| 5273 | --ch;
|
|---|
| 5274 | }
|
|---|
| 5275 |
|
|---|
| 5276 | if (space < 0)
|
|---|
| 5277 | space = 0;
|
|---|
| 5278 |
|
|---|
| 5279 | // do alignment Auto == Left in this case
|
|---|
| 5280 | if ( align & Qt::AlignHCenter || align & Qt::AlignRight ) {
|
|---|
| 5281 | if ( align & Qt::AlignHCenter )
|
|---|
| 5282 | space /= 2;
|
|---|
| 5283 | for ( int j = start; j <= last; ++j )
|
|---|
| 5284 | string->at( j ).x += space;
|
|---|
| 5285 | } else if ( align & Qt::AlignJustify ) {
|
|---|
| 5286 | int numSpaces = 0;
|
|---|
| 5287 | // End at "last-1", the last space ends up with a width of 0
|
|---|
| 5288 | for ( int j = last-1; j >= start; --j ) {
|
|---|
| 5289 | // Start at last tab, if any.
|
|---|
| 5290 | QTextStringChar &ch = string->at( j );
|
|---|
| 5291 | if ( ch.c == '\t' ) {
|
|---|
| 5292 | start = j+1;
|
|---|
| 5293 | break;
|
|---|
| 5294 | }
|
|---|
| 5295 | if(ch.whiteSpace)
|
|---|
| 5296 | numSpaces++;
|
|---|
| 5297 | }
|
|---|
| 5298 | int toAdd = 0;
|
|---|
| 5299 | for ( int k = start + 1; k <= last; ++k ) {
|
|---|
| 5300 | QTextStringChar &ch = string->at( k );
|
|---|
| 5301 | if( numSpaces && ch.whiteSpace ) {
|
|---|
| 5302 | int s = space / numSpaces;
|
|---|
| 5303 | toAdd += s;
|
|---|
| 5304 | space -= s;
|
|---|
| 5305 | numSpaces--;
|
|---|
| 5306 | }
|
|---|
| 5307 | string->at( k ).x += toAdd;
|
|---|
| 5308 | }
|
|---|
| 5309 | }
|
|---|
| 5310 |
|
|---|
| 5311 | if ( last >= 0 && last < string->length() )
|
|---|
| 5312 | line->w = string->at( last ).x + string->width( last );
|
|---|
| 5313 | else
|
|---|
| 5314 | line->w = 0;
|
|---|
| 5315 |
|
|---|
| 5316 | return new QTextLineStart;
|
|---|
| 5317 | }
|
|---|
| 5318 |
|
|---|
| 5319 | #ifndef QT_NO_COMPLEXTEXT
|
|---|
| 5320 |
|
|---|
| 5321 | #ifdef BIDI_DEBUG
|
|---|
| 5322 | #include <iostream>
|
|---|
| 5323 | #endif
|
|---|
| 5324 |
|
|---|
| 5325 | // collects one line of the paragraph and transforms it to visual order
|
|---|
| 5326 | QTextLineStart *QTextFormatter::bidiReorderLine( QTextParagraph * /*parag*/, QTextString *text, QTextLineStart *line,
|
|---|
| 5327 | QTextStringChar *startChar, QTextStringChar *lastChar, int align, int space )
|
|---|
| 5328 | {
|
|---|
| 5329 | // ignore white space at the end of the line.
|
|---|
| 5330 | int endSpaces = 0;
|
|---|
| 5331 | while ( lastChar > startChar && lastChar->whiteSpace ) {
|
|---|
| 5332 | space += lastChar->format()->width( ' ' );
|
|---|
| 5333 | --lastChar;
|
|---|
| 5334 | ++endSpaces;
|
|---|
| 5335 | }
|
|---|
| 5336 |
|
|---|
| 5337 | int start = (startChar - &text->at(0));
|
|---|
| 5338 | int last = (lastChar - &text->at(0) );
|
|---|
| 5339 |
|
|---|
| 5340 | int length = lastChar - startChar + 1;
|
|---|
| 5341 |
|
|---|
| 5342 |
|
|---|
| 5343 | int x = startChar->x;
|
|---|
| 5344 |
|
|---|
| 5345 | unsigned char _levels[256];
|
|---|
| 5346 | int _visual[256];
|
|---|
| 5347 |
|
|---|
| 5348 | unsigned char *levels = _levels;
|
|---|
| 5349 | int *visual = _visual;
|
|---|
| 5350 |
|
|---|
| 5351 | if ( length > 255 ) {
|
|---|
| 5352 | levels = (unsigned char *)malloc( length*sizeof( unsigned char ) );
|
|---|
| 5353 | visual = (int *)malloc( length*sizeof( int ) );
|
|---|
| 5354 | }
|
|---|
| 5355 |
|
|---|
| 5356 | //qDebug("bidiReorderLine: length=%d (%d-%d)", length, start, last );
|
|---|
| 5357 |
|
|---|
| 5358 | QTextStringChar *ch = startChar;
|
|---|
| 5359 | unsigned char *l = levels;
|
|---|
| 5360 | while ( ch <= lastChar ) {
|
|---|
| 5361 | //qDebug( " level: %d", ch->bidiLevel );
|
|---|
| 5362 | *(l++) = (ch++)->bidiLevel;
|
|---|
| 5363 | }
|
|---|
| 5364 |
|
|---|
| 5365 | QTextEngine::bidiReorder( length, levels, visual );
|
|---|
| 5366 |
|
|---|
| 5367 | // now construct the reordered string out of the runs...
|
|---|
| 5368 |
|
|---|
| 5369 | int numSpaces = 0;
|
|---|
| 5370 | // set the correct alignment. This is a bit messy....
|
|---|
| 5371 | if( align == Qt::AlignAuto ) {
|
|---|
| 5372 | // align according to directionality of the paragraph...
|
|---|
| 5373 | if ( text->isRightToLeft() )
|
|---|
| 5374 | align = Qt::AlignRight;
|
|---|
| 5375 | }
|
|---|
| 5376 |
|
|---|
| 5377 | // This is not really correct, but as we can't make the scrollbar move to the left of the origin,
|
|---|
| 5378 | // this ensures all text can be scrolled to and read.
|
|---|
| 5379 | if (space < 0)
|
|---|
| 5380 | space = 0;
|
|---|
| 5381 |
|
|---|
| 5382 | if ( align & Qt::AlignHCenter )
|
|---|
| 5383 | x += space/2;
|
|---|
| 5384 | else if ( align & Qt::AlignRight )
|
|---|
| 5385 | x += space;
|
|---|
| 5386 | else if ( align & Qt::AlignJustify ) {
|
|---|
| 5387 | // End at "last-1", the last space ends up with a width of 0
|
|---|
| 5388 | for ( int j = last-1; j >= start; --j ) {
|
|---|
| 5389 | // Start at last tab, if any.
|
|---|
| 5390 | QTextStringChar &ch = text->at( j );
|
|---|
| 5391 | if ( ch.c == '\t' ) {
|
|---|
| 5392 | start = j+1;
|
|---|
| 5393 | break;
|
|---|
| 5394 | }
|
|---|
| 5395 | if(ch.whiteSpace)
|
|---|
| 5396 | numSpaces++;
|
|---|
| 5397 | }
|
|---|
| 5398 | }
|
|---|
| 5399 |
|
|---|
| 5400 | int toAdd = 0;
|
|---|
| 5401 | int xorig = x;
|
|---|
| 5402 | QTextStringChar *lc = startChar + visual[0];
|
|---|
| 5403 | for ( int i = 0; i < length; i++ ) {
|
|---|
| 5404 | QTextStringChar *ch = startChar + visual[i];
|
|---|
| 5405 | if (numSpaces && ch->whiteSpace) {
|
|---|
| 5406 | int s = space / numSpaces;
|
|---|
| 5407 | toAdd += s;
|
|---|
| 5408 | space -= s;
|
|---|
| 5409 | numSpaces--;
|
|---|
| 5410 | }
|
|---|
| 5411 |
|
|---|
| 5412 | if (lc->format() != ch->format() && !ch->c.isSpace()
|
|---|
| 5413 | && lc->format()->font().italic() && !ch->format()->font().italic()) {
|
|---|
| 5414 | int rb = lc->format()->fontMetrics().rightBearing(lc->c);
|
|---|
| 5415 | if (rb < 0)
|
|---|
| 5416 | x -= rb;
|
|---|
| 5417 | }
|
|---|
| 5418 |
|
|---|
| 5419 | ch->x = x + toAdd;
|
|---|
| 5420 | //qDebug("visual: %d (%p) placed at %d rightToLeft=%d", visual[i], ch, x +toAdd, ch->rightToLeft );
|
|---|
| 5421 | int ww = 0;
|
|---|
| 5422 | if ( ch->c.unicode() >= 32 || ch->c == '\t' || ch->c == '\n' || ch->isCustom() ) {
|
|---|
| 5423 | ww = text->width( start+visual[i] );
|
|---|
| 5424 | } else {
|
|---|
| 5425 | ww = ch->format()->width( ' ' );
|
|---|
| 5426 | }
|
|---|
| 5427 | x += ww;
|
|---|
| 5428 | lc = ch;
|
|---|
| 5429 | }
|
|---|
| 5430 | x += toAdd;
|
|---|
| 5431 |
|
|---|
| 5432 | while ( endSpaces-- ) {
|
|---|
| 5433 | ++lastChar;
|
|---|
| 5434 | int sw = lastChar->format()->width( ' ' );
|
|---|
| 5435 | if ( lastChar->rightToLeft ) {
|
|---|
| 5436 | xorig -= sw;
|
|---|
| 5437 | lastChar->x = xorig;
|
|---|
| 5438 | } else {
|
|---|
| 5439 | lastChar->x = x;
|
|---|
| 5440 | x += sw;
|
|---|
| 5441 | }
|
|---|
| 5442 | }
|
|---|
| 5443 |
|
|---|
| 5444 | line->w = x;
|
|---|
| 5445 |
|
|---|
| 5446 | if ( length > 255 ) {
|
|---|
| 5447 | free( levels );
|
|---|
| 5448 | free( visual );
|
|---|
| 5449 | }
|
|---|
| 5450 |
|
|---|
| 5451 | return new QTextLineStart;
|
|---|
| 5452 | }
|
|---|
| 5453 | #endif
|
|---|
| 5454 |
|
|---|
| 5455 |
|
|---|
| 5456 | void QTextFormatter::insertLineStart( QTextParagraph *parag, int index, QTextLineStart *ls )
|
|---|
| 5457 | {
|
|---|
| 5458 | QMap<int, QTextLineStart*>::Iterator it;
|
|---|
| 5459 | if ( ( it = parag->lineStartList().find( index ) ) == parag->lineStartList().end() ) {
|
|---|
| 5460 | parag->lineStartList().insert( index, ls );
|
|---|
| 5461 | } else {
|
|---|
| 5462 | delete *it;
|
|---|
| 5463 | parag->lineStartList().remove( it );
|
|---|
| 5464 | parag->lineStartList().insert( index, ls );
|
|---|
| 5465 | }
|
|---|
| 5466 | }
|
|---|
| 5467 |
|
|---|
| 5468 |
|
|---|
| 5469 | /* Standard pagebreak algorithm using QTextFlow::adjustFlow. Returns
|
|---|
| 5470 | the shift of the paragraphs bottom line.
|
|---|
| 5471 | */
|
|---|
| 5472 | int QTextFormatter::formatVertically( QTextDocument* doc, QTextParagraph* parag )
|
|---|
| 5473 | {
|
|---|
| 5474 | int oldHeight = parag->rect().height();
|
|---|
| 5475 | QMap<int, QTextLineStart*>& lineStarts = parag->lineStartList();
|
|---|
| 5476 | QMap<int, QTextLineStart*>::Iterator it = lineStarts.begin();
|
|---|
| 5477 | int h = parag->prev() ? QMAX(parag->prev()->bottomMargin(),parag->topMargin() ) / 2: 0;
|
|---|
| 5478 | for ( ; it != lineStarts.end() ; ++it ) {
|
|---|
| 5479 | QTextLineStart * ls = it.data();
|
|---|
| 5480 | ls->y = h;
|
|---|
| 5481 | QTextStringChar *c = ¶g->string()->at(it.key());
|
|---|
| 5482 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 5483 | if ( c && c->customItem() && c->customItem()->ownLine() ) {
|
|---|
| 5484 | int h = c->customItem()->height;
|
|---|
| 5485 | c->customItem()->pageBreak( parag->rect().y() + ls->y + ls->baseLine - h, doc->flow() );
|
|---|
| 5486 | int delta = c->customItem()->height - h;
|
|---|
| 5487 | ls->h += delta;
|
|---|
| 5488 | if ( delta )
|
|---|
| 5489 | parag->setMovedDown( TRUE );
|
|---|
| 5490 | } else
|
|---|
| 5491 | #endif
|
|---|
| 5492 | {
|
|---|
| 5493 |
|
|---|
| 5494 | int shift = doc->flow()->adjustFlow( parag->rect().y() + ls->y, ls->w, ls->h );
|
|---|
| 5495 | ls->y += shift;
|
|---|
| 5496 | if ( shift )
|
|---|
| 5497 | parag->setMovedDown( TRUE );
|
|---|
| 5498 | }
|
|---|
| 5499 | h = ls->y + ls->h;
|
|---|
| 5500 | }
|
|---|
| 5501 | int m = parag->bottomMargin();
|
|---|
| 5502 | if ( !parag->next() )
|
|---|
| 5503 | m = 0;
|
|---|
| 5504 | else
|
|---|
| 5505 | m = QMAX(m, parag->next()->topMargin() ) / 2;
|
|---|
| 5506 | h += m;
|
|---|
| 5507 | parag->setHeight( h );
|
|---|
| 5508 | return h - oldHeight;
|
|---|
| 5509 | }
|
|---|
| 5510 |
|
|---|
| 5511 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 5512 |
|
|---|
| 5513 | QTextFormatterBreakInWords::QTextFormatterBreakInWords()
|
|---|
| 5514 | {
|
|---|
| 5515 | }
|
|---|
| 5516 |
|
|---|
| 5517 | #define SPACE(s) s
|
|---|
| 5518 |
|
|---|
| 5519 | int QTextFormatterBreakInWords::format( QTextDocument *doc,QTextParagraph *parag,
|
|---|
| 5520 | int start, const QMap<int, QTextLineStart*> & )
|
|---|
| 5521 | {
|
|---|
| 5522 | // make sure bidi information is correct.
|
|---|
| 5523 | (void )parag->string()->isBidi();
|
|---|
| 5524 |
|
|---|
| 5525 | QTextStringChar *c = 0;
|
|---|
| 5526 | QTextStringChar *firstChar = 0;
|
|---|
| 5527 | int left = doc ? parag->leftMargin() + doc->leftMargin() : 0;
|
|---|
| 5528 | int x = left + ( doc ? parag->firstLineMargin() : 0 );
|
|---|
| 5529 | int dw = parag->documentVisibleWidth() - ( doc ? doc->rightMargin() : 0 );
|
|---|
| 5530 | int y = parag->prev() ? QMAX(parag->prev()->bottomMargin(),parag->topMargin()) / 2: 0;
|
|---|
| 5531 | int h = y;
|
|---|
| 5532 | int len = parag->length();
|
|---|
| 5533 | if ( doc )
|
|---|
| 5534 | x = doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), x, 4 );
|
|---|
| 5535 | int rm = parag->rightMargin();
|
|---|
| 5536 | int w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
|
|---|
| 5537 | bool fullWidth = TRUE;
|
|---|
| 5538 | int minw = 0;
|
|---|
| 5539 | int wused = 0;
|
|---|
| 5540 | bool wrapEnabled = isWrapEnabled( parag );
|
|---|
| 5541 |
|
|---|
| 5542 | start = 0; //######### what is the point with start?! (Matthias)
|
|---|
| 5543 | if ( start == 0 )
|
|---|
| 5544 | c = ¶g->string()->at( 0 );
|
|---|
| 5545 |
|
|---|
| 5546 | int i = start;
|
|---|
| 5547 | QTextLineStart *lineStart = new QTextLineStart( y, y, 0 );
|
|---|
| 5548 | insertLineStart( parag, 0, lineStart );
|
|---|
| 5549 |
|
|---|
| 5550 | QPainter *painter = QTextFormat::painter();
|
|---|
| 5551 |
|
|---|
| 5552 | int col = 0;
|
|---|
| 5553 | int ww = 0;
|
|---|
| 5554 | QChar lastChr;
|
|---|
| 5555 | for ( ; i < len; ++i, ++col ) {
|
|---|
| 5556 | if ( c )
|
|---|
| 5557 | lastChr = c->c;
|
|---|
| 5558 | c = ¶g->string()->at( i );
|
|---|
| 5559 | // ### the lines below should not be needed
|
|---|
| 5560 | if ( painter )
|
|---|
| 5561 | c->format()->setPainter( painter );
|
|---|
| 5562 | if ( i > 0 ) {
|
|---|
| 5563 | c->lineStart = 0;
|
|---|
| 5564 | } else {
|
|---|
| 5565 | c->lineStart = 1;
|
|---|
| 5566 | firstChar = c;
|
|---|
| 5567 | }
|
|---|
| 5568 | if ( c->c.unicode() >= 32 || c->isCustom() ) {
|
|---|
| 5569 | ww = parag->string()->width( i );
|
|---|
| 5570 | } else if ( c->c == '\t' ) {
|
|---|
| 5571 | int nx = parag->nextTab( i, x - left ) + left;
|
|---|
| 5572 | if ( nx < x )
|
|---|
| 5573 | ww = w - x;
|
|---|
| 5574 | else
|
|---|
| 5575 | ww = nx - x;
|
|---|
| 5576 | } else {
|
|---|
| 5577 | ww = c->format()->width( ' ' );
|
|---|
| 5578 | }
|
|---|
| 5579 |
|
|---|
| 5580 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 5581 | if ( c->isCustom() && c->customItem()->ownLine() ) {
|
|---|
| 5582 | x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
|
|---|
| 5583 | w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
|
|---|
| 5584 | c->customItem()->resize( w - x );
|
|---|
| 5585 | w = dw;
|
|---|
| 5586 | y += h;
|
|---|
| 5587 | h = c->height();
|
|---|
| 5588 | lineStart = new QTextLineStart( y, h, h );
|
|---|
| 5589 | insertLineStart( parag, i, lineStart );
|
|---|
| 5590 | c->lineStart = 1;
|
|---|
| 5591 | firstChar = c;
|
|---|
| 5592 | x = 0xffffff;
|
|---|
| 5593 | continue;
|
|---|
| 5594 | }
|
|---|
| 5595 | #endif
|
|---|
| 5596 |
|
|---|
| 5597 | if ( wrapEnabled &&
|
|---|
| 5598 | ( wrapAtColumn() == -1 && x + ww > w ||
|
|---|
| 5599 | wrapAtColumn() != -1 && col >= wrapAtColumn() ) ) {
|
|---|
| 5600 | x = doc ? parag->document()->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
|
|---|
| 5601 | w = dw;
|
|---|
| 5602 | y += h;
|
|---|
| 5603 | h = c->height();
|
|---|
| 5604 | lineStart = formatLine( parag, parag->string(), lineStart, firstChar, c-1 );
|
|---|
| 5605 | lineStart->y = y;
|
|---|
| 5606 | insertLineStart( parag, i, lineStart );
|
|---|
| 5607 | lineStart->baseLine = c->ascent();
|
|---|
| 5608 | lineStart->h = c->height();
|
|---|
| 5609 | c->lineStart = 1;
|
|---|
| 5610 | firstChar = c;
|
|---|
| 5611 | col = 0;
|
|---|
| 5612 | if ( wrapAtColumn() != -1 )
|
|---|
| 5613 | minw = QMAX( minw, w );
|
|---|
| 5614 | } else if ( lineStart ) {
|
|---|
| 5615 | lineStart->baseLine = QMAX( lineStart->baseLine, c->ascent() );
|
|---|
| 5616 | h = QMAX( h, c->height() );
|
|---|
| 5617 | lineStart->h = h;
|
|---|
| 5618 | }
|
|---|
| 5619 |
|
|---|
| 5620 | c->x = x;
|
|---|
| 5621 | x += ww;
|
|---|
| 5622 | wused = QMAX( wused, x );
|
|---|
| 5623 | }
|
|---|
| 5624 |
|
|---|
| 5625 | int m = parag->bottomMargin();
|
|---|
| 5626 | if ( !parag->next() )
|
|---|
| 5627 | m = 0;
|
|---|
| 5628 | else
|
|---|
| 5629 | m = QMAX(m, parag->next()->topMargin() ) / 2;
|
|---|
| 5630 | parag->setFullWidth( fullWidth );
|
|---|
| 5631 | y += h + m;
|
|---|
| 5632 | if ( doc )
|
|---|
| 5633 | minw += doc->rightMargin();
|
|---|
| 5634 | if ( !wrapEnabled )
|
|---|
| 5635 | minw = QMAX(minw, wused);
|
|---|
| 5636 |
|
|---|
| 5637 | thisminw = minw;
|
|---|
| 5638 | thiswused = wused;
|
|---|
| 5639 | return y;
|
|---|
| 5640 | }
|
|---|
| 5641 |
|
|---|
| 5642 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 5643 |
|
|---|
| 5644 | QTextFormatterBreakWords::QTextFormatterBreakWords()
|
|---|
| 5645 | {
|
|---|
| 5646 | }
|
|---|
| 5647 |
|
|---|
| 5648 | #define DO_FLOW( lineStart ) do{ if ( doc && doc->isPageBreakEnabled() ) { \
|
|---|
| 5649 | int yflow = lineStart->y + parag->rect().y();\
|
|---|
| 5650 | int shift = doc->flow()->adjustFlow( yflow, dw, lineStart->h ); \
|
|---|
| 5651 | lineStart->y += shift;\
|
|---|
| 5652 | y += shift;\
|
|---|
| 5653 | }}while(FALSE)
|
|---|
| 5654 |
|
|---|
| 5655 | int QTextFormatterBreakWords::format( QTextDocument *doc, QTextParagraph *parag,
|
|---|
| 5656 | int start, const QMap<int, QTextLineStart*> & )
|
|---|
| 5657 | {
|
|---|
| 5658 | // make sure bidi information is correct.
|
|---|
| 5659 | (void )parag->string()->isBidi();
|
|---|
| 5660 |
|
|---|
| 5661 | QTextStringChar *c = 0;
|
|---|
| 5662 | QTextStringChar *firstChar = 0;
|
|---|
| 5663 | QTextString *string = parag->string();
|
|---|
| 5664 | int left = doc ? parag->leftMargin() + doc->leftMargin() : 0;
|
|---|
| 5665 | int x = left + ( doc ? parag->firstLineMargin() : 0 );
|
|---|
| 5666 | int y = parag->prev() ? QMAX(parag->prev()->bottomMargin(),parag->topMargin()) / 2: 0;
|
|---|
| 5667 | int h = y;
|
|---|
| 5668 | int len = parag->length();
|
|---|
| 5669 | if ( doc )
|
|---|
| 5670 | x = doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), x, 0 );
|
|---|
| 5671 | int dw = parag->documentVisibleWidth() - ( doc ? ( left != x ? 0 : doc->rightMargin() ) : 0 );
|
|---|
| 5672 |
|
|---|
| 5673 | int curLeft = x;
|
|---|
| 5674 | int rm = parag->rightMargin();
|
|---|
| 5675 | int rdiff = doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 0 ) : 0;
|
|---|
| 5676 | int w = dw - rdiff;
|
|---|
| 5677 | bool fullWidth = TRUE;
|
|---|
| 5678 | int marg = left + rdiff;
|
|---|
| 5679 | int minw = 0;
|
|---|
| 5680 | int wused = 0;
|
|---|
| 5681 | int tminw = marg;
|
|---|
| 5682 | int linespacing = doc ? parag->lineSpacing() : 0;
|
|---|
| 5683 | bool wrapEnabled = isWrapEnabled( parag );
|
|---|
| 5684 |
|
|---|
| 5685 | start = 0;
|
|---|
| 5686 |
|
|---|
| 5687 | int i = start;
|
|---|
| 5688 | QTextLineStart *lineStart = new QTextLineStart( y, y, 0 );
|
|---|
| 5689 | insertLineStart( parag, 0, lineStart );
|
|---|
| 5690 | int lastBreak = -1;
|
|---|
| 5691 | int tmpBaseLine = 0, tmph = 0;
|
|---|
| 5692 | bool lastWasNonInlineCustom = FALSE;
|
|---|
| 5693 |
|
|---|
| 5694 | int align = parag->alignment();
|
|---|
| 5695 | if ( align == Qt::AlignAuto && doc && doc->alignment() != Qt::AlignAuto )
|
|---|
| 5696 | align = doc->alignment();
|
|---|
| 5697 |
|
|---|
| 5698 | align &= Qt::AlignHorizontal_Mask;
|
|---|
| 5699 |
|
|---|
| 5700 | // ### hack. The last char in the paragraph is always invisible,
|
|---|
| 5701 | // ### and somehow sometimes has a wrong format. It changes
|
|---|
| 5702 | // ### between // layouting and printing. This corrects some
|
|---|
| 5703 | // ### layouting errors in BiDi mode due to this.
|
|---|
| 5704 | if ( len > 1 ) {
|
|---|
| 5705 | c = ¶g->string()->at(len - 1);
|
|---|
| 5706 | if (!c->isAnchor()) {
|
|---|
| 5707 | c->format()->removeRef();
|
|---|
| 5708 | c->setFormat( string->at( len - 2 ).format() );
|
|---|
| 5709 | c->format()->addRef();
|
|---|
| 5710 | }
|
|---|
| 5711 | }
|
|---|
| 5712 |
|
|---|
| 5713 | c = ¶g->string()->at( 0 );
|
|---|
| 5714 |
|
|---|
| 5715 | QPainter *painter = QTextFormat::painter();
|
|---|
| 5716 | int col = 0;
|
|---|
| 5717 | int ww = 0;
|
|---|
| 5718 | QChar lastChr = c->c;
|
|---|
| 5719 | QTextFormat *lastFormat = c->format();
|
|---|
| 5720 | for ( ; i < len; ++i, ++col ) {
|
|---|
| 5721 | if ( i ) {
|
|---|
| 5722 | c = ¶g->string()->at(i-1);
|
|---|
| 5723 | lastChr = c->c;
|
|---|
| 5724 | lastFormat = c->format();
|
|---|
| 5725 | }
|
|---|
| 5726 | bool lastWasOwnLineCustomItem = lastBreak == -2;
|
|---|
| 5727 | bool hadBreakableChar = lastBreak != -1;
|
|---|
| 5728 | bool lastWasHardBreak = lastChr == QChar_linesep;
|
|---|
| 5729 |
|
|---|
| 5730 | // ### next line should not be needed
|
|---|
| 5731 | if ( painter )
|
|---|
| 5732 | c->format()->setPainter( painter );
|
|---|
| 5733 | c = &string->at( i );
|
|---|
| 5734 |
|
|---|
| 5735 | if (lastFormat != c->format() && !c->c.isSpace()
|
|---|
| 5736 | && lastFormat->font().italic() && !c->format()->font().italic()) {
|
|---|
| 5737 | int rb = lastFormat->fontMetrics().rightBearing(lastChr);
|
|---|
| 5738 | if (rb < 0)
|
|---|
| 5739 | x -= rb;
|
|---|
| 5740 | }
|
|---|
| 5741 |
|
|---|
| 5742 | if ( i > 0 && (x > curLeft || ww == 0) || lastWasNonInlineCustom ) {
|
|---|
| 5743 | c->lineStart = 0;
|
|---|
| 5744 | } else {
|
|---|
| 5745 | c->lineStart = 1;
|
|---|
| 5746 | firstChar = c;
|
|---|
| 5747 | }
|
|---|
| 5748 |
|
|---|
| 5749 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 5750 | lastWasNonInlineCustom = ( c->isCustom() && c->customItem()->placement() != QTextCustomItem::PlaceInline );
|
|---|
| 5751 | #endif
|
|---|
| 5752 |
|
|---|
| 5753 | if ( c->c.unicode() >= 32 || c->isCustom() ) {
|
|---|
| 5754 | ww = string->width( i );
|
|---|
| 5755 | } else if ( c->c == '\t' ) {
|
|---|
| 5756 | if ( align == Qt::AlignRight || align == Qt::AlignCenter ) {
|
|---|
| 5757 | // we can not (yet) do tabs
|
|---|
| 5758 | ww = c->format()->width(' ' );
|
|---|
| 5759 | } else {
|
|---|
| 5760 | int tabx = lastWasHardBreak ? (left + ( doc ? parag->firstLineMargin() : 0 )) : x;
|
|---|
| 5761 | int nx = parag->nextTab( i, tabx - left ) + left;
|
|---|
| 5762 | if ( nx < tabx ) // strrrange...
|
|---|
| 5763 | ww = 0;
|
|---|
| 5764 | else
|
|---|
| 5765 | ww = nx - tabx;
|
|---|
| 5766 | }
|
|---|
| 5767 | } else {
|
|---|
| 5768 | ww = c->format()->width( ' ' );
|
|---|
| 5769 | }
|
|---|
| 5770 |
|
|---|
| 5771 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 5772 | QTextCustomItem* ci = c->customItem();
|
|---|
| 5773 | if ( c->isCustom() && ci->ownLine() ) {
|
|---|
| 5774 | QTextLineStart *lineStart2 = formatLine( parag, string, lineStart, firstChar, c-1, align, SPACE(w - x - ww) );
|
|---|
| 5775 | x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
|
|---|
| 5776 | w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
|
|---|
| 5777 | ci->resize(w - x);
|
|---|
| 5778 | if ( ci->width < w - x ) {
|
|---|
| 5779 | if ( align & Qt::AlignHCenter )
|
|---|
| 5780 | x = ( w - ci->width ) / 2;
|
|---|
| 5781 | else if ( align & Qt::AlignRight ) {
|
|---|
| 5782 | x = w - ci->width;
|
|---|
| 5783 | }
|
|---|
| 5784 | }
|
|---|
| 5785 | c->x = x;
|
|---|
| 5786 | curLeft = x;
|
|---|
| 5787 | if ( i == 0 || !isBreakable(string, i-1) ||
|
|---|
| 5788 | string->at( i - 1 ).lineStart == 0 ) {
|
|---|
| 5789 | y += QMAX( h, QMAX( tmph, linespacing ) );
|
|---|
| 5790 | tmph = c->height();
|
|---|
| 5791 | h = tmph;
|
|---|
| 5792 | lineStart = lineStart2;
|
|---|
| 5793 | lineStart->y = y;
|
|---|
| 5794 | insertLineStart( parag, i, lineStart );
|
|---|
| 5795 | c->lineStart = 1;
|
|---|
| 5796 | firstChar = c;
|
|---|
| 5797 | } else {
|
|---|
| 5798 | tmph = c->height();
|
|---|
| 5799 | h = tmph;
|
|---|
| 5800 | delete lineStart2;
|
|---|
| 5801 | }
|
|---|
| 5802 | lineStart->h = h;
|
|---|
| 5803 | lineStart->baseLine = h;
|
|---|
| 5804 | tmpBaseLine = lineStart->baseLine;
|
|---|
| 5805 | lastBreak = -2;
|
|---|
| 5806 | x = w;
|
|---|
| 5807 | minw = QMAX( minw, tminw );
|
|---|
| 5808 |
|
|---|
| 5809 | int tw = ci->minimumWidth() + ( doc ? doc->leftMargin() : 0 );
|
|---|
| 5810 | if ( tw < QWIDGETSIZE_MAX )
|
|---|
| 5811 | tminw = tw;
|
|---|
| 5812 | else
|
|---|
| 5813 | tminw = marg;
|
|---|
| 5814 | wused = QMAX( wused, ci->width );
|
|---|
| 5815 | continue;
|
|---|
| 5816 | } else if ( c->isCustom() && ci->placement() != QTextCustomItem::PlaceInline ) {
|
|---|
| 5817 | int tw = ci->minimumWidth();
|
|---|
| 5818 | if ( tw < QWIDGETSIZE_MAX )
|
|---|
| 5819 | minw = QMAX( minw, tw );
|
|---|
| 5820 | }
|
|---|
| 5821 | #endif
|
|---|
| 5822 | // we break if
|
|---|
| 5823 | // 1. the last character was a hard break (QChar_linesep) or
|
|---|
| 5824 | // 2. the last charater was a own-line custom item (eg. table or ruler) or
|
|---|
| 5825 | // 3. wrapping was enabled, it was not a space and following
|
|---|
| 5826 | // condition is true: We either had a breakable character
|
|---|
| 5827 | // previously or we ar allowed to break in words and - either
|
|---|
| 5828 | // we break at w pixels and the current char would exceed that
|
|---|
| 5829 | // or - we break at a column and the current character would
|
|---|
| 5830 | // exceed that.
|
|---|
| 5831 | if ( lastWasHardBreak || lastWasOwnLineCustomItem ||
|
|---|
| 5832 | ( wrapEnabled &&
|
|---|
| 5833 | ( (!c->c.isSpace() && (hadBreakableChar || allowBreakInWords()) &&
|
|---|
| 5834 | ( (wrapAtColumn() == -1 && x + ww > w) ||
|
|---|
| 5835 | (wrapAtColumn() != -1 && col >= wrapAtColumn()) ) ) )
|
|---|
| 5836 | )
|
|---|
| 5837 | ) {
|
|---|
| 5838 | if ( wrapAtColumn() != -1 )
|
|---|
| 5839 | minw = QMAX( minw, x + ww );
|
|---|
| 5840 | // if a break was forced (no breakable char, hard break or own line custom item), break immediately....
|
|---|
| 5841 | if ( !hadBreakableChar || lastWasHardBreak || lastWasOwnLineCustomItem ) {
|
|---|
| 5842 | if ( lineStart ) {
|
|---|
| 5843 | lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
|
|---|
| 5844 | h = QMAX( h, tmph );
|
|---|
| 5845 | lineStart->h = h;
|
|---|
| 5846 | DO_FLOW( lineStart );
|
|---|
| 5847 | }
|
|---|
| 5848 | lineStart = formatLine( parag, string, lineStart, firstChar, c-1, align, SPACE(w - x) );
|
|---|
| 5849 | x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
|
|---|
| 5850 | w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
|
|---|
| 5851 | if ( !doc && c->c == '\t' ) { // qt_format_text tab handling
|
|---|
| 5852 | int nx = parag->nextTab( i, x - left ) + left;
|
|---|
| 5853 | if ( nx < x )
|
|---|
| 5854 | ww = w - x;
|
|---|
| 5855 | else
|
|---|
| 5856 | ww = nx - x;
|
|---|
| 5857 | }
|
|---|
| 5858 | curLeft = x;
|
|---|
| 5859 | y += QMAX( h, linespacing );
|
|---|
| 5860 | tmph = c->height();
|
|---|
| 5861 | h = 0;
|
|---|
| 5862 | lineStart->y = y;
|
|---|
| 5863 | insertLineStart( parag, i, lineStart );
|
|---|
| 5864 | lineStart->baseLine = c->ascent();
|
|---|
| 5865 | lineStart->h = c->height();
|
|---|
| 5866 | c->lineStart = 1;
|
|---|
| 5867 | firstChar = c;
|
|---|
| 5868 | tmpBaseLine = lineStart->baseLine;
|
|---|
| 5869 | lastBreak = -1;
|
|---|
| 5870 | col = 0;
|
|---|
| 5871 | if ( allowBreakInWords() || lastWasHardBreak ) {
|
|---|
| 5872 | minw = QMAX(minw, tminw);
|
|---|
| 5873 | tminw = marg;
|
|---|
| 5874 | }
|
|---|
| 5875 | } else { // ... otherwise if we had a breakable char, break there
|
|---|
| 5876 | DO_FLOW( lineStart );
|
|---|
| 5877 | c->x = x;
|
|---|
| 5878 | i = lastBreak;
|
|---|
| 5879 | lineStart = formatLine( parag, string, lineStart, firstChar, parag->at( lastBreak ),align, SPACE(w - string->at( i+1 ).x) );
|
|---|
| 5880 | x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
|
|---|
| 5881 | w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
|
|---|
| 5882 | if ( !doc && c->c == '\t' ) { // qt_format_text tab handling
|
|---|
| 5883 | int nx = parag->nextTab( i, x - left ) + left;
|
|---|
| 5884 | if ( nx < x )
|
|---|
| 5885 | ww = w - x;
|
|---|
| 5886 | else
|
|---|
| 5887 | ww = nx - x;
|
|---|
| 5888 | }
|
|---|
| 5889 | curLeft = x;
|
|---|
| 5890 | y += QMAX( h, linespacing );
|
|---|
| 5891 | tmph = c->height();
|
|---|
| 5892 | h = tmph;
|
|---|
| 5893 | lineStart->y = y;
|
|---|
| 5894 | insertLineStart( parag, i + 1, lineStart );
|
|---|
| 5895 | lineStart->baseLine = c->ascent();
|
|---|
| 5896 | lineStart->h = c->height();
|
|---|
| 5897 | c->lineStart = 1;
|
|---|
| 5898 | firstChar = c;
|
|---|
| 5899 | tmpBaseLine = lineStart->baseLine;
|
|---|
| 5900 | lastBreak = -1;
|
|---|
| 5901 | col = 0;
|
|---|
| 5902 | minw = QMAX(minw, tminw);
|
|---|
| 5903 | tminw = marg;
|
|---|
| 5904 | continue;
|
|---|
| 5905 | }
|
|---|
| 5906 | } else if (lineStart && isBreakable(string, i)) {
|
|---|
| 5907 | if ( len <= 2 || i < len - 1 ) {
|
|---|
| 5908 | tmpBaseLine = QMAX( tmpBaseLine, c->ascent() );
|
|---|
| 5909 | tmph = QMAX( tmph, c->height() );
|
|---|
| 5910 | }
|
|---|
| 5911 | minw = QMAX( minw, tminw );
|
|---|
| 5912 |
|
|---|
| 5913 | tminw = marg + ww;
|
|---|
| 5914 | lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
|
|---|
| 5915 | h = QMAX( h, tmph );
|
|---|
| 5916 | lineStart->h = h;
|
|---|
| 5917 | if ( i < len - 2 || c->c != ' ' )
|
|---|
| 5918 | lastBreak = i;
|
|---|
| 5919 | } else {
|
|---|
| 5920 | tminw += ww;
|
|---|
| 5921 | int cascent = c->ascent();
|
|---|
| 5922 | int cheight = c->height();
|
|---|
| 5923 | int belowBaseLine = QMAX( tmph - tmpBaseLine, cheight-cascent );
|
|---|
| 5924 | tmpBaseLine = QMAX( tmpBaseLine, cascent );
|
|---|
| 5925 | tmph = tmpBaseLine + belowBaseLine;
|
|---|
| 5926 | }
|
|---|
| 5927 |
|
|---|
| 5928 | c->x = x;
|
|---|
| 5929 | x += ww;
|
|---|
| 5930 | wused = QMAX( wused, x );
|
|---|
| 5931 | }
|
|---|
| 5932 |
|
|---|
| 5933 | if ( lineStart ) {
|
|---|
| 5934 | lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
|
|---|
| 5935 | h = QMAX( h, tmph );
|
|---|
| 5936 | lineStart->h = h;
|
|---|
| 5937 | // last line in a paragraph is not justified
|
|---|
| 5938 | if ( align == Qt::AlignJustify )
|
|---|
| 5939 | align = Qt::AlignAuto;
|
|---|
| 5940 | DO_FLOW( lineStart );
|
|---|
| 5941 | lineStart = formatLine( parag, string, lineStart, firstChar, c, align, SPACE(w - x) );
|
|---|
| 5942 | delete lineStart;
|
|---|
| 5943 | }
|
|---|
| 5944 |
|
|---|
| 5945 | minw = QMAX( minw, tminw );
|
|---|
| 5946 | if ( doc )
|
|---|
| 5947 | minw += doc->rightMargin();
|
|---|
| 5948 |
|
|---|
| 5949 | int m = parag->bottomMargin();
|
|---|
| 5950 | if ( !parag->next() )
|
|---|
| 5951 | m = 0;
|
|---|
| 5952 | else
|
|---|
| 5953 | m = QMAX(m, parag->next()->topMargin() ) / 2;
|
|---|
| 5954 | parag->setFullWidth( fullWidth );
|
|---|
| 5955 | y += QMAX( h, linespacing ) + m;
|
|---|
| 5956 |
|
|---|
| 5957 | wused += rm;
|
|---|
| 5958 | if ( !wrapEnabled || wrapAtColumn() != -1 )
|
|---|
| 5959 | minw = QMAX(minw, wused);
|
|---|
| 5960 |
|
|---|
| 5961 | // This is the case where we are breaking wherever we darn well please
|
|---|
| 5962 | // in cases like that, the minw should not be the length of the entire
|
|---|
| 5963 | // word, because we necessarily want to show the word on the whole line.
|
|---|
| 5964 | // example: word wrap in iconview
|
|---|
| 5965 | if ( allowBreakInWords() && minw > wused )
|
|---|
| 5966 | minw = wused;
|
|---|
| 5967 |
|
|---|
| 5968 | thisminw = minw;
|
|---|
| 5969 | thiswused = wused;
|
|---|
| 5970 | return y;
|
|---|
| 5971 | }
|
|---|
| 5972 |
|
|---|
| 5973 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 5974 |
|
|---|
| 5975 | QTextIndent::QTextIndent()
|
|---|
| 5976 | {
|
|---|
| 5977 | }
|
|---|
| 5978 |
|
|---|
| 5979 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 5980 |
|
|---|
| 5981 | QTextFormatCollection::QTextFormatCollection()
|
|---|
| 5982 | : cKey( 307 ), paintdevice( 0 )
|
|---|
| 5983 | {
|
|---|
| 5984 | defFormat = new QTextFormat( QApplication::font(),
|
|---|
| 5985 | QApplication::palette().color( QPalette::Active, QColorGroup::Text ) );
|
|---|
| 5986 | lastFormat = cres = 0;
|
|---|
| 5987 | cflags = -1;
|
|---|
| 5988 | cKey.setAutoDelete( TRUE );
|
|---|
| 5989 | cachedFormat = 0;
|
|---|
| 5990 | }
|
|---|
| 5991 |
|
|---|
| 5992 | QTextFormatCollection::~QTextFormatCollection()
|
|---|
| 5993 | {
|
|---|
| 5994 | delete defFormat;
|
|---|
| 5995 | }
|
|---|
| 5996 |
|
|---|
| 5997 | void QTextFormatCollection::setPaintDevice( QPaintDevice *pd )
|
|---|
| 5998 | {
|
|---|
| 5999 | paintdevice = pd;
|
|---|
| 6000 |
|
|---|
| 6001 | #if defined(Q_WS_X11)
|
|---|
| 6002 | int scr = ( paintdevice ) ? paintdevice->x11Screen() : QPaintDevice::x11AppScreen();
|
|---|
| 6003 |
|
|---|
| 6004 | defFormat->fn.x11SetScreen( scr );
|
|---|
| 6005 | defFormat->update();
|
|---|
| 6006 |
|
|---|
| 6007 | QDictIterator<QTextFormat> it( cKey );
|
|---|
| 6008 | QTextFormat *format;
|
|---|
| 6009 | while ( ( format = it.current() ) != 0 ) {
|
|---|
| 6010 | ++it;
|
|---|
| 6011 | format->fn.x11SetScreen( scr );
|
|---|
| 6012 | format->update();
|
|---|
| 6013 | }
|
|---|
| 6014 | #endif // Q_WS_X11
|
|---|
| 6015 | }
|
|---|
| 6016 |
|
|---|
| 6017 | QTextFormat *QTextFormatCollection::format( QTextFormat *f )
|
|---|
| 6018 | {
|
|---|
| 6019 | if ( f->parent() == this || f == defFormat ) {
|
|---|
| 6020 | lastFormat = f;
|
|---|
| 6021 | lastFormat->addRef();
|
|---|
| 6022 | return lastFormat;
|
|---|
| 6023 | }
|
|---|
| 6024 |
|
|---|
| 6025 | if ( f == lastFormat || ( lastFormat && f->key() == lastFormat->key() ) ) {
|
|---|
| 6026 | lastFormat->addRef();
|
|---|
| 6027 | return lastFormat;
|
|---|
| 6028 | }
|
|---|
| 6029 |
|
|---|
| 6030 | QTextFormat *fm = cKey.find( f->key() );
|
|---|
| 6031 | if ( fm ) {
|
|---|
| 6032 | lastFormat = fm;
|
|---|
| 6033 | lastFormat->addRef();
|
|---|
| 6034 | return lastFormat;
|
|---|
| 6035 | }
|
|---|
| 6036 |
|
|---|
| 6037 | if ( f->key() == defFormat->key() )
|
|---|
| 6038 | return defFormat;
|
|---|
| 6039 |
|
|---|
| 6040 | lastFormat = createFormat( *f );
|
|---|
| 6041 | lastFormat->collection = this;
|
|---|
| 6042 | cKey.insert( lastFormat->key(), lastFormat );
|
|---|
| 6043 | return lastFormat;
|
|---|
| 6044 | }
|
|---|
| 6045 |
|
|---|
| 6046 | QTextFormat *QTextFormatCollection::format( QTextFormat *of, QTextFormat *nf, int flags )
|
|---|
| 6047 | {
|
|---|
| 6048 | if ( cres && kof == of->key() && knf == nf->key() && cflags == flags ) {
|
|---|
| 6049 | cres->addRef();
|
|---|
| 6050 | return cres;
|
|---|
| 6051 | }
|
|---|
| 6052 |
|
|---|
| 6053 | cres = createFormat( *of );
|
|---|
| 6054 | kof = of->key();
|
|---|
| 6055 | knf = nf->key();
|
|---|
| 6056 | cflags = flags;
|
|---|
| 6057 | if ( flags & QTextFormat::Bold )
|
|---|
| 6058 | cres->fn.setBold( nf->fn.bold() );
|
|---|
| 6059 | if ( flags & QTextFormat::Italic )
|
|---|
| 6060 | cres->fn.setItalic( nf->fn.italic() );
|
|---|
| 6061 | if ( flags & QTextFormat::Underline )
|
|---|
| 6062 | cres->fn.setUnderline( nf->fn.underline() );
|
|---|
| 6063 | if ( flags & QTextFormat::StrikeOut )
|
|---|
| 6064 | cres->fn.setStrikeOut( nf->fn.strikeOut() );
|
|---|
| 6065 | if ( flags & QTextFormat::Family )
|
|---|
| 6066 | cres->fn.setFamily( nf->fn.family() );
|
|---|
| 6067 | if ( flags & QTextFormat::Size ) {
|
|---|
| 6068 | if ( of->usePixelSizes )
|
|---|
| 6069 | cres->fn.setPixelSize( nf->fn.pixelSize() );
|
|---|
| 6070 | else
|
|---|
| 6071 | cres->fn.setPointSize( nf->fn.pointSize() );
|
|---|
| 6072 | }
|
|---|
| 6073 | if ( flags & QTextFormat::Color )
|
|---|
| 6074 | cres->col = nf->col;
|
|---|
| 6075 | if ( flags & QTextFormat::Misspelled )
|
|---|
| 6076 | cres->missp = nf->missp;
|
|---|
| 6077 | if ( flags & QTextFormat::VAlign )
|
|---|
| 6078 | cres->ha = nf->ha;
|
|---|
| 6079 | cres->update();
|
|---|
| 6080 |
|
|---|
| 6081 | QTextFormat *fm = cKey.find( cres->key() );
|
|---|
| 6082 | if ( !fm ) {
|
|---|
| 6083 | cres->collection = this;
|
|---|
| 6084 | cKey.insert( cres->key(), cres );
|
|---|
| 6085 | } else {
|
|---|
| 6086 | delete cres;
|
|---|
| 6087 | cres = fm;
|
|---|
| 6088 | cres->addRef();
|
|---|
| 6089 | }
|
|---|
| 6090 |
|
|---|
| 6091 | return cres;
|
|---|
| 6092 | }
|
|---|
| 6093 |
|
|---|
| 6094 | QTextFormat *QTextFormatCollection::format( const QFont &f, const QColor &c )
|
|---|
| 6095 | {
|
|---|
| 6096 | if ( cachedFormat && cfont == f && ccol == c ) {
|
|---|
| 6097 | cachedFormat->addRef();
|
|---|
| 6098 | return cachedFormat;
|
|---|
| 6099 | }
|
|---|
| 6100 |
|
|---|
| 6101 | QString key = QTextFormat::getKey( f, c, FALSE, QTextFormat::AlignNormal );
|
|---|
| 6102 | cachedFormat = cKey.find( key );
|
|---|
| 6103 | cfont = f;
|
|---|
| 6104 | ccol = c;
|
|---|
| 6105 |
|
|---|
| 6106 | if ( cachedFormat ) {
|
|---|
| 6107 | cachedFormat->addRef();
|
|---|
| 6108 | return cachedFormat;
|
|---|
| 6109 | }
|
|---|
| 6110 |
|
|---|
| 6111 | if ( key == defFormat->key() )
|
|---|
| 6112 | return defFormat;
|
|---|
| 6113 |
|
|---|
| 6114 | cachedFormat = createFormat( f, c );
|
|---|
| 6115 | cachedFormat->collection = this;
|
|---|
| 6116 | cKey.insert( cachedFormat->key(), cachedFormat );
|
|---|
| 6117 | if ( cachedFormat->key() != key )
|
|---|
| 6118 | qWarning("ASSERT: keys for format not identical: '%s '%s'", cachedFormat->key().latin1(), key.latin1() );
|
|---|
| 6119 | return cachedFormat;
|
|---|
| 6120 | }
|
|---|
| 6121 |
|
|---|
| 6122 | void QTextFormatCollection::remove( QTextFormat *f )
|
|---|
| 6123 | {
|
|---|
| 6124 | if ( lastFormat == f )
|
|---|
| 6125 | lastFormat = 0;
|
|---|
| 6126 | if ( cres == f )
|
|---|
| 6127 | cres = 0;
|
|---|
| 6128 | if ( cachedFormat == f )
|
|---|
| 6129 | cachedFormat = 0;
|
|---|
| 6130 | if (cKey.find(f->key()) == f)
|
|---|
| 6131 | cKey.remove( f->key() );
|
|---|
| 6132 | }
|
|---|
| 6133 |
|
|---|
| 6134 | #define UPDATE( up, lo, rest ) \
|
|---|
| 6135 | if ( font.lo##rest() != defFormat->fn.lo##rest() && fm->fn.lo##rest() == defFormat->fn.lo##rest() ) \
|
|---|
| 6136 | fm->fn.set##up##rest( font.lo##rest() )
|
|---|
| 6137 |
|
|---|
| 6138 | void QTextFormatCollection::updateDefaultFormat( const QFont &font, const QColor &color, QStyleSheet *sheet )
|
|---|
| 6139 | {
|
|---|
| 6140 | QDictIterator<QTextFormat> it( cKey );
|
|---|
| 6141 | QTextFormat *fm;
|
|---|
| 6142 | bool usePixels = font.pointSize() == -1;
|
|---|
| 6143 | bool changeSize = usePixels ? font.pixelSize() != defFormat->fn.pixelSize() :
|
|---|
| 6144 | font.pointSize() != defFormat->fn.pointSize();
|
|---|
| 6145 | int base = usePixels ? font.pixelSize() : font.pointSize();
|
|---|
| 6146 | while ( ( fm = it.current() ) ) {
|
|---|
| 6147 | ++it;
|
|---|
| 6148 | UPDATE( F, f, amily );
|
|---|
| 6149 | UPDATE( W, w, eight );
|
|---|
| 6150 | UPDATE( B, b, old );
|
|---|
| 6151 | UPDATE( I, i, talic );
|
|---|
| 6152 | UPDATE( U, u, nderline );
|
|---|
| 6153 | if ( changeSize ) {
|
|---|
| 6154 | fm->stdSize = base;
|
|---|
| 6155 | fm->usePixelSizes = usePixels;
|
|---|
| 6156 | if ( usePixels )
|
|---|
| 6157 | fm->fn.setPixelSize( fm->stdSize );
|
|---|
| 6158 | else
|
|---|
| 6159 | fm->fn.setPointSize( fm->stdSize );
|
|---|
| 6160 | sheet->scaleFont( fm->fn, fm->logicalFontSize );
|
|---|
| 6161 | }
|
|---|
| 6162 | if ( color.isValid() && color != defFormat->col && fm->col == defFormat->col )
|
|---|
| 6163 | fm->col = color;
|
|---|
| 6164 | fm->update();
|
|---|
| 6165 | }
|
|---|
| 6166 |
|
|---|
| 6167 | defFormat->fn = font;
|
|---|
| 6168 | defFormat->col = color;
|
|---|
| 6169 | defFormat->update();
|
|---|
| 6170 | defFormat->stdSize = base;
|
|---|
| 6171 | defFormat->usePixelSizes = usePixels;
|
|---|
| 6172 |
|
|---|
| 6173 | updateKeys();
|
|---|
| 6174 | }
|
|---|
| 6175 |
|
|---|
| 6176 | // the keys in cKey have changed, rebuild the hashtable
|
|---|
| 6177 | void QTextFormatCollection::updateKeys()
|
|---|
| 6178 | {
|
|---|
| 6179 | if ( cKey.isEmpty() )
|
|---|
| 6180 | return;
|
|---|
| 6181 | cKey.setAutoDelete( FALSE );
|
|---|
| 6182 | QTextFormat** formats = new QTextFormat*[ cKey.count() + 1 ];
|
|---|
| 6183 | QTextFormat **f = formats;
|
|---|
| 6184 | QDictIterator<QTextFormat> it( cKey );
|
|---|
| 6185 | while ( ( *f = it.current() ) ) {
|
|---|
| 6186 | ++it;
|
|---|
| 6187 | ++f;
|
|---|
| 6188 | }
|
|---|
| 6189 | cKey.clear();
|
|---|
| 6190 | for ( f = formats; *f; f++ )
|
|---|
| 6191 | cKey.insert( (*f)->key(), *f );
|
|---|
| 6192 | cKey.setAutoDelete( TRUE );
|
|---|
| 6193 | delete [] formats;
|
|---|
| 6194 | }
|
|---|
| 6195 |
|
|---|
| 6196 |
|
|---|
| 6197 |
|
|---|
| 6198 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 6199 |
|
|---|
| 6200 | void QTextFormat::setBold( bool b )
|
|---|
| 6201 | {
|
|---|
| 6202 | if ( b == fn.bold() )
|
|---|
| 6203 | return;
|
|---|
| 6204 | fn.setBold( b );
|
|---|
| 6205 | update();
|
|---|
| 6206 | }
|
|---|
| 6207 |
|
|---|
| 6208 | void QTextFormat::setMisspelled( bool b )
|
|---|
| 6209 | {
|
|---|
| 6210 | if ( b == (bool)missp )
|
|---|
| 6211 | return;
|
|---|
| 6212 | missp = b;
|
|---|
| 6213 | update();
|
|---|
| 6214 | }
|
|---|
| 6215 |
|
|---|
| 6216 | void QTextFormat::setVAlign( VerticalAlignment a )
|
|---|
| 6217 | {
|
|---|
| 6218 | if ( a == ha )
|
|---|
| 6219 | return;
|
|---|
| 6220 | ha = a;
|
|---|
| 6221 | update();
|
|---|
| 6222 | }
|
|---|
| 6223 |
|
|---|
| 6224 | void QTextFormat::setItalic( bool b )
|
|---|
| 6225 | {
|
|---|
| 6226 | if ( b == fn.italic() )
|
|---|
| 6227 | return;
|
|---|
| 6228 | fn.setItalic( b );
|
|---|
| 6229 | update();
|
|---|
| 6230 | }
|
|---|
| 6231 |
|
|---|
| 6232 | void QTextFormat::setUnderline( bool b )
|
|---|
| 6233 | {
|
|---|
| 6234 | if ( b == fn.underline() )
|
|---|
| 6235 | return;
|
|---|
| 6236 | fn.setUnderline( b );
|
|---|
| 6237 | update();
|
|---|
| 6238 | }
|
|---|
| 6239 |
|
|---|
| 6240 | void QTextFormat::setStrikeOut( bool b )
|
|---|
| 6241 | {
|
|---|
| 6242 | if ( b == fn.strikeOut() )
|
|---|
| 6243 | return;
|
|---|
| 6244 | fn.setStrikeOut( b );
|
|---|
| 6245 | update();
|
|---|
| 6246 | }
|
|---|
| 6247 |
|
|---|
| 6248 | void QTextFormat::setFamily( const QString &f )
|
|---|
| 6249 | {
|
|---|
| 6250 | if ( f == fn.family() )
|
|---|
| 6251 | return;
|
|---|
| 6252 | fn.setFamily( f );
|
|---|
| 6253 | update();
|
|---|
| 6254 | }
|
|---|
| 6255 |
|
|---|
| 6256 | void QTextFormat::setPointSize( int s )
|
|---|
| 6257 | {
|
|---|
| 6258 | if ( s == fn.pointSize() )
|
|---|
| 6259 | return;
|
|---|
| 6260 | fn.setPointSize( s );
|
|---|
| 6261 | usePixelSizes = FALSE;
|
|---|
| 6262 | update();
|
|---|
| 6263 | }
|
|---|
| 6264 |
|
|---|
| 6265 | void QTextFormat::setFont( const QFont &f )
|
|---|
| 6266 | {
|
|---|
| 6267 | if ( f == fn && !k.isEmpty() )
|
|---|
| 6268 | return;
|
|---|
| 6269 | fn = f;
|
|---|
| 6270 | update();
|
|---|
| 6271 | }
|
|---|
| 6272 |
|
|---|
| 6273 | void QTextFormat::setColor( const QColor &c )
|
|---|
| 6274 | {
|
|---|
| 6275 | if ( c == col )
|
|---|
| 6276 | return;
|
|---|
| 6277 | col = c;
|
|---|
| 6278 | update();
|
|---|
| 6279 | }
|
|---|
| 6280 |
|
|---|
| 6281 | QString QTextFormat::makeFormatChangeTags( QTextFormat* defaultFormat, QTextFormat *f,
|
|---|
| 6282 | const QString& oldAnchorHref, const QString& anchorHref ) const
|
|---|
| 6283 | {
|
|---|
| 6284 | QString tag;
|
|---|
| 6285 | if ( f )
|
|---|
| 6286 | tag += f->makeFormatEndTags( defaultFormat, oldAnchorHref );
|
|---|
| 6287 |
|
|---|
| 6288 | if ( !anchorHref.isEmpty() )
|
|---|
| 6289 | tag += "<a href=\"" + anchorHref + "\">";
|
|---|
| 6290 |
|
|---|
| 6291 | if ( font() != defaultFormat->font()
|
|---|
| 6292 | || vAlign() != defaultFormat->vAlign()
|
|---|
| 6293 | || color().rgb() != defaultFormat->color().rgb() ) {
|
|---|
| 6294 | QString s;
|
|---|
| 6295 | if ( font().family() != defaultFormat->font().family() )
|
|---|
| 6296 | s += QString(!!s?";":"") + "font-family:" + fn.family();
|
|---|
| 6297 | if ( font().italic() && font().italic() != defaultFormat->font().italic() )
|
|---|
| 6298 | s += QString(!!s?";":"") + "font-style:" + (font().italic() ? "italic" : "normal");
|
|---|
| 6299 | if ( font().pointSize() != defaultFormat->font().pointSize() )
|
|---|
| 6300 | s += QString(!!s?";":"") + "font-size:" + QString::number( fn.pointSize() ) + "pt";
|
|---|
| 6301 | if ( font().weight() != defaultFormat->font().weight() )
|
|---|
| 6302 | s += QString(!!s?";":"") + "font-weight:" + QString::number( fn.weight() * 8 );
|
|---|
| 6303 | if ( font().underline() != defaultFormat->font().underline() )
|
|---|
| 6304 | s += QString(!!s?";":"") + "text-decoration:" + ( font().underline() ? "underline" : "none");
|
|---|
| 6305 | if ( vAlign() != defaultFormat->vAlign() ) {
|
|---|
| 6306 | s += QString(!!s?";":"") + "vertical-align:";
|
|---|
| 6307 | if ( vAlign() == QTextFormat::AlignSuperScript )
|
|---|
| 6308 | s += "super";
|
|---|
| 6309 | else if ( vAlign() == QTextFormat::AlignSubScript )
|
|---|
| 6310 | s += "sub";
|
|---|
| 6311 | else
|
|---|
| 6312 | s += "normal";
|
|---|
| 6313 | }
|
|---|
| 6314 | if ( color().rgb() != defaultFormat->color().rgb() )
|
|---|
| 6315 | s += QString(!!s?";":"") + "color:" + col.name();
|
|---|
| 6316 | if ( !s.isEmpty() )
|
|---|
| 6317 | tag += "<span style=\"" + s + "\">";
|
|---|
| 6318 | }
|
|---|
| 6319 |
|
|---|
| 6320 | return tag;
|
|---|
| 6321 | }
|
|---|
| 6322 |
|
|---|
| 6323 | QString QTextFormat::makeFormatEndTags( QTextFormat* defaultFormat, const QString& anchorHref ) const
|
|---|
| 6324 | {
|
|---|
| 6325 | QString tag;
|
|---|
| 6326 | if ( font().family() != defaultFormat->font().family()
|
|---|
| 6327 | || font().pointSize() != defaultFormat->font().pointSize()
|
|---|
| 6328 | || font().weight() != defaultFormat->font().weight()
|
|---|
| 6329 | || font().italic() != defaultFormat->font().italic()
|
|---|
| 6330 | || font().underline() != defaultFormat->font().underline()
|
|---|
| 6331 | || font().strikeOut() != defaultFormat->font().strikeOut()
|
|---|
| 6332 | || vAlign() != defaultFormat->vAlign()
|
|---|
| 6333 | || color().rgb() != defaultFormat->color().rgb() )
|
|---|
| 6334 | tag += "</span>";
|
|---|
| 6335 | if ( !anchorHref.isEmpty() )
|
|---|
| 6336 | tag += "</a>";
|
|---|
| 6337 | return tag;
|
|---|
| 6338 | }
|
|---|
| 6339 |
|
|---|
| 6340 | QTextFormat QTextFormat::makeTextFormat( const QStyleSheetItem *style, const QMap<QString,QString>& attr, double scaleFontsFactor ) const
|
|---|
| 6341 | {
|
|---|
| 6342 | QTextFormat format(*this);
|
|---|
| 6343 | if (!style )
|
|---|
| 6344 | return format;
|
|---|
| 6345 |
|
|---|
| 6346 | if ( !style->isAnchor() && style->color().isValid() ) {
|
|---|
| 6347 | // the style is not an anchor and defines a color.
|
|---|
| 6348 | // It might be used inside an anchor and it should
|
|---|
| 6349 | // override the link color.
|
|---|
| 6350 | format.linkColor = FALSE;
|
|---|
| 6351 | }
|
|---|
| 6352 | switch ( style->verticalAlignment() ) {
|
|---|
| 6353 | case QStyleSheetItem::VAlignBaseline:
|
|---|
| 6354 | format.setVAlign( QTextFormat::AlignNormal );
|
|---|
| 6355 | break;
|
|---|
| 6356 | case QStyleSheetItem::VAlignSuper:
|
|---|
| 6357 | format.setVAlign( QTextFormat::AlignSuperScript );
|
|---|
| 6358 | break;
|
|---|
| 6359 | case QStyleSheetItem::VAlignSub:
|
|---|
| 6360 | format.setVAlign( QTextFormat::AlignSubScript );
|
|---|
| 6361 | break;
|
|---|
| 6362 | }
|
|---|
| 6363 |
|
|---|
| 6364 | if ( style->fontWeight() != QStyleSheetItem::Undefined )
|
|---|
| 6365 | format.fn.setWeight( style->fontWeight() );
|
|---|
| 6366 | if ( style->fontSize() != QStyleSheetItem::Undefined ) {
|
|---|
| 6367 | format.fn.setPointSize( style->fontSize() );
|
|---|
| 6368 | } else if ( style->logicalFontSize() != QStyleSheetItem::Undefined ) {
|
|---|
| 6369 | format.logicalFontSize = style->logicalFontSize();
|
|---|
| 6370 | if ( format.usePixelSizes )
|
|---|
| 6371 | format.fn.setPixelSize( format.stdSize );
|
|---|
| 6372 | else
|
|---|
| 6373 | format.fn.setPointSize( format.stdSize );
|
|---|
| 6374 | style->styleSheet()->scaleFont( format.fn, format.logicalFontSize );
|
|---|
| 6375 | } else if ( style->logicalFontSizeStep() ) {
|
|---|
| 6376 | format.logicalFontSize += style->logicalFontSizeStep();
|
|---|
| 6377 | if ( format.usePixelSizes )
|
|---|
| 6378 | format.fn.setPixelSize( format.stdSize );
|
|---|
| 6379 | else
|
|---|
| 6380 | format.fn.setPointSize( format.stdSize );
|
|---|
| 6381 | style->styleSheet()->scaleFont( format.fn, format.logicalFontSize );
|
|---|
| 6382 | }
|
|---|
| 6383 | if ( !style->fontFamily().isEmpty() )
|
|---|
| 6384 | format.fn.setFamily( style->fontFamily() );
|
|---|
| 6385 | if ( style->color().isValid() )
|
|---|
| 6386 | format.col = style->color();
|
|---|
| 6387 | if ( style->definesFontItalic() )
|
|---|
| 6388 | format.fn.setItalic( style->fontItalic() );
|
|---|
| 6389 | if ( style->definesFontUnderline() )
|
|---|
| 6390 | format.fn.setUnderline( style->fontUnderline() );
|
|---|
| 6391 | if ( style->definesFontStrikeOut() )
|
|---|
| 6392 | format.fn.setStrikeOut( style->fontStrikeOut() );
|
|---|
| 6393 |
|
|---|
| 6394 |
|
|---|
| 6395 | if ( style->name() == "font") {
|
|---|
| 6396 | if ( attr.contains("color") ) {
|
|---|
| 6397 | QString s = attr["color"];
|
|---|
| 6398 | if ( !s.isEmpty() ) {
|
|---|
| 6399 | format.col.setNamedColor( s );
|
|---|
| 6400 | format.linkColor = FALSE;
|
|---|
| 6401 | }
|
|---|
| 6402 | }
|
|---|
| 6403 | if ( attr.contains("face") ) {
|
|---|
| 6404 | QString a = attr["face"];
|
|---|
| 6405 | QString family = a.section( ',', 0, 0 );
|
|---|
| 6406 | if ( !!family )
|
|---|
| 6407 | format.fn.setFamily( family );
|
|---|
| 6408 | }
|
|---|
| 6409 | if ( attr.contains("size") ) {
|
|---|
| 6410 | QString a = attr["size"];
|
|---|
| 6411 | int n = a.toInt();
|
|---|
| 6412 | if ( a[0] == '+' || a[0] == '-' )
|
|---|
| 6413 | n += 3;
|
|---|
| 6414 | format.logicalFontSize = n;
|
|---|
| 6415 | if ( format.usePixelSizes )
|
|---|
| 6416 | format.fn.setPixelSize( format.stdSize );
|
|---|
| 6417 | else
|
|---|
| 6418 | format.fn.setPointSize( format.stdSize );
|
|---|
| 6419 | style->styleSheet()->scaleFont( format.fn, format.logicalFontSize );
|
|---|
| 6420 | }
|
|---|
| 6421 | }
|
|---|
| 6422 | if ( attr.contains("style" ) ) {
|
|---|
| 6423 | QString a = attr["style"];
|
|---|
| 6424 | for ( int s = 0; s < a.contains(';')+1; s++ ) {
|
|---|
| 6425 | QString style = a.section( ';', s, s );
|
|---|
| 6426 | if ( style.startsWith("font-size:" ) && style.endsWith("pt") ) {
|
|---|
| 6427 | format.logicalFontSize = 0;
|
|---|
| 6428 | int size = int( scaleFontsFactor * style.mid( 10, style.length() - 12 ).toDouble() );
|
|---|
| 6429 | format.setPointSize( size );
|
|---|
| 6430 | } if ( style.startsWith("font-style:" ) ) {
|
|---|
| 6431 | QString s = style.mid( 11 ).stripWhiteSpace();
|
|---|
| 6432 | if ( s == "normal" )
|
|---|
| 6433 | format.fn.setItalic( FALSE );
|
|---|
| 6434 | else if ( s == "italic" || s == "oblique" )
|
|---|
| 6435 | format.fn.setItalic( TRUE );
|
|---|
| 6436 | } else if ( style.startsWith("font-weight:" ) ) {
|
|---|
| 6437 | QString s = style.mid( 12 );
|
|---|
| 6438 | bool ok = TRUE;
|
|---|
| 6439 | int n = s.toInt( &ok );
|
|---|
| 6440 | if ( ok )
|
|---|
| 6441 | format.fn.setWeight( n/8 );
|
|---|
| 6442 | } else if ( style.startsWith("font-family:" ) ) {
|
|---|
| 6443 | QString family = style.mid(12).section(',',0,0);
|
|---|
| 6444 | family.replace( '\"', ' ' );
|
|---|
| 6445 | family.replace( '\'', ' ' );
|
|---|
| 6446 | family = family.stripWhiteSpace();
|
|---|
| 6447 | format.fn.setFamily( family );
|
|---|
| 6448 | } else if ( style.startsWith("text-decoration:" ) ) {
|
|---|
| 6449 | QString s = style.mid( 16 ).stripWhiteSpace();
|
|---|
| 6450 | format.fn.setUnderline( s == "underline" );
|
|---|
| 6451 | } else if ( style.startsWith("vertical-align:" ) ) {
|
|---|
| 6452 | QString s = style.mid( 15 ).stripWhiteSpace();
|
|---|
| 6453 | if ( s == "sub" )
|
|---|
| 6454 | format.setVAlign( QTextFormat::AlignSubScript );
|
|---|
| 6455 | else if ( s == "super" )
|
|---|
| 6456 | format.setVAlign( QTextFormat::AlignSuperScript );
|
|---|
| 6457 | else
|
|---|
| 6458 | format.setVAlign( QTextFormat::AlignNormal );
|
|---|
| 6459 | } else if ( style.startsWith("color:" ) ) {
|
|---|
| 6460 | format.col.setNamedColor( style.mid(6) );
|
|---|
| 6461 | format.linkColor = FALSE;
|
|---|
| 6462 | }
|
|---|
| 6463 | }
|
|---|
| 6464 | }
|
|---|
| 6465 |
|
|---|
| 6466 | format.update();
|
|---|
| 6467 | return format;
|
|---|
| 6468 | }
|
|---|
| 6469 |
|
|---|
| 6470 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 6471 |
|
|---|
| 6472 | struct QPixmapInt
|
|---|
| 6473 | {
|
|---|
| 6474 | QPixmapInt() : ref( 0 ) {}
|
|---|
| 6475 | QPixmap pm;
|
|---|
| 6476 | int ref;
|
|---|
| 6477 | Q_DUMMY_COMPARISON_OPERATOR(QPixmapInt)
|
|---|
| 6478 | };
|
|---|
| 6479 |
|
|---|
| 6480 | static QMap<QString, QPixmapInt> *pixmap_map = 0;
|
|---|
| 6481 |
|
|---|
| 6482 | QTextImage::QTextImage( QTextDocument *p, const QMap<QString, QString> &attr, const QString& context,
|
|---|
| 6483 | QMimeSourceFactory &factory )
|
|---|
| 6484 | : QTextCustomItem( p )
|
|---|
| 6485 | {
|
|---|
| 6486 | width = height = 0;
|
|---|
| 6487 | if ( attr.contains("width") )
|
|---|
| 6488 | width = attr["width"].toInt();
|
|---|
| 6489 | if ( attr.contains("height") )
|
|---|
| 6490 | height = attr["height"].toInt();
|
|---|
| 6491 |
|
|---|
| 6492 | reg = 0;
|
|---|
| 6493 | QString imageName = attr["src"];
|
|---|
| 6494 |
|
|---|
| 6495 | if (!imageName)
|
|---|
| 6496 | imageName = attr["source"];
|
|---|
| 6497 |
|
|---|
| 6498 | if ( !imageName.isEmpty() ) {
|
|---|
| 6499 | imgId = QString( "%1,%2,%3,%4" ).arg( imageName ).arg( width ).arg( height ).arg( (ulong)&factory );
|
|---|
| 6500 | if ( !pixmap_map )
|
|---|
| 6501 | pixmap_map = new QMap<QString, QPixmapInt>;
|
|---|
| 6502 | if ( pixmap_map->contains( imgId ) ) {
|
|---|
| 6503 | QPixmapInt& pmi = pixmap_map->operator[](imgId);
|
|---|
| 6504 | pm = pmi.pm;
|
|---|
| 6505 | pmi.ref++;
|
|---|
| 6506 | width = pm.width();
|
|---|
| 6507 | height = pm.height();
|
|---|
| 6508 | } else {
|
|---|
| 6509 | QImage img;
|
|---|
| 6510 | const QMimeSource* m =
|
|---|
| 6511 | factory.data( imageName, context );
|
|---|
| 6512 | if ( !m ) {
|
|---|
| 6513 | qWarning("QTextImage: no mimesource for %s", imageName.latin1() );
|
|---|
| 6514 | }
|
|---|
| 6515 | else {
|
|---|
| 6516 | if ( !QImageDrag::decode( m, img ) ) {
|
|---|
| 6517 | qWarning("QTextImage: cannot decode %s", imageName.latin1() );
|
|---|
| 6518 | }
|
|---|
| 6519 | }
|
|---|
| 6520 |
|
|---|
| 6521 | if ( !img.isNull() ) {
|
|---|
| 6522 | if ( width == 0 ) {
|
|---|
| 6523 | width = img.width();
|
|---|
| 6524 | if ( height != 0 ) {
|
|---|
| 6525 | width = img.width() * height / img.height();
|
|---|
| 6526 | }
|
|---|
| 6527 | }
|
|---|
| 6528 | if ( height == 0 ) {
|
|---|
| 6529 | height = img.height();
|
|---|
| 6530 | if ( width != img.width() ) {
|
|---|
| 6531 | height = img.height() * width / img.width();
|
|---|
| 6532 | }
|
|---|
| 6533 | }
|
|---|
| 6534 | if ( img.width() != width || img.height() != height ){
|
|---|
| 6535 | #ifndef QT_NO_IMAGE_SMOOTHSCALE
|
|---|
| 6536 | img = img.smoothScale(width, height);
|
|---|
| 6537 | #endif
|
|---|
| 6538 | width = img.width();
|
|---|
| 6539 | height = img.height();
|
|---|
| 6540 | }
|
|---|
| 6541 | pm.convertFromImage( img );
|
|---|
| 6542 | }
|
|---|
| 6543 | if ( !pm.isNull() ) {
|
|---|
| 6544 | QPixmapInt& pmi = pixmap_map->operator[](imgId);
|
|---|
| 6545 | pmi.pm = pm;
|
|---|
| 6546 | pmi.ref++;
|
|---|
| 6547 | }
|
|---|
| 6548 | }
|
|---|
| 6549 | if ( pm.mask() ) {
|
|---|
| 6550 | QRegion mask( *pm.mask() );
|
|---|
| 6551 | QRegion all( 0, 0, pm.width(), pm.height() );
|
|---|
| 6552 | reg = new QRegion( all.subtract( mask ) );
|
|---|
| 6553 | }
|
|---|
| 6554 | }
|
|---|
| 6555 |
|
|---|
| 6556 | if ( pm.isNull() && (width*height)==0 )
|
|---|
| 6557 | width = height = 50;
|
|---|
| 6558 |
|
|---|
| 6559 | place = PlaceInline;
|
|---|
| 6560 | if ( attr["align"] == "left" )
|
|---|
| 6561 | place = PlaceLeft;
|
|---|
| 6562 | else if ( attr["align"] == "right" )
|
|---|
| 6563 | place = PlaceRight;
|
|---|
| 6564 |
|
|---|
| 6565 | tmpwidth = width;
|
|---|
| 6566 | tmpheight = height;
|
|---|
| 6567 |
|
|---|
| 6568 | attributes = attr;
|
|---|
| 6569 | }
|
|---|
| 6570 |
|
|---|
| 6571 | QTextImage::~QTextImage()
|
|---|
| 6572 | {
|
|---|
| 6573 | if ( pixmap_map && pixmap_map->contains( imgId ) ) {
|
|---|
| 6574 | QPixmapInt& pmi = pixmap_map->operator[](imgId);
|
|---|
| 6575 | pmi.ref--;
|
|---|
| 6576 | if ( !pmi.ref ) {
|
|---|
| 6577 | pixmap_map->remove( imgId );
|
|---|
| 6578 | if ( pixmap_map->isEmpty() ) {
|
|---|
| 6579 | delete pixmap_map;
|
|---|
| 6580 | pixmap_map = 0;
|
|---|
| 6581 | }
|
|---|
| 6582 | }
|
|---|
| 6583 | }
|
|---|
| 6584 | delete reg;
|
|---|
| 6585 | }
|
|---|
| 6586 |
|
|---|
| 6587 | QString QTextImage::richText() const
|
|---|
| 6588 | {
|
|---|
| 6589 | QString s;
|
|---|
| 6590 | s += "<img ";
|
|---|
| 6591 | QMap<QString, QString>::ConstIterator it = attributes.begin();
|
|---|
| 6592 | for ( ; it != attributes.end(); ++it ) {
|
|---|
| 6593 | s += it.key() + "=";
|
|---|
| 6594 | if ( (*it).find( ' ' ) != -1 )
|
|---|
| 6595 | s += "\"" + *it + "\"" + " ";
|
|---|
| 6596 | else
|
|---|
| 6597 | s += *it + " ";
|
|---|
| 6598 | }
|
|---|
| 6599 | s += ">";
|
|---|
| 6600 | return s;
|
|---|
| 6601 | }
|
|---|
| 6602 |
|
|---|
| 6603 | void QTextImage::adjustToPainter( QPainter* p )
|
|---|
| 6604 | {
|
|---|
| 6605 | width = scale( tmpwidth, p );
|
|---|
| 6606 | height = scale( tmpheight, p );
|
|---|
| 6607 | }
|
|---|
| 6608 |
|
|---|
| 6609 | #if !defined(Q_WS_X11)
|
|---|
| 6610 | #include <qbitmap.h>
|
|---|
| 6611 | #include <qcleanuphandler.h>
|
|---|
| 6612 | static QPixmap *qrt_selection = 0;
|
|---|
| 6613 | static QSingleCleanupHandler<QPixmap> qrt_cleanup_pixmap;
|
|---|
| 6614 | static void qrt_createSelectionPixmap( const QColorGroup &cg )
|
|---|
| 6615 | {
|
|---|
| 6616 | qrt_selection = new QPixmap( 2, 2 );
|
|---|
| 6617 | qrt_cleanup_pixmap.set( &qrt_selection );
|
|---|
| 6618 | qrt_selection->fill( Qt::color0 );
|
|---|
| 6619 | QBitmap m( 2, 2 );
|
|---|
| 6620 | m.fill( Qt::color1 );
|
|---|
| 6621 | QPainter p( &m );
|
|---|
| 6622 | p.setPen( Qt::color0 );
|
|---|
| 6623 | for ( int j = 0; j < 2; ++j ) {
|
|---|
| 6624 | p.drawPoint( j % 2, j );
|
|---|
| 6625 | }
|
|---|
| 6626 | p.end();
|
|---|
| 6627 | qrt_selection->setMask( m );
|
|---|
| 6628 | qrt_selection->fill( cg.highlight() );
|
|---|
| 6629 | }
|
|---|
| 6630 | #endif
|
|---|
| 6631 |
|
|---|
| 6632 | void QTextImage::draw( QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected )
|
|---|
| 6633 | {
|
|---|
| 6634 | if ( placement() != PlaceInline ) {
|
|---|
| 6635 | x = xpos;
|
|---|
| 6636 | y = ypos;
|
|---|
| 6637 | }
|
|---|
| 6638 |
|
|---|
| 6639 | if ( pm.isNull() ) {
|
|---|
| 6640 | p->fillRect( x , y, width, height, cg.dark() );
|
|---|
| 6641 | return;
|
|---|
| 6642 | }
|
|---|
| 6643 |
|
|---|
| 6644 | if ( is_printer( p ) ) {
|
|---|
| 6645 | p->drawPixmap( QRect( x, y, width, height ), pm );
|
|---|
| 6646 | return;
|
|---|
| 6647 | }
|
|---|
| 6648 |
|
|---|
| 6649 | if ( placement() != PlaceInline && !QRect( xpos, ypos, width, height ).intersects( QRect( cx, cy, cw, ch ) ) )
|
|---|
| 6650 | return;
|
|---|
| 6651 |
|
|---|
| 6652 | if ( placement() == PlaceInline )
|
|---|
| 6653 | p->drawPixmap( x , y, pm );
|
|---|
| 6654 | else
|
|---|
| 6655 | p->drawPixmap( cx , cy, pm, cx - x, cy - y, cw, ch );
|
|---|
| 6656 |
|
|---|
| 6657 | if ( selected && placement() == PlaceInline && is_printer( p ) ) {
|
|---|
| 6658 | #if defined(Q_WS_X11)
|
|---|
| 6659 | p->fillRect( QRect( QPoint( x, y ), pm.size() ), QBrush( cg.highlight(), QBrush::Dense4Pattern) );
|
|---|
| 6660 | #else // in WIN32 Dense4Pattern doesn't work correctly (transparency problem), so work around it
|
|---|
| 6661 | if ( !qrt_selection )
|
|---|
| 6662 | qrt_createSelectionPixmap( cg );
|
|---|
| 6663 | p->drawTiledPixmap( x, y, pm.width(), pm.height(), *qrt_selection );
|
|---|
| 6664 | #endif
|
|---|
| 6665 | }
|
|---|
| 6666 | }
|
|---|
| 6667 |
|
|---|
| 6668 | void QTextHorizontalLine::adjustToPainter( QPainter* p )
|
|---|
| 6669 | {
|
|---|
| 6670 | height = scale( tmpheight, p );
|
|---|
| 6671 | }
|
|---|
| 6672 |
|
|---|
| 6673 |
|
|---|
| 6674 | QTextHorizontalLine::QTextHorizontalLine( QTextDocument *p, const QMap<QString, QString> &attr,
|
|---|
| 6675 | const QString &,
|
|---|
| 6676 | QMimeSourceFactory & )
|
|---|
| 6677 | : QTextCustomItem( p )
|
|---|
| 6678 | {
|
|---|
| 6679 | height = tmpheight = 8;
|
|---|
| 6680 | if ( attr.find( "color" ) != attr.end() )
|
|---|
| 6681 | color = QColor( *attr.find( "color" ) );
|
|---|
| 6682 | shade = attr.find( "noshade" ) == attr.end();
|
|---|
| 6683 | }
|
|---|
| 6684 |
|
|---|
| 6685 | QTextHorizontalLine::~QTextHorizontalLine()
|
|---|
| 6686 | {
|
|---|
| 6687 | }
|
|---|
| 6688 |
|
|---|
| 6689 | QString QTextHorizontalLine::richText() const
|
|---|
| 6690 | {
|
|---|
| 6691 | return "<hr>";
|
|---|
| 6692 | }
|
|---|
| 6693 |
|
|---|
| 6694 | void QTextHorizontalLine::draw( QPainter* p, int x, int y, int , int , int , int , const QColorGroup& cg, bool selected )
|
|---|
| 6695 | {
|
|---|
| 6696 | QRect r( x, y, width, height);
|
|---|
| 6697 | if ( is_printer( p ) || !shade ) {
|
|---|
| 6698 | QPen oldPen = p->pen();
|
|---|
| 6699 | if ( !color.isValid() )
|
|---|
| 6700 | p->setPen( QPen( cg.text(), is_printer( p ) ? height/8 : QMAX( 2, height/4 ) ) );
|
|---|
| 6701 | else
|
|---|
| 6702 | p->setPen( QPen( color, is_printer( p ) ? height/8 : QMAX( 2, height/4 ) ) );
|
|---|
| 6703 | p->drawLine( r.left()-1, y + height / 2, r.right() + 1, y + height / 2 );
|
|---|
| 6704 | p->setPen( oldPen );
|
|---|
| 6705 | } else {
|
|---|
| 6706 | QColorGroup g( cg );
|
|---|
| 6707 | if ( color.isValid() )
|
|---|
| 6708 | g.setColor( QColorGroup::Dark, color );
|
|---|
| 6709 | if ( selected )
|
|---|
| 6710 | p->fillRect( r, g.highlight() );
|
|---|
| 6711 | qDrawShadeLine( p, r.left() - 1, y + height / 2, r.right() + 1, y + height / 2, g, TRUE, height / 8 );
|
|---|
| 6712 | }
|
|---|
| 6713 | }
|
|---|
| 6714 | #endif //QT_NO_TEXTCUSTOMITEM
|
|---|
| 6715 |
|
|---|
| 6716 | /*****************************************************************/
|
|---|
| 6717 | // Small set of utility functions to make the parser a bit simpler
|
|---|
| 6718 | //
|
|---|
| 6719 |
|
|---|
| 6720 | bool QTextDocument::hasPrefix(const QChar* doc, int length, int pos, QChar c)
|
|---|
| 6721 | {
|
|---|
| 6722 | if ( pos + 1 > length )
|
|---|
| 6723 | return FALSE;
|
|---|
| 6724 | return doc[ pos ].lower() == c.lower();
|
|---|
| 6725 | }
|
|---|
| 6726 |
|
|---|
| 6727 | bool QTextDocument::hasPrefix( const QChar* doc, int length, int pos, const QString& s )
|
|---|
| 6728 | {
|
|---|
| 6729 | if ( pos + (int) s.length() > length )
|
|---|
| 6730 | return FALSE;
|
|---|
| 6731 | for ( int i = 0; i < (int)s.length(); i++ ) {
|
|---|
| 6732 | if ( doc[ pos + i ].lower() != s[ i ].lower() )
|
|---|
| 6733 | return FALSE;
|
|---|
| 6734 | }
|
|---|
| 6735 | return TRUE;
|
|---|
| 6736 | }
|
|---|
| 6737 |
|
|---|
| 6738 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 6739 | static bool qt_is_cell_in_use( QPtrList<QTextTableCell>& cells, int row, int col )
|
|---|
| 6740 | {
|
|---|
| 6741 | for ( QTextTableCell* c = cells.first(); c; c = cells.next() ) {
|
|---|
| 6742 | if ( row >= c->row() && row < c->row() + c->rowspan()
|
|---|
| 6743 | && col >= c->column() && col < c->column() + c->colspan() )
|
|---|
| 6744 | return TRUE;
|
|---|
| 6745 | }
|
|---|
| 6746 | return FALSE;
|
|---|
| 6747 | }
|
|---|
| 6748 |
|
|---|
| 6749 | QTextCustomItem* QTextDocument::parseTable( const QMap<QString, QString> &attr, const QTextFormat &fmt,
|
|---|
| 6750 | const QChar* doc, int length, int& pos, QTextParagraph *curpar )
|
|---|
| 6751 | {
|
|---|
| 6752 |
|
|---|
| 6753 | QTextTable* table = new QTextTable( this, attr );
|
|---|
| 6754 | int row = -1;
|
|---|
| 6755 | int col = -1;
|
|---|
| 6756 |
|
|---|
| 6757 | QString rowbgcolor;
|
|---|
| 6758 | QString rowalign;
|
|---|
| 6759 | QString tablebgcolor = attr["bgcolor"];
|
|---|
| 6760 |
|
|---|
| 6761 | QPtrList<QTextTableCell> multicells;
|
|---|
| 6762 |
|
|---|
| 6763 | QString tagname;
|
|---|
| 6764 | (void) eatSpace(doc, length, pos);
|
|---|
| 6765 | while ( pos < length) {
|
|---|
| 6766 | if (hasPrefix(doc, length, pos, QChar('<')) ){
|
|---|
| 6767 | if (hasPrefix(doc, length, pos+1, QChar('/'))) {
|
|---|
| 6768 | tagname = parseCloseTag( doc, length, pos );
|
|---|
| 6769 | if ( tagname == "table" ) {
|
|---|
| 6770 | return table;
|
|---|
| 6771 | }
|
|---|
| 6772 | } else {
|
|---|
| 6773 | QMap<QString, QString> attr2;
|
|---|
| 6774 | bool emptyTag = FALSE;
|
|---|
| 6775 | tagname = parseOpenTag( doc, length, pos, attr2, emptyTag );
|
|---|
| 6776 | if ( tagname == "tr" ) {
|
|---|
| 6777 | rowbgcolor = attr2["bgcolor"];
|
|---|
| 6778 | rowalign = attr2["align"];
|
|---|
| 6779 | row++;
|
|---|
| 6780 | col = -1;
|
|---|
| 6781 | }
|
|---|
| 6782 | else if ( tagname == "td" || tagname == "th" ) {
|
|---|
| 6783 | col++;
|
|---|
| 6784 | while ( qt_is_cell_in_use( multicells, row, col ) ) {
|
|---|
| 6785 | col++;
|
|---|
| 6786 | }
|
|---|
| 6787 |
|
|---|
| 6788 | if ( row >= 0 && col >= 0 ) {
|
|---|
| 6789 | const QStyleSheetItem* s = sheet_->item(tagname);
|
|---|
| 6790 | if ( !attr2.contains("bgcolor") ) {
|
|---|
| 6791 | if (!rowbgcolor.isEmpty() )
|
|---|
| 6792 | attr2["bgcolor"] = rowbgcolor;
|
|---|
| 6793 | else if (!tablebgcolor.isEmpty() )
|
|---|
| 6794 | attr2["bgcolor"] = tablebgcolor;
|
|---|
| 6795 | }
|
|---|
| 6796 | if ( !attr2.contains("align") ) {
|
|---|
| 6797 | if (!rowalign.isEmpty() )
|
|---|
| 6798 | attr2["align"] = rowalign;
|
|---|
| 6799 | }
|
|---|
| 6800 |
|
|---|
| 6801 | // extract the cell contents
|
|---|
| 6802 | int end = pos;
|
|---|
| 6803 | while ( end < length
|
|---|
| 6804 | && !hasPrefix( doc, length, end, "</td")
|
|---|
| 6805 | && !hasPrefix( doc, length, end, "<td")
|
|---|
| 6806 | && !hasPrefix( doc, length, end, "</th")
|
|---|
| 6807 | && !hasPrefix( doc, length, end, "<th")
|
|---|
| 6808 | && !hasPrefix( doc, length, end, "<td")
|
|---|
| 6809 | && !hasPrefix( doc, length, end, "</tr")
|
|---|
| 6810 | && !hasPrefix( doc, length, end, "<tr")
|
|---|
| 6811 | && !hasPrefix( doc, length, end, "</table") ) {
|
|---|
| 6812 | if ( hasPrefix( doc, length, end, "<table" ) ) { // nested table
|
|---|
| 6813 | int nested = 1;
|
|---|
| 6814 | ++end;
|
|---|
| 6815 | while ( end < length && nested != 0 ) {
|
|---|
| 6816 | if ( hasPrefix( doc, length, end, "</table" ) )
|
|---|
| 6817 | nested--;
|
|---|
| 6818 | if ( hasPrefix( doc, length, end, "<table" ) )
|
|---|
| 6819 | nested++;
|
|---|
| 6820 | end++;
|
|---|
| 6821 | }
|
|---|
| 6822 | }
|
|---|
| 6823 | end++;
|
|---|
| 6824 | }
|
|---|
| 6825 | QTextTableCell* cell = new QTextTableCell( table, row, col,
|
|---|
| 6826 | attr2, s, fmt.makeTextFormat( s, attr2, scaleFontsFactor ),
|
|---|
| 6827 | contxt, *factory_, sheet_,
|
|---|
| 6828 | QConstString( doc + pos, end - pos ).string() );
|
|---|
| 6829 | cell->richText()->parentPar = curpar;
|
|---|
| 6830 | if ( cell->colspan() > 1 || cell->rowspan() > 1 )
|
|---|
| 6831 | multicells.append( cell );
|
|---|
| 6832 | col += cell->colspan()-1;
|
|---|
| 6833 | pos = end;
|
|---|
| 6834 | }
|
|---|
| 6835 | }
|
|---|
| 6836 | }
|
|---|
| 6837 |
|
|---|
| 6838 | } else {
|
|---|
| 6839 | ++pos;
|
|---|
| 6840 | }
|
|---|
| 6841 | }
|
|---|
| 6842 | return table;
|
|---|
| 6843 | }
|
|---|
| 6844 | #endif // QT_NO_TEXTCUSTOMITEM
|
|---|
| 6845 |
|
|---|
| 6846 | bool QTextDocument::eatSpace(const QChar* doc, int length, int& pos, bool includeNbsp )
|
|---|
| 6847 | {
|
|---|
| 6848 | int old_pos = pos;
|
|---|
| 6849 | while (pos < length && doc[pos].isSpace() && ( includeNbsp || (doc[pos] != QChar::nbsp ) ) )
|
|---|
| 6850 | pos++;
|
|---|
| 6851 | return old_pos < pos;
|
|---|
| 6852 | }
|
|---|
| 6853 |
|
|---|
| 6854 | bool QTextDocument::eat(const QChar* doc, int length, int& pos, QChar c)
|
|---|
| 6855 | {
|
|---|
| 6856 | bool ok = pos < length && doc[pos] == c;
|
|---|
| 6857 | if ( ok )
|
|---|
| 6858 | pos++;
|
|---|
| 6859 | return ok;
|
|---|
| 6860 | }
|
|---|
| 6861 | /*****************************************************************/
|
|---|
| 6862 |
|
|---|
| 6863 | struct Entity {
|
|---|
| 6864 | const char * name;
|
|---|
| 6865 | Q_UINT16 code;
|
|---|
| 6866 | };
|
|---|
| 6867 |
|
|---|
| 6868 | static const Entity entitylist [] = {
|
|---|
| 6869 | { "AElig", 0x00c6 },
|
|---|
| 6870 | { "Aacute", 0x00c1 },
|
|---|
| 6871 | { "Acirc", 0x00c2 },
|
|---|
| 6872 | { "Agrave", 0x00c0 },
|
|---|
| 6873 | { "Alpha", 0x0391 },
|
|---|
| 6874 | { "AMP", 38 },
|
|---|
| 6875 | { "Aring", 0x00c5 },
|
|---|
| 6876 | { "Atilde", 0x00c3 },
|
|---|
| 6877 | { "Auml", 0x00c4 },
|
|---|
| 6878 | { "Beta", 0x0392 },
|
|---|
| 6879 | { "Ccedil", 0x00c7 },
|
|---|
| 6880 | { "Chi", 0x03a7 },
|
|---|
| 6881 | { "Dagger", 0x2021 },
|
|---|
| 6882 | { "Delta", 0x0394 },
|
|---|
| 6883 | { "ETH", 0x00d0 },
|
|---|
| 6884 | { "Eacute", 0x00c9 },
|
|---|
| 6885 | { "Ecirc", 0x00ca },
|
|---|
| 6886 | { "Egrave", 0x00c8 },
|
|---|
| 6887 | { "Epsilon", 0x0395 },
|
|---|
| 6888 | { "Eta", 0x0397 },
|
|---|
| 6889 | { "Euml", 0x00cb },
|
|---|
| 6890 | { "Gamma", 0x0393 },
|
|---|
| 6891 | { "GT", 62 },
|
|---|
| 6892 | { "Iacute", 0x00cd },
|
|---|
| 6893 | { "Icirc", 0x00ce },
|
|---|
| 6894 | { "Igrave", 0x00cc },
|
|---|
| 6895 | { "Iota", 0x0399 },
|
|---|
| 6896 | { "Iuml", 0x00cf },
|
|---|
| 6897 | { "Kappa", 0x039a },
|
|---|
| 6898 | { "Lambda", 0x039b },
|
|---|
| 6899 | { "LT", 60 },
|
|---|
| 6900 | { "Mu", 0x039c },
|
|---|
| 6901 | { "Ntilde", 0x00d1 },
|
|---|
| 6902 | { "Nu", 0x039d },
|
|---|
| 6903 | { "OElig", 0x0152 },
|
|---|
| 6904 | { "Oacute", 0x00d3 },
|
|---|
| 6905 | { "Ocirc", 0x00d4 },
|
|---|
| 6906 | { "Ograve", 0x00d2 },
|
|---|
| 6907 | { "Omega", 0x03a9 },
|
|---|
| 6908 | { "Omicron", 0x039f },
|
|---|
| 6909 | { "Oslash", 0x00d8 },
|
|---|
| 6910 | { "Otilde", 0x00d5 },
|
|---|
| 6911 | { "Ouml", 0x00d6 },
|
|---|
| 6912 | { "Phi", 0x03a6 },
|
|---|
| 6913 | { "Pi", 0x03a0 },
|
|---|
| 6914 | { "Prime", 0x2033 },
|
|---|
| 6915 | { "Psi", 0x03a8 },
|
|---|
| 6916 | { "QUOT", 34 },
|
|---|
| 6917 | { "Rho", 0x03a1 },
|
|---|
| 6918 | { "Scaron", 0x0160 },
|
|---|
| 6919 | { "Sigma", 0x03a3 },
|
|---|
| 6920 | { "THORN", 0x00de },
|
|---|
| 6921 | { "Tau", 0x03a4 },
|
|---|
| 6922 | { "Theta", 0x0398 },
|
|---|
| 6923 | { "Uacute", 0x00da },
|
|---|
| 6924 | { "Ucirc", 0x00db },
|
|---|
| 6925 | { "Ugrave", 0x00d9 },
|
|---|
| 6926 | { "Upsilon", 0x03a5 },
|
|---|
| 6927 | { "Uuml", 0x00dc },
|
|---|
| 6928 | { "Xi", 0x039e },
|
|---|
| 6929 | { "Yacute", 0x00dd },
|
|---|
| 6930 | { "Yuml", 0x0178 },
|
|---|
| 6931 | { "Zeta", 0x0396 },
|
|---|
| 6932 | { "aacute", 0x00e1 },
|
|---|
| 6933 | { "acirc", 0x00e2 },
|
|---|
| 6934 | { "acute", 0x00b4 },
|
|---|
| 6935 | { "aelig", 0x00e6 },
|
|---|
| 6936 | { "agrave", 0x00e0 },
|
|---|
| 6937 | { "alefsym", 0x2135 },
|
|---|
| 6938 | { "alpha", 0x03b1 },
|
|---|
| 6939 | { "amp", 38 },
|
|---|
| 6940 | { "and", 0x22a5 },
|
|---|
| 6941 | { "ang", 0x2220 },
|
|---|
| 6942 | { "apos", 0x0027 },
|
|---|
| 6943 | { "aring", 0x00e5 },
|
|---|
| 6944 | { "asymp", 0x2248 },
|
|---|
| 6945 | { "atilde", 0x00e3 },
|
|---|
| 6946 | { "auml", 0x00e4 },
|
|---|
| 6947 | { "bdquo", 0x201e },
|
|---|
| 6948 | { "beta", 0x03b2 },
|
|---|
| 6949 | { "brvbar", 0x00a6 },
|
|---|
| 6950 | { "bull", 0x2022 },
|
|---|
| 6951 | { "cap", 0x2229 },
|
|---|
| 6952 | { "ccedil", 0x00e7 },
|
|---|
| 6953 | { "cedil", 0x00b8 },
|
|---|
| 6954 | { "cent", 0x00a2 },
|
|---|
| 6955 | { "chi", 0x03c7 },
|
|---|
| 6956 | { "circ", 0x02c6 },
|
|---|
| 6957 | { "clubs", 0x2663 },
|
|---|
| 6958 | { "cong", 0x2245 },
|
|---|
| 6959 | { "copy", 0x00a9 },
|
|---|
| 6960 | { "crarr", 0x21b5 },
|
|---|
| 6961 | { "cup", 0x222a },
|
|---|
| 6962 | { "curren", 0x00a4 },
|
|---|
| 6963 | { "dArr", 0x21d3 },
|
|---|
| 6964 | { "dagger", 0x2020 },
|
|---|
| 6965 | { "darr", 0x2193 },
|
|---|
| 6966 | { "deg", 0x00b0 },
|
|---|
| 6967 | { "delta", 0x03b4 },
|
|---|
| 6968 | { "diams", 0x2666 },
|
|---|
| 6969 | { "divide", 0x00f7 },
|
|---|
| 6970 | { "eacute", 0x00e9 },
|
|---|
| 6971 | { "ecirc", 0x00ea },
|
|---|
| 6972 | { "egrave", 0x00e8 },
|
|---|
| 6973 | { "empty", 0x2205 },
|
|---|
| 6974 | { "emsp", 0x2003 },
|
|---|
| 6975 | { "ensp", 0x2002 },
|
|---|
| 6976 | { "epsilon", 0x03b5 },
|
|---|
| 6977 | { "equiv", 0x2261 },
|
|---|
| 6978 | { "eta", 0x03b7 },
|
|---|
| 6979 | { "eth", 0x00f0 },
|
|---|
| 6980 | { "euml", 0x00eb },
|
|---|
| 6981 | { "euro", 0x20ac },
|
|---|
| 6982 | { "exist", 0x2203 },
|
|---|
| 6983 | { "fnof", 0x0192 },
|
|---|
| 6984 | { "forall", 0x2200 },
|
|---|
| 6985 | { "frac12", 0x00bd },
|
|---|
| 6986 | { "frac14", 0x00bc },
|
|---|
| 6987 | { "frac34", 0x00be },
|
|---|
| 6988 | { "frasl", 0x2044 },
|
|---|
| 6989 | { "gamma", 0x03b3 },
|
|---|
| 6990 | { "ge", 0x2265 },
|
|---|
| 6991 | { "gt", 62 },
|
|---|
| 6992 | { "hArr", 0x21d4 },
|
|---|
| 6993 | { "harr", 0x2194 },
|
|---|
| 6994 | { "hearts", 0x2665 },
|
|---|
| 6995 | { "hellip", 0x2026 },
|
|---|
| 6996 | { "iacute", 0x00ed },
|
|---|
| 6997 | { "icirc", 0x00ee },
|
|---|
| 6998 | { "iexcl", 0x00a1 },
|
|---|
| 6999 | { "igrave", 0x00ec },
|
|---|
| 7000 | { "image", 0x2111 },
|
|---|
| 7001 | { "infin", 0x221e },
|
|---|
| 7002 | { "int", 0x222b },
|
|---|
| 7003 | { "iota", 0x03b9 },
|
|---|
| 7004 | { "iquest", 0x00bf },
|
|---|
| 7005 | { "isin", 0x2208 },
|
|---|
| 7006 | { "iuml", 0x00ef },
|
|---|
| 7007 | { "kappa", 0x03ba },
|
|---|
| 7008 | { "lArr", 0x21d0 },
|
|---|
| 7009 | { "lambda", 0x03bb },
|
|---|
| 7010 | { "lang", 0x2329 },
|
|---|
| 7011 | { "laquo", 0x00ab },
|
|---|
| 7012 | { "larr", 0x2190 },
|
|---|
| 7013 | { "lceil", 0x2308 },
|
|---|
| 7014 | { "ldquo", 0x201c },
|
|---|
| 7015 | { "le", 0x2264 },
|
|---|
| 7016 | { "lfloor", 0x230a },
|
|---|
| 7017 | { "lowast", 0x2217 },
|
|---|
| 7018 | { "loz", 0x25ca },
|
|---|
| 7019 | { "lrm", 0x200e },
|
|---|
| 7020 | { "lsaquo", 0x2039 },
|
|---|
| 7021 | { "lsquo", 0x2018 },
|
|---|
| 7022 | { "lt", 60 },
|
|---|
| 7023 | { "macr", 0x00af },
|
|---|
| 7024 | { "mdash", 0x2014 },
|
|---|
| 7025 | { "micro", 0x00b5 },
|
|---|
| 7026 | { "middot", 0x00b7 },
|
|---|
| 7027 | { "minus", 0x2212 },
|
|---|
| 7028 | { "mu", 0x03bc },
|
|---|
| 7029 | { "nabla", 0x2207 },
|
|---|
| 7030 | { "nbsp", 0x00a0 },
|
|---|
| 7031 | { "ndash", 0x2013 },
|
|---|
| 7032 | { "ne", 0x2260 },
|
|---|
| 7033 | { "ni", 0x220b },
|
|---|
| 7034 | { "not", 0x00ac },
|
|---|
| 7035 | { "notin", 0x2209 },
|
|---|
| 7036 | { "nsub", 0x2284 },
|
|---|
| 7037 | { "ntilde", 0x00f1 },
|
|---|
| 7038 | { "nu", 0x03bd },
|
|---|
| 7039 | { "oacute", 0x00f3 },
|
|---|
| 7040 | { "ocirc", 0x00f4 },
|
|---|
| 7041 | { "oelig", 0x0153 },
|
|---|
| 7042 | { "ograve", 0x00f2 },
|
|---|
| 7043 | { "oline", 0x203e },
|
|---|
| 7044 | { "omega", 0x03c9 },
|
|---|
| 7045 | { "omicron", 0x03bf },
|
|---|
| 7046 | { "oplus", 0x2295 },
|
|---|
| 7047 | { "or", 0x22a6 },
|
|---|
| 7048 | { "ordf", 0x00aa },
|
|---|
| 7049 | { "ordm", 0x00ba },
|
|---|
| 7050 | { "oslash", 0x00f8 },
|
|---|
| 7051 | { "otilde", 0x00f5 },
|
|---|
| 7052 | { "otimes", 0x2297 },
|
|---|
| 7053 | { "ouml", 0x00f6 },
|
|---|
| 7054 | { "para", 0x00b6 },
|
|---|
| 7055 | { "part", 0x2202 },
|
|---|
| 7056 | { "percnt", 0x0025 },
|
|---|
| 7057 | { "permil", 0x2030 },
|
|---|
| 7058 | { "perp", 0x22a5 },
|
|---|
| 7059 | { "phi", 0x03c6 },
|
|---|
| 7060 | { "pi", 0x03c0 },
|
|---|
| 7061 | { "piv", 0x03d6 },
|
|---|
| 7062 | { "plusmn", 0x00b1 },
|
|---|
| 7063 | { "pound", 0x00a3 },
|
|---|
| 7064 | { "prime", 0x2032 },
|
|---|
| 7065 | { "prod", 0x220f },
|
|---|
| 7066 | { "prop", 0x221d },
|
|---|
| 7067 | { "psi", 0x03c8 },
|
|---|
| 7068 | { "quot", 34 },
|
|---|
| 7069 | { "rArr", 0x21d2 },
|
|---|
| 7070 | { "radic", 0x221a },
|
|---|
| 7071 | { "rang", 0x232a },
|
|---|
| 7072 | { "raquo", 0x00bb },
|
|---|
| 7073 | { "rarr", 0x2192 },
|
|---|
| 7074 | { "rceil", 0x2309 },
|
|---|
| 7075 | { "rdquo", 0x201d },
|
|---|
| 7076 | { "real", 0x211c },
|
|---|
| 7077 | { "reg", 0x00ae },
|
|---|
| 7078 | { "rfloor", 0x230b },
|
|---|
| 7079 | { "rho", 0x03c1 },
|
|---|
| 7080 | { "rlm", 0x200f },
|
|---|
| 7081 | { "rsaquo", 0x203a },
|
|---|
| 7082 | { "rsquo", 0x2019 },
|
|---|
| 7083 | { "sbquo", 0x201a },
|
|---|
| 7084 | { "scaron", 0x0161 },
|
|---|
| 7085 | { "sdot", 0x22c5 },
|
|---|
| 7086 | { "sect", 0x00a7 },
|
|---|
| 7087 | { "shy", 0x00ad },
|
|---|
| 7088 | { "sigma", 0x03c3 },
|
|---|
| 7089 | { "sigmaf", 0x03c2 },
|
|---|
| 7090 | { "sim", 0x223c },
|
|---|
| 7091 | { "spades", 0x2660 },
|
|---|
| 7092 | { "sub", 0x2282 },
|
|---|
| 7093 | { "sube", 0x2286 },
|
|---|
| 7094 | { "sum", 0x2211 },
|
|---|
| 7095 | { "sup1", 0x00b9 },
|
|---|
| 7096 | { "sup2", 0x00b2 },
|
|---|
| 7097 | { "sup3", 0x00b3 },
|
|---|
| 7098 | { "sup", 0x2283 },
|
|---|
| 7099 | { "supe", 0x2287 },
|
|---|
| 7100 | { "szlig", 0x00df },
|
|---|
| 7101 | { "tau", 0x03c4 },
|
|---|
| 7102 | { "there4", 0x2234 },
|
|---|
| 7103 | { "theta", 0x03b8 },
|
|---|
| 7104 | { "thetasym", 0x03d1 },
|
|---|
| 7105 | { "thinsp", 0x2009 },
|
|---|
| 7106 | { "thorn", 0x00fe },
|
|---|
| 7107 | { "tilde", 0x02dc },
|
|---|
| 7108 | { "times", 0x00d7 },
|
|---|
| 7109 | { "trade", 0x2122 },
|
|---|
| 7110 | { "uArr", 0x21d1 },
|
|---|
| 7111 | { "uacute", 0x00fa },
|
|---|
| 7112 | { "uarr", 0x2191 },
|
|---|
| 7113 | { "ucirc", 0x00fb },
|
|---|
| 7114 | { "ugrave", 0x00f9 },
|
|---|
| 7115 | { "uml", 0x00a8 },
|
|---|
| 7116 | { "upsih", 0x03d2 },
|
|---|
| 7117 | { "upsilon", 0x03c5 },
|
|---|
| 7118 | { "uuml", 0x00fc },
|
|---|
| 7119 | { "weierp", 0x2118 },
|
|---|
| 7120 | { "xi", 0x03be },
|
|---|
| 7121 | { "yacute", 0x00fd },
|
|---|
| 7122 | { "yen", 0x00a5 },
|
|---|
| 7123 | { "yuml", 0x00ff },
|
|---|
| 7124 | { "zeta", 0x03b6 },
|
|---|
| 7125 | { "zwj", 0x200d },
|
|---|
| 7126 | { "zwnj", 0x200c },
|
|---|
| 7127 | { "", 0x0000 }
|
|---|
| 7128 | };
|
|---|
| 7129 |
|
|---|
| 7130 |
|
|---|
| 7131 |
|
|---|
| 7132 |
|
|---|
| 7133 |
|
|---|
| 7134 | static QMap<QCString, QChar> *html_map = 0;
|
|---|
| 7135 | static void qt_cleanup_html_map()
|
|---|
| 7136 | {
|
|---|
| 7137 | delete html_map;
|
|---|
| 7138 | html_map = 0;
|
|---|
| 7139 | }
|
|---|
| 7140 |
|
|---|
| 7141 | static QMap<QCString, QChar> *htmlMap()
|
|---|
| 7142 | {
|
|---|
| 7143 | if ( !html_map ) {
|
|---|
| 7144 | html_map = new QMap<QCString, QChar>;
|
|---|
| 7145 | qAddPostRoutine( qt_cleanup_html_map );
|
|---|
| 7146 |
|
|---|
| 7147 | const Entity *ent = entitylist;
|
|---|
| 7148 | while( ent->code ) {
|
|---|
| 7149 | html_map->insert( ent->name, QChar(ent->code) );
|
|---|
| 7150 | ent++;
|
|---|
| 7151 | }
|
|---|
| 7152 | }
|
|---|
| 7153 | return html_map;
|
|---|
| 7154 | }
|
|---|
| 7155 |
|
|---|
| 7156 | QChar QTextDocument::parseHTMLSpecialChar(const QChar* doc, int length, int& pos)
|
|---|
| 7157 | {
|
|---|
| 7158 | QCString s;
|
|---|
| 7159 | pos++;
|
|---|
| 7160 | int recoverpos = pos;
|
|---|
| 7161 | while ( pos < length && doc[pos] != ';' && !doc[pos].isSpace() && pos < recoverpos + 8 ) {
|
|---|
| 7162 | s += doc[pos];
|
|---|
| 7163 | pos++;
|
|---|
| 7164 | }
|
|---|
| 7165 | if (doc[pos] != ';' && !doc[pos].isSpace() ) {
|
|---|
| 7166 | pos = recoverpos;
|
|---|
| 7167 | return '&';
|
|---|
| 7168 | }
|
|---|
| 7169 | pos++;
|
|---|
| 7170 |
|
|---|
| 7171 | if ( s.length() > 1 && s[0] == '#') {
|
|---|
| 7172 | int num = s.mid(1).toInt();
|
|---|
| 7173 | if ( num == 151 ) // ### hack for designer manual
|
|---|
| 7174 | return '-';
|
|---|
| 7175 | return num;
|
|---|
| 7176 | }
|
|---|
| 7177 |
|
|---|
| 7178 | QMap<QCString, QChar>::Iterator it = htmlMap()->find(s);
|
|---|
| 7179 | if ( it != htmlMap()->end() ) {
|
|---|
| 7180 | return *it;
|
|---|
| 7181 | }
|
|---|
| 7182 |
|
|---|
| 7183 | pos = recoverpos;
|
|---|
| 7184 | return '&';
|
|---|
| 7185 | }
|
|---|
| 7186 |
|
|---|
| 7187 | QString QTextDocument::parseWord(const QChar* doc, int length, int& pos, bool lower)
|
|---|
| 7188 | {
|
|---|
| 7189 | QString s;
|
|---|
| 7190 |
|
|---|
| 7191 | if (doc[pos] == '"') {
|
|---|
| 7192 | pos++;
|
|---|
| 7193 | while ( pos < length && doc[pos] != '"' ) {
|
|---|
| 7194 | if ( doc[pos] == '&' ) {
|
|---|
| 7195 | s += parseHTMLSpecialChar( doc, length, pos );
|
|---|
| 7196 | } else {
|
|---|
| 7197 | s += doc[pos];
|
|---|
| 7198 | pos++;
|
|---|
| 7199 | }
|
|---|
| 7200 | }
|
|---|
| 7201 | eat(doc, length, pos, '"');
|
|---|
| 7202 | } else if (doc[pos] == '\'') {
|
|---|
| 7203 | pos++;
|
|---|
| 7204 | while ( pos < length && doc[pos] != '\'' ) {
|
|---|
| 7205 | s += doc[pos];
|
|---|
| 7206 | pos++;
|
|---|
| 7207 | }
|
|---|
| 7208 | eat(doc, length, pos, '\'');
|
|---|
| 7209 | } else {
|
|---|
| 7210 | static QString term = QString::fromLatin1("/>");
|
|---|
| 7211 | while ( pos < length
|
|---|
| 7212 | && doc[pos] != '>'
|
|---|
| 7213 | && !hasPrefix(doc, length, pos, term)
|
|---|
| 7214 | && doc[pos] != '<'
|
|---|
| 7215 | && doc[pos] != '='
|
|---|
| 7216 | && !doc[pos].isSpace() )
|
|---|
| 7217 | {
|
|---|
| 7218 | if ( doc[pos] == '&' ) {
|
|---|
| 7219 | s += parseHTMLSpecialChar( doc, length, pos );
|
|---|
| 7220 | } else {
|
|---|
| 7221 | s += doc[pos];
|
|---|
| 7222 | pos++;
|
|---|
| 7223 | }
|
|---|
| 7224 | }
|
|---|
| 7225 | if (lower)
|
|---|
| 7226 | s = s.lower();
|
|---|
| 7227 | }
|
|---|
| 7228 | return s;
|
|---|
| 7229 | }
|
|---|
| 7230 |
|
|---|
| 7231 | QChar QTextDocument::parseChar(const QChar* doc, int length, int& pos, QStyleSheetItem::WhiteSpaceMode wsm )
|
|---|
| 7232 | {
|
|---|
| 7233 | if ( pos >= length )
|
|---|
| 7234 | return QChar::null;
|
|---|
| 7235 |
|
|---|
| 7236 | QChar c = doc[pos++];
|
|---|
| 7237 |
|
|---|
| 7238 | if (c == '<' )
|
|---|
| 7239 | return QChar::null;
|
|---|
| 7240 |
|
|---|
| 7241 | if ( c.isSpace() && c != QChar::nbsp ) {
|
|---|
| 7242 | if ( wsm == QStyleSheetItem::WhiteSpacePre ) {
|
|---|
| 7243 | if ( c == '\n' )
|
|---|
| 7244 | return QChar_linesep;
|
|---|
| 7245 | else
|
|---|
| 7246 | return c;
|
|---|
| 7247 | } else { // non-pre mode: collapse whitespace except nbsp
|
|---|
| 7248 | while ( pos< length &&
|
|---|
| 7249 | doc[pos].isSpace() && doc[pos] != QChar::nbsp )
|
|---|
| 7250 | pos++;
|
|---|
| 7251 | return ' ';
|
|---|
| 7252 | }
|
|---|
| 7253 | }
|
|---|
| 7254 | else if ( c == '&' )
|
|---|
| 7255 | return parseHTMLSpecialChar( doc, length, --pos );
|
|---|
| 7256 | else
|
|---|
| 7257 | return c;
|
|---|
| 7258 | }
|
|---|
| 7259 |
|
|---|
| 7260 | QString QTextDocument::parseOpenTag(const QChar* doc, int length, int& pos,
|
|---|
| 7261 | QMap<QString, QString> &attr, bool& emptyTag)
|
|---|
| 7262 | {
|
|---|
| 7263 | emptyTag = FALSE;
|
|---|
| 7264 | pos++;
|
|---|
| 7265 | if ( hasPrefix(doc, length, pos, '!') ) {
|
|---|
| 7266 | if ( hasPrefix( doc, length, pos+1, "--")) {
|
|---|
| 7267 | pos += 3;
|
|---|
| 7268 | // eat comments
|
|---|
| 7269 | QString pref = QString::fromLatin1("-->");
|
|---|
| 7270 | while ( !hasPrefix(doc, length, pos, pref ) && pos < length )
|
|---|
| 7271 | pos++;
|
|---|
| 7272 | if ( hasPrefix(doc, length, pos, pref ) ) {
|
|---|
| 7273 | pos += 3;
|
|---|
| 7274 | eatSpace(doc, length, pos, TRUE);
|
|---|
| 7275 | }
|
|---|
| 7276 | emptyTag = TRUE;
|
|---|
| 7277 | return QString::null;
|
|---|
| 7278 | }
|
|---|
| 7279 | else {
|
|---|
| 7280 | // eat strange internal tags
|
|---|
| 7281 | while ( !hasPrefix(doc, length, pos, '>') && pos < length )
|
|---|
| 7282 | pos++;
|
|---|
| 7283 | if ( hasPrefix(doc, length, pos, '>') ) {
|
|---|
| 7284 | pos++;
|
|---|
| 7285 | eatSpace(doc, length, pos, TRUE);
|
|---|
| 7286 | }
|
|---|
| 7287 | return QString::null;
|
|---|
| 7288 | }
|
|---|
| 7289 | }
|
|---|
| 7290 |
|
|---|
| 7291 | QString tag = parseWord(doc, length, pos );
|
|---|
| 7292 | eatSpace(doc, length, pos, TRUE);
|
|---|
| 7293 | static QString term = QString::fromLatin1("/>");
|
|---|
| 7294 | static QString s_TRUE = QString::fromLatin1("TRUE");
|
|---|
| 7295 |
|
|---|
| 7296 | while (doc[pos] != '>' && ! (emptyTag = hasPrefix(doc, length, pos, term) )) {
|
|---|
| 7297 | QString key = parseWord(doc, length, pos );
|
|---|
| 7298 | eatSpace(doc, length, pos, TRUE);
|
|---|
| 7299 | if ( key.isEmpty()) {
|
|---|
| 7300 | // error recovery
|
|---|
| 7301 | while ( pos < length && doc[pos] != '>' )
|
|---|
| 7302 | pos++;
|
|---|
| 7303 | break;
|
|---|
| 7304 | }
|
|---|
| 7305 | QString value;
|
|---|
| 7306 | if (hasPrefix(doc, length, pos, '=') ){
|
|---|
| 7307 | pos++;
|
|---|
| 7308 | eatSpace(doc, length, pos);
|
|---|
| 7309 | value = parseWord(doc, length, pos, FALSE);
|
|---|
| 7310 | }
|
|---|
| 7311 | else
|
|---|
| 7312 | value = s_TRUE;
|
|---|
| 7313 | attr.insert(key.lower(), value );
|
|---|
| 7314 | eatSpace(doc, length, pos, TRUE);
|
|---|
| 7315 | }
|
|---|
| 7316 |
|
|---|
| 7317 | if (emptyTag) {
|
|---|
| 7318 | eat(doc, length, pos, '/');
|
|---|
| 7319 | eat(doc, length, pos, '>');
|
|---|
| 7320 | }
|
|---|
| 7321 | else
|
|---|
| 7322 | eat(doc, length, pos, '>');
|
|---|
| 7323 |
|
|---|
| 7324 | return tag;
|
|---|
| 7325 | }
|
|---|
| 7326 |
|
|---|
| 7327 | QString QTextDocument::parseCloseTag( const QChar* doc, int length, int& pos )
|
|---|
| 7328 | {
|
|---|
| 7329 | pos++;
|
|---|
| 7330 | pos++;
|
|---|
| 7331 | QString tag = parseWord(doc, length, pos );
|
|---|
| 7332 | eatSpace(doc, length, pos, TRUE);
|
|---|
| 7333 | eat(doc, length, pos, '>');
|
|---|
| 7334 | return tag;
|
|---|
| 7335 | }
|
|---|
| 7336 |
|
|---|
| 7337 | QTextFlow::QTextFlow()
|
|---|
| 7338 | {
|
|---|
| 7339 | w = pagesize = 0;
|
|---|
| 7340 | }
|
|---|
| 7341 |
|
|---|
| 7342 | QTextFlow::~QTextFlow()
|
|---|
| 7343 | {
|
|---|
| 7344 | clear();
|
|---|
| 7345 | }
|
|---|
| 7346 |
|
|---|
| 7347 | void QTextFlow::clear()
|
|---|
| 7348 | {
|
|---|
| 7349 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 7350 | leftItems.setAutoDelete( TRUE );
|
|---|
| 7351 | rightItems.setAutoDelete( TRUE );
|
|---|
| 7352 | leftItems.clear();
|
|---|
| 7353 | rightItems.clear();
|
|---|
| 7354 | leftItems.setAutoDelete( FALSE );
|
|---|
| 7355 | rightItems.setAutoDelete( FALSE );
|
|---|
| 7356 | #endif
|
|---|
| 7357 | }
|
|---|
| 7358 |
|
|---|
| 7359 | void QTextFlow::setWidth( int width )
|
|---|
| 7360 | {
|
|---|
| 7361 | w = width;
|
|---|
| 7362 | }
|
|---|
| 7363 |
|
|---|
| 7364 | int QTextFlow::adjustLMargin( int yp, int, int margin, int space )
|
|---|
| 7365 | {
|
|---|
| 7366 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 7367 | for ( QTextCustomItem* item = leftItems.first(); item; item = leftItems.next() ) {
|
|---|
| 7368 | if ( item->ypos == -1 )
|
|---|
| 7369 | continue;
|
|---|
| 7370 | if ( yp >= item->ypos && yp < item->ypos + item->height )
|
|---|
| 7371 | margin = QMAX( margin, item->xpos + item->width + space );
|
|---|
| 7372 | }
|
|---|
| 7373 | #endif
|
|---|
| 7374 | return margin;
|
|---|
| 7375 | }
|
|---|
| 7376 |
|
|---|
| 7377 | int QTextFlow::adjustRMargin( int yp, int, int margin, int space )
|
|---|
| 7378 | {
|
|---|
| 7379 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 7380 | for ( QTextCustomItem* item = rightItems.first(); item; item = rightItems.next() ) {
|
|---|
| 7381 | if ( item->ypos == -1 )
|
|---|
| 7382 | continue;
|
|---|
| 7383 | if ( yp >= item->ypos && yp < item->ypos + item->height )
|
|---|
| 7384 | margin = QMAX( margin, w - item->xpos - space );
|
|---|
| 7385 | }
|
|---|
| 7386 | #endif
|
|---|
| 7387 | return margin;
|
|---|
| 7388 | }
|
|---|
| 7389 |
|
|---|
| 7390 |
|
|---|
| 7391 | int QTextFlow::adjustFlow( int y, int /*w*/, int h )
|
|---|
| 7392 | {
|
|---|
| 7393 | if ( pagesize > 0 ) { // check pages
|
|---|
| 7394 | int yinpage = y % pagesize;
|
|---|
| 7395 | if ( yinpage <= border_tolerance )
|
|---|
| 7396 | return border_tolerance - yinpage;
|
|---|
| 7397 | else
|
|---|
| 7398 | if ( yinpage + h > pagesize - border_tolerance )
|
|---|
| 7399 | return ( pagesize - yinpage ) + border_tolerance;
|
|---|
| 7400 | }
|
|---|
| 7401 | return 0;
|
|---|
| 7402 | }
|
|---|
| 7403 |
|
|---|
| 7404 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 7405 | void QTextFlow::unregisterFloatingItem( QTextCustomItem* item )
|
|---|
| 7406 | {
|
|---|
| 7407 | leftItems.removeRef( item );
|
|---|
| 7408 | rightItems.removeRef( item );
|
|---|
| 7409 | }
|
|---|
| 7410 |
|
|---|
| 7411 | void QTextFlow::registerFloatingItem( QTextCustomItem* item )
|
|---|
| 7412 | {
|
|---|
| 7413 | if ( item->placement() == QTextCustomItem::PlaceRight ) {
|
|---|
| 7414 | if ( !rightItems.contains( item ) )
|
|---|
| 7415 | rightItems.append( item );
|
|---|
| 7416 | } else if ( item->placement() == QTextCustomItem::PlaceLeft &&
|
|---|
| 7417 | !leftItems.contains( item ) ) {
|
|---|
| 7418 | leftItems.append( item );
|
|---|
| 7419 | }
|
|---|
| 7420 | }
|
|---|
| 7421 | #endif // QT_NO_TEXTCUSTOMITEM
|
|---|
| 7422 |
|
|---|
| 7423 | QRect QTextFlow::boundingRect() const
|
|---|
| 7424 | {
|
|---|
| 7425 | QRect br;
|
|---|
| 7426 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 7427 | QPtrListIterator<QTextCustomItem> l( leftItems );
|
|---|
| 7428 | while( l.current() ) {
|
|---|
| 7429 | br = br.unite( l.current()->geometry() );
|
|---|
| 7430 | ++l;
|
|---|
| 7431 | }
|
|---|
| 7432 | QPtrListIterator<QTextCustomItem> r( rightItems );
|
|---|
| 7433 | while( r.current() ) {
|
|---|
| 7434 | br = br.unite( r.current()->geometry() );
|
|---|
| 7435 | ++r;
|
|---|
| 7436 | }
|
|---|
| 7437 | #endif
|
|---|
| 7438 | return br;
|
|---|
| 7439 | }
|
|---|
| 7440 |
|
|---|
| 7441 |
|
|---|
| 7442 | void QTextFlow::drawFloatingItems( QPainter* p, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected )
|
|---|
| 7443 | {
|
|---|
| 7444 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 7445 | QTextCustomItem *item;
|
|---|
| 7446 | for ( item = leftItems.first(); item; item = leftItems.next() ) {
|
|---|
| 7447 | if ( item->xpos == -1 || item->ypos == -1 )
|
|---|
| 7448 | continue;
|
|---|
| 7449 | item->draw( p, item->xpos, item->ypos, cx, cy, cw, ch, cg, selected );
|
|---|
| 7450 | }
|
|---|
| 7451 |
|
|---|
| 7452 | for ( item = rightItems.first(); item; item = rightItems.next() ) {
|
|---|
| 7453 | if ( item->xpos == -1 || item->ypos == -1 )
|
|---|
| 7454 | continue;
|
|---|
| 7455 | item->draw( p, item->xpos, item->ypos, cx, cy, cw, ch, cg, selected );
|
|---|
| 7456 | }
|
|---|
| 7457 | #endif
|
|---|
| 7458 | }
|
|---|
| 7459 |
|
|---|
| 7460 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|---|
| 7461 |
|
|---|
| 7462 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 7463 | void QTextCustomItem::pageBreak( int /*y*/ , QTextFlow* /*flow*/ )
|
|---|
| 7464 | {
|
|---|
| 7465 | }
|
|---|
| 7466 | #endif
|
|---|
| 7467 |
|
|---|
| 7468 | #ifndef QT_NO_TEXTCUSTOMITEM
|
|---|
| 7469 | QTextTable::QTextTable( QTextDocument *p, const QMap<QString, QString> & attr )
|
|---|
| 7470 | : QTextCustomItem( p )
|
|---|
| 7471 | {
|
|---|
| 7472 | cells.setAutoDelete( FALSE );
|
|---|
| 7473 | cellspacing = 2;
|
|---|
| 7474 | if ( attr.contains("cellspacing") )
|
|---|
| 7475 | cellspacing = attr["cellspacing"].toInt();
|
|---|
| 7476 | cellpadding = 1;
|
|---|
| 7477 | if ( attr.contains("cellpadding") )
|
|---|
| 7478 | cellpadding = attr["cellpadding"].toInt();
|
|---|
| 7479 | border = innerborder = 0;
|
|---|
| 7480 | if ( attr.contains("border" ) ) {
|
|---|
| 7481 | QString s( attr["border"] );
|
|---|
| 7482 | if ( s == "TRUE" )
|
|---|
| 7483 | border = 1;
|
|---|
| 7484 | else
|
|---|
| 7485 | border = attr["border"].toInt();
|
|---|
| 7486 | }
|
|---|
| 7487 | us_b = border;
|
|---|
| 7488 |
|
|---|
| 7489 | innerborder = us_ib = border ? 1 : 0;
|
|---|
| 7490 |
|
|---|
| 7491 | if ( border )
|
|---|
| 7492 | cellspacing += 2;
|
|---|
| 7493 |
|
|---|
| 7494 | us_ib = innerborder;
|
|---|
| 7495 | us_cs = cellspacing;
|
|---|
| 7496 | us_cp = cellpadding;
|
|---|
| 7497 | outerborder = cellspacing + border;
|
|---|
| 7498 | us_ob = outerborder;
|
|---|
| 7499 | layout = new QGridLayout( 1, 1, cellspacing );
|
|---|
| 7500 |
|
|---|
| 7501 | fixwidth = 0;
|
|---|
| 7502 | stretch = 0;
|
|---|
| 7503 | if ( attr.contains("width") ) {
|
|---|
| 7504 | bool b;
|
|---|
| 7505 | QString s( attr["width"] );
|
|---|
| 7506 | int w = s.toInt( &b );
|
|---|
| 7507 | if ( b ) {
|
|---|
| 7508 | fixwidth = w;
|
|---|
| 7509 | } else {
|
|---|
| 7510 | s = s.stripWhiteSpace();
|
|---|
| 7511 | if ( s.length() > 1 && s[ (int)s.length()-1 ] == '%' )
|
|---|
| 7512 | stretch = s.left( s.length()-1).toInt();
|
|---|
| 7513 | }
|
|---|
| 7514 | }
|
|---|
| 7515 |
|
|---|
| 7516 | place = PlaceInline;
|
|---|
| 7517 | if ( attr["align"] == "left" )
|
|---|
| 7518 | place = PlaceLeft;
|
|---|
| 7519 | else if ( attr["align"] == "right" )
|
|---|
| 7520 | place = PlaceRight;
|
|---|
| 7521 | cachewidth = 0;
|
|---|
| 7522 | attributes = attr;
|
|---|
| 7523 | pageBreakFor = -1;
|
|---|
| 7524 | }
|
|---|
| 7525 |
|
|---|
| 7526 | QTextTable::~QTextTable()
|
|---|
| 7527 | {
|
|---|
| 7528 | delete layout;
|
|---|
| 7529 | }
|
|---|
| 7530 |
|
|---|
| 7531 | QString QTextTable::richText() const
|
|---|
| 7532 | {
|
|---|
| 7533 | QString s;
|
|---|
| 7534 | s = "<table ";
|
|---|
| 7535 | QMap<QString, QString>::ConstIterator it = attributes.begin();
|
|---|
| 7536 | for ( ; it != attributes.end(); ++it )
|
|---|
| 7537 | s += it.key() + "=" + *it + " ";
|
|---|
| 7538 | s += ">\n";
|
|---|
| 7539 |
|
|---|
| 7540 | int lastRow = -1;
|
|---|
| 7541 | bool needEnd = FALSE;
|
|---|
| 7542 | QPtrListIterator<QTextTableCell> it2( cells );
|
|---|
| 7543 | while ( it2.current() ) {
|
|---|
| 7544 | QTextTableCell *cell = it2.current();
|
|---|
| 7545 | ++it2;
|
|---|
| 7546 | if ( lastRow != cell->row() ) {
|
|---|
| 7547 | if ( lastRow != -1 )
|
|---|
| 7548 | s += "</tr>\n";
|
|---|
| 7549 | s += "<tr>";
|
|---|
| 7550 | lastRow = cell->row();
|
|---|
| 7551 | needEnd = TRUE;
|
|---|
| 7552 | }
|
|---|
| 7553 | s += "<td";
|
|---|
| 7554 | it = cell->attributes.begin();
|
|---|
| 7555 | for ( ; it != cell->attributes.end(); ++it )
|
|---|
| 7556 | s += " " + it.key() + "=" + *it;
|
|---|
| 7557 | s += ">";
|
|---|
| 7558 | s += cell->richText()->richText();
|
|---|
| 7559 | s += "</td>";
|
|---|
| 7560 | }
|
|---|
| 7561 | if ( needEnd )
|
|---|
| 7562 | s += "</tr>\n";
|
|---|
| 7563 | s += "</table>\n";
|
|---|
| 7564 | return s;
|
|---|
| 7565 | }
|
|---|
| 7566 |
|
|---|
| 7567 | void QTextTable::adjustToPainter( QPainter* p )
|
|---|
| 7568 | {
|
|---|
| 7569 | cellspacing = scale( us_cs, p );
|
|---|
| 7570 | cellpadding = scale( us_cp, p );
|
|---|
| 7571 | border = scale( us_b , p );
|
|---|
| 7572 | innerborder = scale( us_ib, p );
|
|---|
| 7573 | outerborder = scale( us_ob ,p );
|
|---|
| 7574 | width = 0;
|
|---|
| 7575 | cachewidth = 0;
|
|---|
| 7576 | for ( QTextTableCell* cell = cells.first(); cell; cell = cells.next() )
|
|---|
| 7577 | cell->adjustToPainter( p );
|
|---|
| 7578 | }
|
|---|
| 7579 |
|
|---|
| 7580 | void QTextTable::adjustCells( int y , int shift )
|
|---|
| 7581 | {
|
|---|
| 7582 | QPtrListIterator<QTextTableCell> it( cells );
|
|---|
| 7583 | QTextTableCell* cell;
|
|---|
| 7584 | bool enlarge = FALSE;
|
|---|
| 7585 | while ( ( cell = it.current() ) ) {
|
|---|
| 7586 | ++it;
|
|---|
| 7587 | QRect r = cell->geometry();
|
|---|
| 7588 | if ( y <= r.top() ) {
|
|---|
| 7589 | r.moveBy(0, shift );
|
|---|
| 7590 | cell->setGeometry( r );
|
|---|
| 7591 | enlarge = TRUE;
|
|---|
| 7592 | } else if ( y <= r.bottom() ) {
|
|---|
| 7593 | r.rBottom() += shift;
|
|---|
| 7594 | cell->setGeometry( r );
|
|---|
| 7595 | enlarge = TRUE;
|
|---|
| 7596 | }
|
|---|
| 7597 | }
|
|---|
| 7598 | if ( enlarge )
|
|---|
| 7599 | height += shift;
|
|---|
| 7600 | }
|
|---|
| 7601 |
|
|---|
| 7602 | void QTextTable::pageBreak( int yt, QTextFlow* flow )
|
|---|
| 7603 | {
|
|---|
| 7604 | if ( flow->pageSize() <= 0 )
|
|---|
| 7605 | return;
|
|---|
| 7606 | if ( layout && pageBreakFor > 0 && pageBreakFor != yt ) {
|
|---|
| 7607 | layout->invalidate();
|
|---|
| 7608 | int h = layout->heightForWidth( width-2*outerborder );
|
|---|
| 7609 | layout->setGeometry( QRect(0, 0, width-2*outerborder, h) );
|
|---|
| 7610 | height = layout->geometry().height()+2*outerborder;
|
|---|
| 7611 | }
|
|---|
| 7612 | pageBreakFor = yt;
|
|---|
| 7613 | QPtrListIterator<QTextTableCell> it( cells );
|
|---|
| 7614 | QTextTableCell* cell;
|
|---|
| 7615 | while ( ( cell = it.current() ) ) {
|
|---|
| 7616 | ++it;
|
|---|
| 7617 | int y = yt + outerborder + cell->geometry().y();
|
|---|
| 7618 | int shift = flow->adjustFlow( y - cellspacing, width, cell->richText()->height() + 2*cellspacing );
|
|---|
| 7619 | adjustCells( y - outerborder - yt, shift );
|
|---|
| 7620 | }
|
|---|
| 7621 | }
|
|---|
| 7622 |
|
|---|
| 7623 |
|
|---|
| 7624 | void QTextTable::draw(QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected )
|
|---|
| 7625 | {
|
|---|
| 7626 | if ( placement() != PlaceInline ) {
|
|---|
| 7627 | x = xpos;
|
|---|
| 7628 | y = ypos;
|
|---|
| 7629 | }
|
|---|
| 7630 |
|
|---|
| 7631 | for (QTextTableCell* cell = cells.first(); cell; cell = cells.next() ) {
|
|---|
| 7632 | if ( cx < 0 && cy < 0 ||
|
|---|
| 7633 | QRect( cx, cy, cw, ch ).intersects( QRect( x + outerborder + cell->geometry().x(),
|
|---|
| 7634 | y + outerborder + cell->geometry().y(),
|
|---|
| 7635 | cell->geometry().width(), cell->geometry().height() ) ) ) {
|
|---|
| 7636 | cell->draw( p, x+outerborder, y+outerborder, cx, cy, cw, ch, cg, selected );
|
|---|
| 7637 | if ( border ) {
|
|---|
| 7638 | QRect r( x+outerborder+cell->geometry().x() - innerborder,
|
|---|
| 7639 | y+outerborder+cell->geometry().y() - innerborder,
|
|---|
| 7640 | cell->geometry().width() + 2 * innerborder,
|
|---|
| 7641 | cell->geometry().height() + 2 * innerborder );
|
|---|
| 7642 | if ( is_printer( p ) ) {
|
|---|
| 7643 | QPen oldPen = p->pen();
|
|---|
| 7644 | QRect r2 = r;
|
|---|
| 7645 | r2.addCoords( innerborder/2, innerborder/2, -innerborder/2, -innerborder/2 );
|
|---|
| 7646 | p->setPen( QPen( cg.text(), innerborder ) );
|
|---|
| 7647 | p->drawRect( r2 );
|
|---|
| 7648 | p->setPen( oldPen );
|
|---|
| 7649 | } else {
|
|---|
| 7650 | int s = QMAX( cellspacing-2*innerborder, 0);
|
|---|
| 7651 | if ( s ) {
|
|---|
| 7652 | p->fillRect( r.left()-s, r.top(), s+1, r.height(), cg.button() );
|
|---|
| 7653 | p->fillRect( r.right(), r.top(), s+1, r.height(), cg.button() );
|
|---|
| 7654 | p->fillRect( r.left()-s, r.top()-s, r.width()+2*s, s, cg.button() );
|
|---|
| 7655 | p->fillRect( r.left()-s, r.bottom(), r.width()+2*s, s, cg.button() );
|
|---|
| 7656 | }
|
|---|
| 7657 | qDrawShadePanel( p, r, cg, TRUE, innerborder );
|
|---|
| 7658 | }
|
|---|
| 7659 | }
|
|---|
| 7660 | }
|
|---|
| 7661 | }
|
|---|
| 7662 | if ( border ) {
|
|---|
| 7663 | QRect r ( x, y, width, height );
|
|---|
| 7664 | if ( is_printer( p ) ) {
|
|---|
| 7665 | QRect r2 = r;
|
|---|
| 7666 | r2.addCoords( border/2, border/2, -border/2, -border/2 );
|
|---|
| 7667 | QPen oldPen = p->pen();
|
|---|
| 7668 | p->setPen( QPen( cg.text(), border ) );
|
|---|
| 7669 | p->drawRect( r2 );
|
|---|
| 7670 | p->setPen( oldPen );
|
|---|
| 7671 | } else {
|
|---|
| 7672 | int s = border+QMAX( cellspacing-2*innerborder, 0);
|
|---|
| 7673 | if ( s ) {
|
|---|
| 7674 | p->fillRect( r.left(), r.top(), s, r.height(), cg.button() );
|
|---|
| 7675 | p->fillRect( r.right()-s, r.top(), s, r.height(), cg.button() );
|
|---|
| 7676 | p->fillRect( r.left(), r.top(), r.width(), s, cg.button() );
|
|---|
| 7677 | p->fillRect( r.left(), r.bottom()-s, r.width(), s, cg.button() );
|
|---|
| 7678 | }
|
|---|
| 7679 | qDrawShadePanel( p, r, cg, FALSE, border );
|
|---|
| 7680 | }
|
|---|
| 7681 | }
|
|---|
| 7682 |
|
|---|
| 7683 | }
|
|---|
| 7684 |
|
|---|
| 7685 | int QTextTable::minimumWidth() const
|
|---|
| 7686 | {
|
|---|
| 7687 | return fixwidth ? fixwidth : ((layout ? layout->minimumSize().width() : 0) + 2 * outerborder);
|
|---|
| 7688 | }
|
|---|
| 7689 |
|
|---|
| 7690 | void QTextTable::resize( int nwidth )
|
|---|
| 7691 | {
|
|---|
| 7692 | if ( fixwidth && cachewidth != 0 )
|
|---|
| 7693 | return;
|
|---|
| 7694 | if ( nwidth == cachewidth )
|
|---|
| 7695 | return;
|
|---|
| 7696 |
|
|---|
| 7697 |
|
|---|
| 7698 | cachewidth = nwidth;
|
|---|
| 7699 | int w = nwidth;
|
|---|
| 7700 |
|
|---|
| 7701 | format( w );
|
|---|
| 7702 |
|
|---|
| 7703 | if ( stretch )
|
|---|
| 7704 | nwidth = nwidth * stretch / 100;
|
|---|
| 7705 |
|
|---|
| 7706 | width = nwidth;
|
|---|
| 7707 | layout->invalidate();
|
|---|
| 7708 | int shw = layout->sizeHint().width() + 2*outerborder;
|
|---|
| 7709 | int mw = layout->minimumSize().width() + 2*outerborder;
|
|---|
| 7710 | if ( stretch )
|
|---|
| 7711 | width = QMAX( mw, nwidth );
|
|---|
| 7712 | else
|
|---|
| 7713 | width = QMAX( mw, QMIN( nwidth, shw ) );
|
|---|
| 7714 |
|
|---|
| 7715 | if ( fixwidth )
|
|---|
| 7716 | width = fixwidth;
|
|---|
| 7717 |
|
|---|
| 7718 | layout->invalidate();
|
|---|
| 7719 | mw = layout->minimumSize().width() + 2*outerborder;
|
|---|
| 7720 | width = QMAX( width, mw );
|
|---|
| 7721 |
|
|---|
| 7722 | int h = layout->heightForWidth( width-2*outerborder );
|
|---|
| 7723 | layout->setGeometry( QRect(0, 0, width-2*outerborder, h) );
|
|---|
| 7724 | height = layout->geometry().height()+2*outerborder;
|
|---|
| 7725 | }
|
|---|
| 7726 |
|
|---|
| 7727 | void QTextTable::format( int w )
|
|---|
| 7728 | {
|
|---|
| 7729 | for ( int i = 0; i < (int)cells.count(); ++i ) {
|
|---|
| 7730 | QTextTableCell *cell = cells.at( i );
|
|---|
| 7731 | QRect r = cell->geometry();
|
|---|
| 7732 | r.setWidth( w - 2*outerborder );
|
|---|
| 7733 | cell->setGeometry( r );
|
|---|
| 7734 | }
|
|---|
| 7735 | }
|
|---|
| 7736 |
|
|---|
| 7737 | void QTextTable::addCell( QTextTableCell* cell )
|
|---|
| 7738 | {
|
|---|
| 7739 | cells.append( cell );
|
|---|
| 7740 | layout->addMultiCell( cell, cell->row(), cell->row() + cell->rowspan()-1,
|
|---|
| 7741 | cell->column(), cell->column() + cell->colspan()-1 );
|
|---|
| 7742 | }
|
|---|
| 7743 |
|
|---|
| 7744 | bool QTextTable::enter( QTextCursor *c, QTextDocument *&doc, QTextParagraph *¶g, int &idx, int &ox, int &oy, bool atEnd )
|
|---|
| 7745 | {
|
|---|
| 7746 | currCell.remove( c );
|
|---|
| 7747 | if ( !atEnd )
|
|---|
| 7748 | return next( c, doc, parag, idx, ox, oy );
|
|---|
| 7749 | currCell.insert( c, cells.count() );
|
|---|
| 7750 | return prev( c, doc, parag, idx, ox, oy );
|
|---|
| 7751 | }
|
|---|
| 7752 |
|
|---|
| 7753 | bool QTextTable::enterAt( QTextCursor *c, QTextDocument *&doc, QTextParagraph *¶g, int &idx, int &ox, int &oy, const QPoint &pos )
|
|---|
| 7754 | {
|
|---|
| 7755 | currCell.remove( c );
|
|---|
| 7756 | int lastCell = -1;
|
|---|
| 7757 | int lastY = -1;
|
|---|
| 7758 | int i;
|
|---|
| 7759 | for ( i = 0; i < (int)cells.count(); ++i ) {
|
|---|
| 7760 | QTextTableCell *cell = cells.at( i );
|
|---|
| 7761 | if ( !cell )
|
|---|
| 7762 | continue;
|
|---|
| 7763 | QRect r( cell->geometry().x(),
|
|---|
| 7764 | cell->geometry().y(),
|
|---|
| 7765 | cell->geometry().width() + 2 * innerborder + 2 * outerborder,
|
|---|
| 7766 | cell->geometry().height() + 2 * innerborder + 2 * outerborder );
|
|---|
| 7767 |
|
|---|
| 7768 | if ( r.left() <= pos.x() && r.right() >= pos.x() ) {
|
|---|
| 7769 | if ( cell->geometry().y() > lastY ) {
|
|---|
| 7770 | lastCell = i;
|
|---|
| 7771 | lastY = cell->geometry().y();
|
|---|
| 7772 | }
|
|---|
| 7773 | if ( r.top() <= pos.y() && r.bottom() >= pos.y() ) {
|
|---|
| 7774 | currCell.insert( c, i );
|
|---|
| 7775 | break;
|
|---|
| 7776 | }
|
|---|
| 7777 | }
|
|---|
| 7778 | }
|
|---|
| 7779 | if ( i == (int) cells.count() )
|
|---|
| 7780 | return FALSE; // no cell found
|
|---|
| 7781 |
|
|---|
| 7782 | if ( currCell.find( c ) == currCell.end() ) {
|
|---|
| 7783 | if ( lastY != -1 )
|
|---|
| 7784 | currCell.insert( c, lastCell );
|
|---|
| 7785 | else
|
|---|
| 7786 | return FALSE;
|
|---|
| 7787 | }
|
|---|
| 7788 |
|
|---|
| 7789 | QTextTableCell *cell = cells.at( *currCell.find( c ) );
|
|---|
| 7790 | if ( !cell )
|
|---|
| 7791 | return FALSE;
|
|---|
| 7792 | doc = cell->richText();
|
|---|
| 7793 | parag = doc->firstParagraph();
|
|---|
| 7794 | idx = 0;
|
|---|
| 7795 | ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
|
|---|
| 7796 | oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
|
|---|
| 7797 | return TRUE;
|
|---|
| 7798 | }
|
|---|
| 7799 |
|
|---|
| 7800 | bool QTextTable::next( QTextCursor *c, QTextDocument *&doc, QTextParagraph *¶g, int &idx, int &ox, int &oy )
|
|---|
| 7801 | {
|
|---|
| 7802 | int cc = -1;
|
|---|
| 7803 | if ( currCell.find( c ) != currCell.end() )
|
|---|
| 7804 | cc = *currCell.find( c );
|
|---|
| 7805 | if ( cc > (int)cells.count() - 1 || cc < 0 )
|
|---|
| 7806 | cc = -1;
|
|---|
| 7807 | currCell.remove( c );
|
|---|
| 7808 | currCell.insert( c, ++cc );
|
|---|
| 7809 | if ( cc >= (int)cells.count() ) {
|
|---|
| 7810 | currCell.insert( c, 0 );
|
|---|
| 7811 | QTextCustomItem::next( c, doc, parag, idx, ox, oy );
|
|---|
| 7812 | QTextTableCell *cell = cells.first();
|
|---|
| 7813 | if ( !cell )
|
|---|
| 7814 | return FALSE;
|
|---|
| 7815 | doc = cell->richText();
|
|---|
| 7816 | idx = -1;
|
|---|
| 7817 | return TRUE;
|
|---|
| 7818 | }
|
|---|
| 7819 |
|
|---|
| 7820 | if ( currCell.find( c ) == currCell.end() )
|
|---|
| 7821 | return FALSE;
|
|---|
| 7822 | QTextTableCell *cell = cells.at( *currCell.find( c ) );
|
|---|
| 7823 | if ( !cell )
|
|---|
| 7824 | return FALSE;
|
|---|
| 7825 | doc = cell->richText();
|
|---|
| 7826 | parag = doc->firstParagraph();
|
|---|
| 7827 | idx = 0;
|
|---|
| 7828 | ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
|
|---|
| 7829 | oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
|
|---|
| 7830 | return TRUE;
|
|---|
| 7831 | }
|
|---|
| 7832 |
|
|---|
| 7833 | bool QTextTable::prev( QTextCursor *c, QTextDocument *&doc, QTextParagraph *¶g, int &idx, int &ox, int &oy )
|
|---|
| 7834 | {
|
|---|
| 7835 | int cc = -1;
|
|---|
| 7836 | if ( currCell.find( c ) != currCell.end() )
|
|---|
| 7837 | cc = *currCell.find( c );
|
|---|
| 7838 | if ( cc > (int)cells.count() - 1 || cc < 0 )
|
|---|
| 7839 | cc = cells.count();
|
|---|
| 7840 | currCell.remove( c );
|
|---|
| 7841 | currCell.insert( c, --cc );
|
|---|
| 7842 | if ( cc < 0 ) {
|
|---|
| 7843 | currCell.insert( c, 0 );
|
|---|
| 7844 | QTextCustomItem::prev( c, doc, parag, idx, ox, oy );
|
|---|
| 7845 | QTextTableCell *cell = cells.first();
|
|---|
| 7846 | if ( !cell )
|
|---|
| 7847 | return FALSE;
|
|---|
| 7848 | doc = cell->richText();
|
|---|
| 7849 | idx = -1;
|
|---|
| 7850 | return TRUE;
|
|---|
| 7851 | }
|
|---|
| 7852 |
|
|---|
| 7853 | if ( currCell.find( c ) == currCell.end() )
|
|---|
| 7854 | return FALSE;
|
|---|
| 7855 | QTextTableCell *cell = cells.at( *currCell.find( c ) );
|
|---|
| 7856 | if ( !cell )
|
|---|
| 7857 | return FALSE;
|
|---|
| 7858 | doc = cell->richText();
|
|---|
| 7859 | parag = doc->lastParagraph();
|
|---|
| 7860 | idx = parag->length() - 1;
|
|---|
| 7861 | ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
|
|---|
| 7862 | oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
|
|---|
| 7863 | return TRUE;
|
|---|
| 7864 | }
|
|---|
| 7865 |
|
|---|
| 7866 | bool QTextTable::down( QTextCursor *c, QTextDocument *&doc, QTextParagraph *¶g, int &idx, int &ox, int &oy )
|
|---|
| 7867 | {
|
|---|
| 7868 | if ( currCell.find( c ) == currCell.end() )
|
|---|
| 7869 | return FALSE;
|
|---|
| 7870 | QTextTableCell *cell = cells.at( *currCell.find( c ) );
|
|---|
| 7871 | if ( cell->row_ == layout->numRows() - 1 ) {
|
|---|
| 7872 | currCell.insert( c, 0 );
|
|---|
| 7873 | QTextCustomItem::down( c, doc, parag, idx, ox, oy );
|
|---|
| 7874 | QTextTableCell *cell = cells.first();
|
|---|
| 7875 | if ( !cell )
|
|---|
| 7876 | return FALSE;
|
|---|
| 7877 | doc = cell->richText();
|
|---|
| 7878 | idx = -1;
|
|---|
| 7879 | return TRUE;
|
|---|
| 7880 | }
|
|---|
| 7881 |
|
|---|
| 7882 | int oldRow = cell->row_;
|
|---|
| 7883 | int oldCol = cell->col_;
|
|---|
| 7884 | if ( currCell.find( c ) == currCell.end() )
|
|---|
| 7885 | return FALSE;
|
|---|
| 7886 | int cc = *currCell.find( c );
|
|---|
| 7887 | for ( int i = cc; i < (int)cells.count(); ++i ) {
|
|---|
| 7888 | cell = cells.at( i );
|
|---|
| 7889 | if ( cell->row_ > oldRow && cell->col_ == oldCol ) {
|
|---|
| 7890 | currCell.insert( c, i );
|
|---|
| 7891 | break;
|
|---|
| 7892 | }
|
|---|
| 7893 | }
|
|---|
| 7894 | doc = cell->richText();
|
|---|
| 7895 | if ( !cell )
|
|---|
| 7896 | return FALSE;
|
|---|
| 7897 | parag = doc->firstParagraph();
|
|---|
| 7898 | idx = 0;
|
|---|
| 7899 | ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
|
|---|
| 7900 | oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
|
|---|
| 7901 | return TRUE;
|
|---|
| 7902 | }
|
|---|
| 7903 |
|
|---|
| 7904 | bool QTextTable::up( QTextCursor *c, QTextDocument *&doc, QTextParagraph *¶g, int &idx, int &ox, int &oy )
|
|---|
| 7905 | {
|
|---|
| 7906 | if ( currCell.find( c ) == currCell.end() )
|
|---|
| 7907 | return FALSE;
|
|---|
| 7908 | QTextTableCell *cell = cells.at( *currCell.find( c ) );
|
|---|
| 7909 | if ( cell->row_ == 0 ) {
|
|---|
| 7910 | currCell.insert( c, 0 );
|
|---|
| 7911 | QTextCustomItem::up( c, doc, parag, idx, ox, oy );
|
|---|
| 7912 | QTextTableCell *cell = cells.first();
|
|---|
| 7913 | if ( !cell )
|
|---|
| 7914 | return FALSE;
|
|---|
| 7915 | doc = cell->richText();
|
|---|
| 7916 | idx = -1;
|
|---|
| 7917 | return TRUE;
|
|---|
| 7918 | }
|
|---|
| 7919 |
|
|---|
| 7920 | int oldRow = cell->row_;
|
|---|
| 7921 | int oldCol = cell->col_;
|
|---|
| 7922 | if ( currCell.find( c ) == currCell.end() )
|
|---|
| 7923 | return FALSE;
|
|---|
| 7924 | int cc = *currCell.find( c );
|
|---|
| 7925 | for ( int i = cc; i >= 0; --i ) {
|
|---|
| 7926 | cell = cells.at( i );
|
|---|
| 7927 | if ( cell->row_ < oldRow && cell->col_ == oldCol ) {
|
|---|
| 7928 | currCell.insert( c, i );
|
|---|
| 7929 | break;
|
|---|
| 7930 | }
|
|---|
| 7931 | }
|
|---|
| 7932 | doc = cell->richText();
|
|---|
| 7933 | if ( !cell )
|
|---|
| 7934 | return FALSE;
|
|---|
| 7935 | parag = doc->lastParagraph();
|
|---|
| 7936 | idx = parag->length() - 1;
|
|---|
| 7937 | ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
|
|---|
| 7938 | oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
|
|---|
| 7939 | return TRUE;
|
|---|
| 7940 | }
|
|---|
| 7941 |
|
|---|
| 7942 | QTextTableCell::QTextTableCell( QTextTable* table,
|
|---|
| 7943 | int row, int column,
|
|---|
| 7944 | const QMap<QString, QString> &attr,
|
|---|
| 7945 | const QStyleSheetItem* /*style*/, // ### use them
|
|---|
| 7946 | const QTextFormat& fmt, const QString& context,
|
|---|
| 7947 | QMimeSourceFactory &factory, QStyleSheet *sheet,
|
|---|
| 7948 | const QString& doc)
|
|---|
| 7949 | {
|
|---|
| 7950 | cached_width = -1;
|
|---|
| 7951 | cached_sizehint = -1;
|
|---|
| 7952 |
|
|---|
| 7953 | maxw = QWIDGETSIZE_MAX;
|
|---|
| 7954 | minw = 0;
|
|---|
| 7955 |
|
|---|
| 7956 | parent = table;
|
|---|
| 7957 | row_ = row;
|
|---|
| 7958 | col_ = column;
|
|---|
| 7959 | stretch_ = 0;
|
|---|
| 7960 | richtext = new QTextDocument( table->parent );
|
|---|
| 7961 | richtext->formatCollection()->setPaintDevice( table->parent->formatCollection()->paintDevice() );
|
|---|
| 7962 | richtext->bodyText = fmt.color();
|
|---|
| 7963 | richtext->setTableCell( this );
|
|---|
| 7964 | QString a = *attr.find( "align" );
|
|---|
| 7965 | if ( !a.isEmpty() ) {
|
|---|
| 7966 | a = a.lower();
|
|---|
| 7967 | if ( a == "left" )
|
|---|
| 7968 | richtext->setAlignment( Qt::AlignLeft );
|
|---|
| 7969 | else if ( a == "center" )
|
|---|
| 7970 | richtext->setAlignment( Qt::AlignHCenter );
|
|---|
| 7971 | else if ( a == "right" )
|
|---|
| 7972 | richtext->setAlignment( Qt::AlignRight );
|
|---|
| 7973 | }
|
|---|
| 7974 | align = 0;
|
|---|
| 7975 | QString va = *attr.find( "valign" );
|
|---|
| 7976 | if ( !va.isEmpty() ) {
|
|---|
| 7977 | va = va.lower();
|
|---|
| 7978 | if ( va == "center" )
|
|---|
| 7979 | align |= Qt::AlignVCenter;
|
|---|
| 7980 | else if ( va == "bottom" )
|
|---|
| 7981 | align |= Qt::AlignBottom;
|
|---|
| 7982 | }
|
|---|
| 7983 | richtext->setFormatter( table->parent->formatter() );
|
|---|
| 7984 | richtext->setUseFormatCollection( table->parent->useFormatCollection() );
|
|---|
| 7985 | richtext->setMimeSourceFactory( &factory );
|
|---|
| 7986 | richtext->setStyleSheet( sheet );
|
|---|
| 7987 | richtext->setDefaultFormat( fmt.font(), fmt.color() );
|
|---|
| 7988 | richtext->setRichText( doc, context );
|
|---|
| 7989 | rowspan_ = 1;
|
|---|
| 7990 | colspan_ = 1;
|
|---|
| 7991 | if ( attr.contains("colspan") )
|
|---|
| 7992 | colspan_ = attr["colspan"].toInt();
|
|---|
| 7993 | if ( attr.contains("rowspan") )
|
|---|
| 7994 | rowspan_ = attr["rowspan"].toInt();
|
|---|
| 7995 |
|
|---|
| 7996 | background = 0;
|
|---|
| 7997 | if ( attr.contains("bgcolor") ) {
|
|---|
| 7998 | background = new QBrush(QColor( attr["bgcolor"] ));
|
|---|
| 7999 | }
|
|---|
| 8000 |
|
|---|
| 8001 |
|
|---|
| 8002 | hasFixedWidth = FALSE;
|
|---|
| 8003 | if ( attr.contains("width") ) {
|
|---|
| 8004 | bool b;
|
|---|
| 8005 | QString s( attr["width"] );
|
|---|
| 8006 | int w = s.toInt( &b );
|
|---|
| 8007 | if ( b ) {
|
|---|
| 8008 | maxw = w;
|
|---|
| 8009 | minw = maxw;
|
|---|
| 8010 | hasFixedWidth = TRUE;
|
|---|
| 8011 | } else {
|
|---|
| 8012 | s = s.stripWhiteSpace();
|
|---|
| 8013 | if ( s.length() > 1 && s[ (int)s.length()-1 ] == '%' )
|
|---|
| 8014 | stretch_ = s.left( s.length()-1).toInt();
|
|---|
| 8015 | }
|
|---|
| 8016 | }
|
|---|
| 8017 |
|
|---|
| 8018 | attributes = attr;
|
|---|
| 8019 |
|
|---|
| 8020 | parent->addCell( this );
|
|---|
| 8021 | }
|
|---|
| 8022 |
|
|---|
| 8023 | QTextTableCell::~QTextTableCell()
|
|---|
| 8024 | {
|
|---|
| 8025 | delete background;
|
|---|
| 8026 | background = 0;
|
|---|
| 8027 | delete richtext;
|
|---|
| 8028 | richtext = 0;
|
|---|
| 8029 | }
|
|---|
| 8030 |
|
|---|
| 8031 | QSize QTextTableCell::sizeHint() const
|
|---|
| 8032 | {
|
|---|
| 8033 | int extra = 2 * ( parent->innerborder + parent->cellpadding + border_tolerance);
|
|---|
| 8034 | int used = richtext->widthUsed() + extra;
|
|---|
| 8035 |
|
|---|
| 8036 | if (stretch_ ) {
|
|---|
| 8037 | int w = parent->width * stretch_ / 100 - 2*parent->cellspacing - 2*parent->cellpadding;
|
|---|
| 8038 | return QSize( QMIN( w, maxw ), 0 ).expandedTo( minimumSize() );
|
|---|
| 8039 | }
|
|---|
| 8040 |
|
|---|
| 8041 | return QSize( used, 0 ).expandedTo( minimumSize() );
|
|---|
| 8042 | }
|
|---|
| 8043 |
|
|---|
| 8044 | QSize QTextTableCell::minimumSize() const
|
|---|
| 8045 | {
|
|---|
| 8046 | int extra = 2 * ( parent->innerborder + parent->cellpadding + border_tolerance);
|
|---|
| 8047 | return QSize( QMAX( richtext->minimumWidth() + extra, minw), 0 );
|
|---|
| 8048 | }
|
|---|
| 8049 |
|
|---|
| 8050 | QSize QTextTableCell::maximumSize() const
|
|---|
| 8051 | {
|
|---|
| 8052 | return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
|
|---|
| 8053 | }
|
|---|
| 8054 |
|
|---|
| 8055 | QSizePolicy::ExpandData QTextTableCell::expanding() const
|
|---|
| 8056 | {
|
|---|
| 8057 | return QSizePolicy::BothDirections;
|
|---|
| 8058 | }
|
|---|
| 8059 |
|
|---|
| 8060 | bool QTextTableCell::isEmpty() const
|
|---|
| 8061 | {
|
|---|
| 8062 | return FALSE;
|
|---|
| 8063 | }
|
|---|
| 8064 | void QTextTableCell::setGeometry( const QRect& r )
|
|---|
| 8065 | {
|
|---|
| 8066 | int extra = 2 * ( parent->innerborder + parent->cellpadding );
|
|---|
| 8067 | if ( r.width() != cached_width )
|
|---|
| 8068 | richtext->doLayout( QTextFormat::painter(), r.width() - extra );
|
|---|
| 8069 | cached_width = r.width();
|
|---|
| 8070 | geom = r;
|
|---|
| 8071 | }
|
|---|
| 8072 |
|
|---|
| 8073 | QRect QTextTableCell::geometry() const
|
|---|
| 8074 | {
|
|---|
| 8075 | return geom;
|
|---|
| 8076 | }
|
|---|
| 8077 |
|
|---|
| 8078 | bool QTextTableCell::hasHeightForWidth() const
|
|---|
| 8079 | {
|
|---|
| 8080 | return TRUE;
|
|---|
| 8081 | }
|
|---|
| 8082 |
|
|---|
| 8083 | int QTextTableCell::heightForWidth( int w ) const
|
|---|
| 8084 | {
|
|---|
| 8085 | int extra = 2 * ( parent->innerborder + parent->cellpadding );
|
|---|
| 8086 | w = QMAX( minw, w );
|
|---|
| 8087 |
|
|---|
| 8088 | if ( cached_width != w ) {
|
|---|
| 8089 | QTextTableCell* that = (QTextTableCell*) this;
|
|---|
| 8090 | that->richtext->doLayout( QTextFormat::painter(), w - extra );
|
|---|
| 8091 | that->cached_width = w;
|
|---|
| 8092 | }
|
|---|
| 8093 | return richtext->height() + extra;
|
|---|
| 8094 | }
|
|---|
| 8095 |
|
|---|
| 8096 | void QTextTableCell::adjustToPainter( QPainter* p )
|
|---|
| 8097 | {
|
|---|
| 8098 | QTextParagraph *parag = richtext->firstParagraph();
|
|---|
| 8099 | while ( parag ) {
|
|---|
| 8100 | parag->adjustToPainter( p );
|
|---|
| 8101 | parag = parag->next();
|
|---|
| 8102 | }
|
|---|
| 8103 | }
|
|---|
| 8104 |
|
|---|
| 8105 | int QTextTableCell::horizontalAlignmentOffset() const
|
|---|
| 8106 | {
|
|---|
| 8107 | return parent->cellpadding;
|
|---|
| 8108 | }
|
|---|
| 8109 |
|
|---|
| 8110 | int QTextTableCell::verticalAlignmentOffset() const
|
|---|
| 8111 | {
|
|---|
| 8112 | if ( (align & Qt::AlignVCenter ) == Qt::AlignVCenter )
|
|---|
| 8113 | return ( geom.height() - richtext->height() ) / 2;
|
|---|
| 8114 | else if ( ( align & Qt::AlignBottom ) == Qt::AlignBottom )
|
|---|
| 8115 | return geom.height() - parent->cellpadding - richtext->height() ;
|
|---|
| 8116 | return parent->cellpadding;
|
|---|
| 8117 | }
|
|---|
| 8118 |
|
|---|
| 8119 | void QTextTableCell::draw( QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool )
|
|---|
| 8120 | {
|
|---|
| 8121 | if ( cached_width != geom.width() ) {
|
|---|
| 8122 | int extra = 2 * ( parent->innerborder + parent->cellpadding );
|
|---|
| 8123 | richtext->doLayout( p, geom.width() - extra );
|
|---|
| 8124 | cached_width = geom.width();
|
|---|
| 8125 | }
|
|---|
| 8126 | QColorGroup g( cg );
|
|---|
| 8127 | if ( background )
|
|---|
| 8128 | g.setBrush( QColorGroup::Base, *background );
|
|---|
| 8129 | else if ( richtext->paper() )
|
|---|
| 8130 | g.setBrush( QColorGroup::Base, *richtext->paper() );
|
|---|
| 8131 |
|
|---|
| 8132 | p->save();
|
|---|
| 8133 | p->translate( x + geom.x(), y + geom.y() );
|
|---|
| 8134 | if ( background )
|
|---|
| 8135 | p->fillRect( 0, 0, geom.width(), geom.height(), *background );
|
|---|
| 8136 | else if ( richtext->paper() )
|
|---|
| 8137 | p->fillRect( 0, 0, geom.width(), geom.height(), *richtext->paper() );
|
|---|
| 8138 |
|
|---|
| 8139 | p->translate( horizontalAlignmentOffset(), verticalAlignmentOffset() );
|
|---|
| 8140 |
|
|---|
| 8141 | QRegion r;
|
|---|
| 8142 | if ( cx >= 0 && cy >= 0 )
|
|---|
| 8143 | richtext->draw( p, cx - ( x + horizontalAlignmentOffset() + geom.x() ),
|
|---|
| 8144 | cy - ( y + geom.y() + verticalAlignmentOffset() ),
|
|---|
| 8145 | cw, ch, g, FALSE, FALSE, 0 );
|
|---|
| 8146 | else
|
|---|
| 8147 | richtext->draw( p, -1, -1, -1, -1, g, FALSE, FALSE, 0 );
|
|---|
| 8148 |
|
|---|
| 8149 | p->restore();
|
|---|
| 8150 | }
|
|---|
| 8151 | #endif
|
|---|
| 8152 |
|
|---|
| 8153 | #endif //QT_NO_RICHTEXT
|
|---|