summaryrefslogtreecommitdiff
path: root/noncore/apps/opie-write/qrichtext.cpp
authorleseb <leseb>2002-07-15 23:22:50 (UTC)
committer leseb <leseb>2002-07-15 23:22:50 (UTC)
commit72eb74051ed8f1b7696041e241ab99df3af5b08d (patch) (unidiff)
treebf9beee9469bc4384cb8178fbd6565cf161b4708 /noncore/apps/opie-write/qrichtext.cpp
parentdcea0e50a00ed9efb988ded5abf5d39de1bea393 (diff)
downloadopie-72eb74051ed8f1b7696041e241ab99df3af5b08d.zip
opie-72eb74051ed8f1b7696041e241ab99df3af5b08d.tar.gz
opie-72eb74051ed8f1b7696041e241ab99df3af5b08d.tar.bz2
Sync with Qt 3.0.5
Diffstat (limited to 'noncore/apps/opie-write/qrichtext.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/apps/opie-write/qrichtext.cpp4311
1 files changed, 2035 insertions, 2276 deletions
diff --git a/noncore/apps/opie-write/qrichtext.cpp b/noncore/apps/opie-write/qrichtext.cpp
index 7901000..3b044c3 100644
--- a/noncore/apps/opie-write/qrichtext.cpp
+++ b/noncore/apps/opie-write/qrichtext.cpp
@@ -38,20 +38,17 @@
38#include "qrichtext_p.h" 38#include "qrichtext_p.h"
39 39
40#include "qstringlist.h" 40#include "qstringlist.h"
41#include "qfont.h" 41#include "qfont.h"
42#include "qtextstream.h" 42#include "qtextstream.h"
43#include "qfile.h" 43#include "qfile.h"
44#include "qregexp.h"
45#include "qapplication.h" 44#include "qapplication.h"
46#include "qclipboard.h"
47#include "qmap.h" 45#include "qmap.h"
48#include "qfileinfo.h" 46#include "qfileinfo.h"
49#include "qstylesheet.h" 47#include "qstylesheet.h"
50#include "qmime.h" 48#include "qmime.h"
51#include "qregexp.h"
52#include "qimage.h" 49#include "qimage.h"
53#include "qdragobject.h" 50#include "qdragobject.h"
54#include "qpaintdevicemetrics.h" 51#include "qpaintdevicemetrics.h"
55#include "qpainter.h" 52#include "qpainter.h"
56#include "qdrawutil.h" 53#include "qdrawutil.h"
57#include "qcursor.h" 54#include "qcursor.h"
@@ -61,31 +58,25 @@
61#include "qcleanuphandler.h" 58#include "qcleanuphandler.h"
62 59
63#include <stdlib.h> 60#include <stdlib.h>
64 61
65using namespace Qt3; 62using namespace Qt3;
66 63
67//#define PARSER_DEBUG 64static QTextCursor* richTextExportStart = 0;
68//#define DEBUG_COLLECTION// ---> also in qrichtext_p.h 65static QTextCursor* richTextExportEnd = 0;
69//#define DEBUG_TABLE_RENDERING
70 66
71static QTextFormatCollection *qFormatCollection = 0; 67static QTextFormatCollection *qFormatCollection = 0;
72 68
73const int QStyleSheetItem_WhiteSpaceNoCompression = 3; // ### belongs in QStyleSheetItem, fix 3.1
74const int QStyleSheetItem_WhiteSpaceNormalWithNewlines = 4; // ### belongs in QStyleSheetItem, fix 3.1
75
76const int border_tolerance = 2; 69const int border_tolerance = 2;
77 70
78#if defined(PARSER_DEBUG)
79static QString debug_indent;
80#endif
81
82#ifdef Q_WS_WIN 71#ifdef Q_WS_WIN
83#include "qt_windows.h" 72#include "qt_windows.h"
84#endif 73#endif
85 74
75#define QChar_linesep QChar(0x2028U)
76
86static inline bool is_printer( QPainter *p ) 77static inline bool is_printer( QPainter *p )
87{ 78{
88 if ( !p || !p->device() ) 79 if ( !p || !p->device() )
89 return FALSE; 80 return FALSE;
90 return p->device()->devType() == QInternal::Printer; 81 return p->device()->devType() == QInternal::Printer;
91} 82}
@@ -174,24 +165,22 @@ bool QTextCommandHistory::isRedoAvailable()
174 return current > -1 && current < (int)history.count() - 1 || current == -1 && history.count() > 0; 165 return current > -1 && current < (int)history.count() - 1 || current == -1 && history.count() > 0;
175} 166}
176 167
177// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 168// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
178 169
179QTextDeleteCommand::QTextDeleteCommand( QTextDocument *d, int i, int idx, const QMemArray<QTextStringChar> &str, 170QTextDeleteCommand::QTextDeleteCommand( QTextDocument *d, int i, int idx, const QMemArray<QTextStringChar> &str,
180 const QValueList< QPtrVector<QStyleSheetItem> > &os, 171 const QByteArray& oldStyleInfo )
181 const QValueList<QStyleSheetItem::ListStyle> &ols, 172 : QTextCommand( d ), id( i ), index( idx ), parag( 0 ), text( str ), styleInformation( oldStyleInfo )
182 const QMemArray<int> &oas)
183 : QTextCommand( d ), id( i ), index( idx ), parag( 0 ), text( str ), oldStyles( os ), oldListStyles( ols ), oldAligns( oas )
184{ 173{
185 for ( int j = 0; j < (int)text.size(); ++j ) { 174 for ( int j = 0; j < (int)text.size(); ++j ) {
186 if ( text[ j ].format() ) 175 if ( text[ j ].format() )
187 text[ j ].format()->addRef(); 176 text[ j ].format()->addRef();
188 } 177 }
189} 178}
190 179
191QTextDeleteCommand::QTextDeleteCommand( QTextParag *p, int idx, const QMemArray<QTextStringChar> &str ) 180QTextDeleteCommand::QTextDeleteCommand( QTextParagraph *p, int idx, const QMemArray<QTextStringChar> &str )
192 : QTextCommand( 0 ), id( -1 ), index( idx ), parag( p ), text( str ) 181 : QTextCommand( 0 ), id( -1 ), index( idx ), parag( p ), text( str )
193{ 182{
194 for ( int i = 0; i < (int)text.size(); ++i ) { 183 for ( int i = 0; i < (int)text.size(); ++i ) {
195 if ( text[ i ].format() ) 184 if ( text[ i ].format() )
196 text[ i ].format()->addRef(); 185 text[ i ].format()->addRef();
197 } 186 }
@@ -205,90 +194,74 @@ QTextDeleteCommand::~QTextDeleteCommand()
205 } 194 }
206 text.resize( 0 ); 195 text.resize( 0 );
207} 196}
208 197
209QTextCursor *QTextDeleteCommand::execute( QTextCursor *c ) 198QTextCursor *QTextDeleteCommand::execute( QTextCursor *c )
210{ 199{
211 QTextParag *s = doc ? doc->paragAt( id ) : parag; 200 QTextParagraph *s = doc ? doc->paragAt( id ) : parag;
212 if ( !s ) { 201 if ( !s ) {
213 qWarning( "can't locate parag at %d, last parag: %d", id, doc->lastParag()->paragId() ); 202 qWarning( "can't locate parag at %d, last parag: %d", id, doc->lastParagraph()->paragId() );
214 return 0; 203 return 0;
215 } 204 }
216 205
217 cursor.setParag( s ); 206 cursor.setParagraph( s );
218 cursor.setIndex( index ); 207 cursor.setIndex( index );
219 int len = text.size(); 208 int len = text.size();
220 if ( c ) 209 if ( c )
221 *c = cursor; 210 *c = cursor;
222 if ( doc ) { 211 if ( doc ) {
223 doc->setSelectionStart( QTextDocument::Temp, &cursor ); 212 doc->setSelectionStart( QTextDocument::Temp, cursor );
224 for ( int i = 0; i < len; ++i ) 213 for ( int i = 0; i < len; ++i )
225 cursor.gotoNextLetter(); 214 cursor.gotoNextLetter();
226 doc->setSelectionEnd( QTextDocument::Temp, &cursor ); 215 doc->setSelectionEnd( QTextDocument::Temp, cursor );
227 doc->removeSelectedText( QTextDocument::Temp, &cursor ); 216 doc->removeSelectedText( QTextDocument::Temp, &cursor );
228 if ( c ) 217 if ( c )
229 *c = cursor; 218 *c = cursor;
230 } else { 219 } else {
231 s->remove( index, len ); 220 s->remove( index, len );
232 } 221 }
233 222
234 return c; 223 return c;
235} 224}
236 225
237QTextCursor *QTextDeleteCommand::unexecute( QTextCursor *c ) 226QTextCursor *QTextDeleteCommand::unexecute( QTextCursor *c )
238{ 227{
239 QTextParag *s = doc ? doc->paragAt( id ) : parag; 228 QTextParagraph *s = doc ? doc->paragAt( id ) : parag;
240 if ( !s ) { 229 if ( !s ) {
241 qWarning( "can't locate parag at %d, last parag: %d", id, doc->lastParag()->paragId() ); 230 qWarning( "can't locate parag at %d, last parag: %d", id, doc->lastParagraph()->paragId() );
242 return 0; 231 return 0;
243 } 232 }
244 233
245 cursor.setParag( s ); 234 cursor.setParagraph( s );
246 cursor.setIndex( index ); 235 cursor.setIndex( index );
247 QString str = QTextString::toString( text ); 236 QString str = QTextString::toString( text );
248 cursor.insert( str, TRUE, &text ); 237 cursor.insert( str, TRUE, &text );
249 cursor.setParag( s ); 238 cursor.setParagraph( s );
250 cursor.setIndex( index ); 239 cursor.setIndex( index );
251 if ( c ) { 240 if ( c ) {
252 c->setParag( s ); 241 c->setParagraph( s );
253 c->setIndex( index ); 242 c->setIndex( index );
254 for ( int i = 0; i < (int)text.size(); ++i ) 243 for ( int i = 0; i < (int)text.size(); ++i )
255 c->gotoNextLetter(); 244 c->gotoNextLetter();
256 } 245 }
257 246
258 QValueList< QPtrVector<QStyleSheetItem> >::Iterator it = oldStyles.begin(); 247 if ( !styleInformation.isEmpty() ) {
259 QValueList<QStyleSheetItem::ListStyle>::Iterator lit = oldListStyles.begin(); 248 QDataStream styleStream( styleInformation, IO_ReadOnly );
260 int i = 0; 249 int num;
261 QTextParag *p = s; 250 styleStream >> num;
262 bool end = FALSE; 251 QTextParagraph *p = s;
263 while ( p ) { 252 while ( num-- && p ) {
264 if ( it != oldStyles.end() ) 253 p->readStyleInformation( styleStream );
265 p->setStyleSheetItems( *it ); 254 p = p->next();
266 else 255 }
267 end = TRUE;
268 if ( lit != oldListStyles.end() )
269 p->setListStyle( *lit );
270 else
271 end = TRUE;
272 if ( i < (int)oldAligns.size() )
273 p->setAlignment( oldAligns.at( i ) );
274 else
275 end = TRUE;
276 if ( end )
277 break;
278 p = p->next();
279 ++it;
280 ++lit;
281 ++i;
282 } 256 }
283 257 s = cursor.paragraph();
284 s = cursor.parag();
285 while ( s ) { 258 while ( s ) {
286 s->format(); 259 s->format();
287 s->setChanged( TRUE ); 260 s->setChanged( TRUE );
288 if ( s == c->parag() ) 261 if ( s == c->paragraph() )
289 break; 262 break;
290 s = s->next(); 263 s = s->next();
291 } 264 }
292 265
293 return &cursor; 266 return &cursor;
294} 267}
@@ -312,38 +285,38 @@ QTextFormatCommand::~QTextFormatCommand()
312 oldFormats[ j ].format()->removeRef(); 285 oldFormats[ j ].format()->removeRef();
313 } 286 }
314} 287}
315 288
316QTextCursor *QTextFormatCommand::execute( QTextCursor *c ) 289QTextCursor *QTextFormatCommand::execute( QTextCursor *c )
317{ 290{
318 QTextParag *sp = doc->paragAt( startId ); 291 QTextParagraph *sp = doc->paragAt( startId );
319 QTextParag *ep = doc->paragAt( endId ); 292 QTextParagraph *ep = doc->paragAt( endId );
320 if ( !sp || !ep ) 293 if ( !sp || !ep )
321 return c; 294 return c;
322 295
323 QTextCursor start( doc ); 296 QTextCursor start( doc );
324 start.setParag( sp ); 297 start.setParagraph( sp );
325 start.setIndex( startIndex ); 298 start.setIndex( startIndex );
326 QTextCursor end( doc ); 299 QTextCursor end( doc );
327 end.setParag( ep ); 300 end.setParagraph( ep );
328 end.setIndex( endIndex ); 301 end.setIndex( endIndex );
329 302
330 doc->setSelectionStart( QTextDocument::Temp, &start ); 303 doc->setSelectionStart( QTextDocument::Temp, start );
331 doc->setSelectionEnd( QTextDocument::Temp, &end ); 304 doc->setSelectionEnd( QTextDocument::Temp, end );
332 doc->setFormat( QTextDocument::Temp, format, flags ); 305 doc->setFormat( QTextDocument::Temp, format, flags );
333 doc->removeSelection( QTextDocument::Temp ); 306 doc->removeSelection( QTextDocument::Temp );
334 if ( endIndex == ep->length() ) 307 if ( endIndex == ep->length() )
335 end.gotoLeft(); 308 end.gotoLeft();
336 *c = end; 309 *c = end;
337 return c; 310 return c;
338} 311}
339 312
340QTextCursor *QTextFormatCommand::unexecute( QTextCursor *c ) 313QTextCursor *QTextFormatCommand::unexecute( QTextCursor *c )
341{ 314{
342 QTextParag *sp = doc->paragAt( startId ); 315 QTextParagraph *sp = doc->paragAt( startId );
343 QTextParag *ep = doc->paragAt( endId ); 316 QTextParagraph *ep = doc->paragAt( endId );
344 if ( !sp || !ep ) 317 if ( !sp || !ep )
345 return 0; 318 return 0;
346 319
347 int idx = startIndex; 320 int idx = startIndex;
348 int fIndex = 0; 321 int fIndex = 0;
349 for ( ;; ) { 322 for ( ;; ) {
@@ -370,384 +343,324 @@ QTextCursor *QTextFormatCommand::unexecute( QTextCursor *c )
370 sp = sp->next(); 343 sp = sp->next();
371 idx = 0; 344 idx = 0;
372 } 345 }
373 } 346 }
374 347
375 QTextCursor end( doc ); 348 QTextCursor end( doc );
376 end.setParag( ep ); 349 end.setParagraph( ep );
377 end.setIndex( endIndex ); 350 end.setIndex( endIndex );
378 if ( endIndex == ep->length() ) 351 if ( endIndex == ep->length() )
379 end.gotoLeft(); 352 end.gotoLeft();
380 *c = end; 353 *c = end;
381 return c; 354 return c;
382} 355}
383 356
384QTextAlignmentCommand::QTextAlignmentCommand( QTextDocument *d, int fParag, int lParag, int na, const QMemArray<int> &oa ) 357QTextStyleCommand::QTextStyleCommand( QTextDocument *d, int fParag, int lParag, const QByteArray& beforeChange )
385 : QTextCommand( d ), firstParag( fParag ), lastParag( lParag ), newAlign( na ), oldAligns( oa ) 358 : QTextCommand( d ), firstParag( fParag ), lastParag( lParag ), before( beforeChange )
386{ 359{
360 after = readStyleInformation( d, fParag, lParag );
387} 361}
388 362
389QTextCursor *QTextAlignmentCommand::execute( QTextCursor *c ) 363
364QByteArray QTextStyleCommand::readStyleInformation( QTextDocument* doc, int fParag, int lParag )
390{ 365{
391 QTextParag *p = doc->paragAt( firstParag ); 366 QByteArray style;
367 QTextParagraph *p = doc->paragAt( fParag );
392 if ( !p ) 368 if ( !p )
393 return c; 369 return style;
394 while ( p ) { 370 QDataStream styleStream( style, IO_WriteOnly );
395 p->setAlignment( newAlign ); 371 int num = lParag - fParag + 1;
396 if ( p->paragId() == lastParag ) 372 styleStream << num;
397 break; 373 while ( num -- && p ) {
374 p->writeStyleInformation( styleStream );
398 p = p->next(); 375 p = p->next();
399 } 376 }
400 return c; 377 return style;
401} 378}
402 379
403QTextCursor *QTextAlignmentCommand::unexecute( QTextCursor *c ) 380void QTextStyleCommand::writeStyleInformation( QTextDocument* doc, int fParag, const QByteArray& style )
404{ 381{
405 QTextParag *p = doc->paragAt( firstParag ); 382 QTextParagraph *p = doc->paragAt( fParag );
406 if ( !p ) 383 if ( !p )
407 return c; 384 return;
408 int i = 0; 385 QDataStream styleStream( style, IO_ReadOnly );
409 while ( p ) { 386 int num;
410 if ( i < (int)oldAligns.size() ) 387 styleStream >> num;
411 p->setAlignment( oldAligns.at( i ) ); 388 while ( num-- && p ) {
412 if ( p->paragId() == lastParag ) 389 p->readStyleInformation( styleStream );
413 break;
414 p = p->next(); 390 p = p->next();
415 ++i;
416 } 391 }
417 return c;
418}
419
420QTextParagTypeCommand::QTextParagTypeCommand( QTextDocument *d, int fParag, int lParag, bool l,
421 QStyleSheetItem::ListStyle s, const QValueList< QPtrVector<QStyleSheetItem> > &os,
422 const QValueList<QStyleSheetItem::ListStyle> &ols )
423 : QTextCommand( d ), firstParag( fParag ), lastParag( lParag ), list( l ), listStyle( s ), oldStyles( os ), oldListStyles( ols )
424{
425} 392}
426 393
427QTextCursor *QTextParagTypeCommand::execute( QTextCursor *c ) 394QTextCursor *QTextStyleCommand::execute( QTextCursor *c )
428{ 395{
429 QTextParag *p = doc->paragAt( firstParag ); 396 writeStyleInformation( doc, firstParag, after );
430 if ( !p )
431 return c;
432 while ( p ) {
433 p->setList( list, (int)listStyle );
434 if ( p->paragId() == lastParag )
435 break;
436 p = p->next();
437 }
438 return c; 397 return c;
439} 398}
440 399
441QTextCursor *QTextParagTypeCommand::unexecute( QTextCursor *c ) 400QTextCursor *QTextStyleCommand::unexecute( QTextCursor *c )
442{ 401{
443 QTextParag *p = doc->paragAt( firstParag ); 402 writeStyleInformation( doc, firstParag, before );
444 if ( !p )
445 return c;
446 QValueList< QPtrVector<QStyleSheetItem> >::Iterator it = oldStyles.begin();
447 QValueList<QStyleSheetItem::ListStyle>::Iterator lit = oldListStyles.begin();
448 while ( p ) {
449 if ( it != oldStyles.end() )
450 p->setStyleSheetItems( *it );
451 if ( lit != oldListStyles.end() )
452 p->setListStyle( *lit );
453 if ( p->paragId() == lastParag )
454 break;
455 p = p->next();
456 ++it;
457 ++lit;
458 }
459 return c; 403 return c;
460} 404}
461 405
462// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 406// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
463 407
464QTextCursor::QTextCursor( QTextDocument *d ) 408QTextCursor::QTextCursor( QTextDocument *d )
465 : doc( d ), ox( 0 ), oy( 0 ) 409 : idx( 0 ), tmpIndex( -1 ), ox( 0 ), oy( 0 ),
466{ 410 valid( TRUE )
467 nested = FALSE;
468 idx = 0;
469 string = doc ? doc->firstParag() : 0;
470 tmpIndex = -1;
471 valid = TRUE;
472}
473
474QTextCursor::QTextCursor()
475{ 411{
412 para = d ? d->firstParagraph() : 0;
476} 413}
477 414
478QTextCursor::QTextCursor( const QTextCursor &c ) 415QTextCursor::QTextCursor( const QTextCursor &c )
479{ 416{
480 doc = c.doc;
481 ox = c.ox; 417 ox = c.ox;
482 oy = c.oy; 418 oy = c.oy;
483 nested = c.nested;
484 idx = c.idx; 419 idx = c.idx;
485 string = c.string; 420 para = c.para;
486 tmpIndex = c.tmpIndex; 421 tmpIndex = c.tmpIndex;
487 indices = c.indices; 422 indices = c.indices;
488 parags = c.parags; 423 paras = c.paras;
489 xOffsets = c.xOffsets; 424 xOffsets = c.xOffsets;
490 yOffsets = c.yOffsets; 425 yOffsets = c.yOffsets;
491 valid = c.valid; 426 valid = c.valid;
492} 427}
493 428
494QTextCursor &QTextCursor::operator=( const QTextCursor &c ) 429QTextCursor &QTextCursor::operator=( const QTextCursor &c )
495{ 430{
496 doc = c.doc;
497 ox = c.ox; 431 ox = c.ox;
498 oy = c.oy; 432 oy = c.oy;
499 nested = c.nested;
500 idx = c.idx; 433 idx = c.idx;
501 string = c.string; 434 para = c.para;
502 tmpIndex = c.tmpIndex; 435 tmpIndex = c.tmpIndex;
503 indices = c.indices; 436 indices = c.indices;
504 parags = c.parags; 437 paras = c.paras;
505 xOffsets = c.xOffsets; 438 xOffsets = c.xOffsets;
506 yOffsets = c.yOffsets; 439 yOffsets = c.yOffsets;
507 valid = c.valid; 440 valid = c.valid;
508 441
509 return *this; 442 return *this;
510} 443}
511 444
512bool QTextCursor::operator==( const QTextCursor &c ) const 445bool QTextCursor::operator==( const QTextCursor &c ) const
513{ 446{
514 return doc == c.doc && string == c.string && idx == c.idx; 447 return para == c.para && idx == c.idx;
515} 448}
516 449
517int QTextCursor::totalOffsetX() const 450int QTextCursor::totalOffsetX() const
518{ 451{
519 if ( !nested )
520 return 0;
521 QValueStack<int>::ConstIterator xit = xOffsets.begin();
522 int xoff = ox; 452 int xoff = ox;
523 for ( ; xit != xOffsets.end(); ++xit ) 453 for ( QValueStack<int>::ConstIterator xit = xOffsets.begin(); xit != xOffsets.end(); ++xit )
524 xoff += *xit; 454 xoff += *xit;
525 return xoff; 455 return xoff;
526} 456}
527 457
528int QTextCursor::totalOffsetY() const 458int QTextCursor::totalOffsetY() const
529{ 459{
530 if ( !nested )
531 return 0;
532 QValueStack<int>::ConstIterator yit = yOffsets.begin();
533 int yoff = oy; 460 int yoff = oy;
534 for ( ; yit != yOffsets.end(); ++yit ) 461 for ( QValueStack<int>::ConstIterator yit = yOffsets.begin(); yit != yOffsets.end(); ++yit )
535 yoff += *yit; 462 yoff += *yit;
536 return yoff; 463 return yoff;
537} 464}
538 465
539void QTextCursor::gotoIntoNested( const QPoint &globalPos ) 466void QTextCursor::gotoIntoNested( const QPoint &globalPos )
540{ 467{
541 if ( !doc ) 468 if ( !para )
542 return; 469 return;
543 push(); 470 push();
544 ox = 0; 471 ox = 0;
545 int bl, y; 472 int bl, y;
546 string->lineHeightOfChar( idx, &bl, &y ); 473 para->lineHeightOfChar( idx, &bl, &y );
547 oy = y + string->rect().y(); 474 oy = y + para->rect().y();
548 nested = TRUE;
549 QPoint p( globalPos.x() - offsetX(), globalPos.y() - offsetY() ); 475 QPoint p( globalPos.x() - offsetX(), globalPos.y() - offsetY() );
550 Q_ASSERT( string->at( idx )->isCustom() ); 476 Q_ASSERT( para->at( idx )->isCustom() );
551 ox = string->at( idx )->x; 477 ox = para->at( idx )->x;
552 string->at( idx )->customItem()->enterAt( this, doc, string, idx, ox, oy, p ); 478
479 QTextDocument* doc = document();
480 para->at( idx )->customItem()->enterAt( this, doc, para, idx, ox, oy, p );
553} 481}
554 482
555void QTextCursor::invalidateNested() 483void QTextCursor::invalidateNested()
556{ 484{
557 if ( nested ) { 485 QValueStack<QTextParagraph*>::Iterator it = paras.begin();
558 QValueStack<QTextParag*>::Iterator it = parags.begin(); 486 QValueStack<int>::Iterator it2 = indices.begin();
559 QValueStack<int>::Iterator it2 = indices.begin(); 487 for ( ; it != paras.end(); ++it, ++it2 ) {
560 for ( ; it != parags.end(); ++it, ++it2 ) { 488 if ( *it == para )
561 if ( *it == string ) 489 continue;
562 continue; 490 (*it)->invalidate( 0 );
563 (*it)->invalidate( 0 ); 491 if ( (*it)->at( *it2 )->isCustom() )
564 if ( (*it)->at( *it2 )->isCustom() ) 492 (*it)->at( *it2 )->customItem()->invalidate();
565 (*it)->at( *it2 )->customItem()->invalidate();
566 }
567 } 493 }
568} 494}
569 495
570void QTextCursor::insert( const QString &str, bool checkNewLine, QMemArray<QTextStringChar> *formatting ) 496void QTextCursor::insert( const QString &str, bool checkNewLine, QMemArray<QTextStringChar> *formatting )
571{ 497{
572 tmpIndex = -1; 498 tmpIndex = -1;
573 bool justInsert = TRUE; 499 bool justInsert = TRUE;
574 QString s( str ); 500 QString s( str );
575#if defined(Q_WS_WIN) 501#if defined(Q_WS_WIN)
576 if ( checkNewLine ) 502 if ( checkNewLine ) {
577 s = s.replace( QRegExp( "\\r" ), "" ); 503 int i = 0;
504 while ( ( i = s.find( '\r', i ) ) != -1 )
505 s.remove( i ,1 );
506 }
578#endif 507#endif
579 if ( checkNewLine ) 508 if ( checkNewLine )
580 justInsert = s.find( '\n' ) == -1; 509 justInsert = s.find( '\n' ) == -1;
581 if ( justInsert ) { 510 if ( justInsert ) { // we ignore new lines and insert all in the current para at the current index
582 string->insert( idx, s ); 511 para->insert( idx, s.unicode(), s.length() );
583 if ( formatting ) { 512 if ( formatting ) {
584 for ( int i = 0; i < (int)s.length(); ++i ) { 513 for ( int i = 0; i < (int)s.length(); ++i ) {
585 if ( formatting->at( i ).format() ) { 514 if ( formatting->at( i ).format() ) {
586 formatting->at( i ).format()->addRef(); 515 formatting->at( i ).format()->addRef();
587 string->string()->setFormat( idx + i, formatting->at( i ).format(), TRUE ); 516 para->string()->setFormat( idx + i, formatting->at( i ).format(), TRUE );
588 } 517 }
589 } 518 }
590 } 519 }
591 idx += s.length(); 520 idx += s.length();
592 } else { 521 } else { // we split at new lines
593 QStringList lst = QStringList::split( '\n', s, TRUE ); 522 int start = -1;
594 QStringList::Iterator it = lst.begin(); 523 int end;
595 int y = string->rect().y() + string->rect().height(); 524 int y = para->rect().y() + para->rect().height();
596 int lastIndex = 0; 525 int lastIndex = 0;
597 QTextFormat *lastFormat = 0; 526 do {
598 for ( ; it != lst.end(); ) { 527 end = s.find( '\n', start + 1 ); // find line break
599 if ( it != lst.begin() ) { 528 if ( end == -1 ) // didn't find one, so end of line is end of string
600 splitAndInsertEmptyParag( FALSE, TRUE ); 529 end = s.length();
601 string->setEndState( -1 ); 530 int len = (start == -1 ? end : end - start - 1);
602 string->prev()->format( -1, FALSE ); 531 if ( len > 0 ) // insert the line
603 if ( lastFormat && formatting && string->prev() ) { 532 para->insert( idx, s.unicode() + start + 1, len );
604 lastFormat->addRef();
605 string->prev()->string()->setFormat( string->prev()->length() - 1, lastFormat, TRUE );
606 }
607 }
608 lastFormat = 0;
609 QString s = *it;
610 ++it;
611 if ( !s.isEmpty() )
612 string->insert( idx, s );
613 else 533 else
614 string->invalidate( 0 ); 534 para->invalidate( 0 );
615 if ( formatting ) { 535 if ( formatting ) { // set formats to the chars of the line
616 int len = s.length();
617 for ( int i = 0; i < len; ++i ) { 536 for ( int i = 0; i < len; ++i ) {
618 if ( formatting->at( i + lastIndex ).format() ) { 537 if ( formatting->at( i + lastIndex ).format() ) {
619 formatting->at( i + lastIndex ).format()->addRef(); 538 formatting->at( i + lastIndex ).format()->addRef();
620 string->string()->setFormat( i + idx, formatting->at( i + lastIndex ).format(), TRUE ); 539 para->string()->setFormat( i + idx, formatting->at( i + lastIndex ).format(), TRUE );
621 } 540 }
622 } 541 }
623 if ( it != lst.end() )
624 lastFormat = formatting->at( len + lastIndex ).format();
625 ++len;
626 lastIndex += len; 542 lastIndex += len;
627 } 543 }
544 start = end; // next start is at the end of this line
545 idx += len; // increase the index of the cursor to the end of the inserted text
546 if ( s[end] == '\n' ) { // if at the end was a line break, break the line
547 splitAndInsertEmptyParagraph( FALSE, TRUE );
548 para->setEndState( -1 );
549 para->prev()->format( -1, FALSE );
550 lastIndex++;
551 }
628 552
629 idx += s.length(); 553 } while ( end < (int)s.length() );
630 } 554
631 string->format( -1, FALSE ); 555 para->format( -1, FALSE );
632 int dy = string->rect().y() + string->rect().height() - y; 556 int dy = para->rect().y() + para->rect().height() - y;
633 QTextParag *p = string; 557 QTextParagraph *p = para;
634 p->setParagId( p->prev()->paragId() + 1 ); 558 p->setParagId( p->prev() ? p->prev()->paragId() + 1 : 0 );
635 p = p->next(); 559 p = p->next();
636 while ( p ) { 560 while ( p ) {
637 p->setParagId( p->prev()->paragId() + 1 ); 561 p->setParagId( p->prev()->paragId() + 1 );
638 p->move( dy ); 562 p->move( dy );
639 p->invalidate( 0 ); 563 p->invalidate( 0 );
640 p->setEndState( -1 ); 564 p->setEndState( -1 );
641 p = p->next(); 565 p = p->next();
642 } 566 }
643 } 567 }
644 568
645 int h = string->rect().height(); 569 int h = para->rect().height();
646 string->format( -1, TRUE ); 570 para->format( -1, TRUE );
647 if ( h != string->rect().height() ) 571 if ( h != para->rect().height() )
648 invalidateNested(); 572 invalidateNested();
649 else if ( doc && doc->parent() ) 573 else if ( para->document() && para->document()->parent() )
650 doc->nextDoubleBuffered = TRUE; 574 para->document()->nextDoubleBuffered = TRUE;
651} 575}
652 576
653void QTextCursor::gotoLeft() 577void QTextCursor::gotoLeft()
654{ 578{
655 if ( string->string()->isRightToLeft() ) 579 if ( para->string()->isRightToLeft() )
656 gotoNextLetter(); 580 gotoNextLetter();
657 else 581 else
658 gotoPreviousLetter(); 582 gotoPreviousLetter();
659} 583}
660 584
661void QTextCursor::gotoPreviousLetter() 585void QTextCursor::gotoPreviousLetter()
662{ 586{
663 tmpIndex = -1; 587 tmpIndex = -1;
664 588
665 if ( idx > 0 ) { 589 if ( idx > 0 ) {
666 idx--; 590 idx--;
667 } else if ( string->prev() ) { 591 const QTextStringChar *tsc = para->at( idx );
668 QTextParag *s = string->prev(); 592 if ( tsc && tsc->isCustom() && tsc->customItem()->isNested() )
669 while ( s && !s->isVisible() ) 593 processNesting( EnterEnd );
670 s = s->prev(); 594 } else if ( para->prev() ) {
671 if ( s ) { 595 para = para->prev();
672 string = s; 596 while ( !para->isVisible() && para->prev() )
673 idx = string->length() - 1; 597 para = para->prev();
674 } 598 idx = para->length() - 1;
675 } else { 599 } else if ( nestedDepth() ) {
676 if ( nested ) { 600 pop();
601 processNesting( Prev );
602 if ( idx == -1 ) {
677 pop(); 603 pop();
678 processNesting( Prev ); 604 if ( idx > 0 ) {
679 if ( idx == -1 ) { 605 idx--;
680 pop(); 606 } else if ( para->prev() ) {
681 if ( idx > 0 ) { 607 para = para->prev();
682 idx--; 608 idx = para->length() - 1;
683 } else if ( string->prev() ) {
684 string = string->prev();
685 idx = string->length() - 1;
686 }
687 } 609 }
688 } 610 }
689 } 611 }
690
691 const QTextStringChar *tsc = string->at( idx );
692 if ( tsc && tsc->isCustom() && tsc->customItem()->isNested() ) {
693 processNesting( EnterEnd );
694 }
695} 612}
696 613
697void QTextCursor::push() 614void QTextCursor::push()
698{ 615{
699 indices.push( idx ); 616 indices.push( idx );
700 parags.push( string ); 617 paras.push( para );
701 xOffsets.push( ox ); 618 xOffsets.push( ox );
702 yOffsets.push( oy ); 619 yOffsets.push( oy );
703 nestedStack.push( nested );
704} 620}
705 621
706void QTextCursor::pop() 622void QTextCursor::pop()
707{ 623{
708 if ( !doc ) 624 if ( indices.isEmpty() )
709 return; 625 return;
710 idx = indices.pop(); 626 idx = indices.pop();
711 string = parags.pop(); 627 para = paras.pop();
712 ox = xOffsets.pop(); 628 ox = xOffsets.pop();
713 oy = yOffsets.pop(); 629 oy = yOffsets.pop();
714 if ( doc->parent() )
715 doc = doc->parent();
716 nested = nestedStack.pop();
717} 630}
718 631
719void QTextCursor::restoreState() 632void QTextCursor::restoreState()
720{ 633{
721 while ( !indices.isEmpty() ) 634 while ( !indices.isEmpty() )
722 pop(); 635 pop();
723} 636}
724 637
725bool QTextCursor::place( const QPoint &p, QTextParag *s, bool link ) 638bool QTextCursor::place( const QPoint &p, QTextParagraph *s, bool link )
726{ 639{
727 QPoint pos( p ); 640 QPoint pos( p );
728 QRect r; 641 QRect r;
729 QTextParag *str = s; 642 QTextParagraph *str = s;
730 if ( pos.y() < s->rect().y() ) 643 if ( pos.y() < s->rect().y() )
731 pos.setY( s->rect().y() ); 644 pos.setY( s->rect().y() );
732 while ( s ) { 645 while ( s ) {
733 r = s->rect(); 646 r = s->rect();
734 r.setWidth( doc ? doc->width() : QWIDGETSIZE_MAX ); 647 r.setWidth( document() ? document()->width() : QWIDGETSIZE_MAX );
735 if ( s->isVisible() ) 648 if ( s->isVisible() )
736 str = s; 649 str = s;
737 if ( pos.y() >= r.y() && pos.y() <= r.y() + r.height() || !s->next() ) 650 if ( pos.y() >= r.y() && pos.y() <= r.y() + r.height() || !s->next() )
738 break; 651 break;
739 s = s->next(); 652 s = s->next();
740 } 653 }
741 654
742 if ( !s || !str ) 655 if ( !s || !str )
743 return FALSE; 656 return FALSE;
744 657
745 s = str; 658 s = str;
746 659
747 setParag( s, FALSE ); 660 setParagraph( s );
748 int y = s->rect().y(); 661 int y = s->rect().y();
749 int lines = s->lines(); 662 int lines = s->lines();
750 QTextStringChar *chr = 0; 663 QTextStringChar *chr = 0;
751 int index = 0; 664 int index = 0;
752 int i = 0; 665 int i = 0;
753 int cy = 0; 666 int cy = 0;
@@ -755,13 +668,13 @@ bool QTextCursor::place( const QPoint &p, QTextParag *s, bool link )
755 for ( ; i < lines; ++i ) { 668 for ( ; i < lines; ++i ) {
756 chr = s->lineStartOfLine( i, &index ); 669 chr = s->lineStartOfLine( i, &index );
757 cy = s->lineY( i ); 670 cy = s->lineY( i );
758 ch = s->lineHeight( i ); 671 ch = s->lineHeight( i );
759 if ( !chr ) 672 if ( !chr )
760 return FALSE; 673 return FALSE;
761 if ( pos.y() >= y + cy && pos.y() <= y + cy + ch ) 674 if ( pos.y() <= y + cy + ch )
762 break; 675 break;
763 } 676 }
764 int nextLine; 677 int nextLine;
765 if ( i < lines - 1 ) 678 if ( i < lines - 1 )
766 s->lineStartOfLine( i+1, &nextLine ); 679 s->lineStartOfLine( i+1, &nextLine );
767 else 680 else
@@ -795,205 +708,200 @@ bool QTextCursor::place( const QPoint &p, QTextParag *s, bool link )
795 if ( !link || pos.x() >= x + chr->x ) 708 if ( !link || pos.x() >= x + chr->x )
796 curpos = i; 709 curpos = i;
797 } 710 }
798 } 711 }
799 i++; 712 i++;
800 } 713 }
801 setIndex( curpos, FALSE ); 714 setIndex( curpos );
802 715
803 if ( inCustom && doc && parag()->at( curpos )->isCustom() && parag()->at( curpos )->customItem()->isNested() ) { 716 if ( inCustom && para->document() && para->at( curpos )->isCustom() && para->at( curpos )->customItem()->isNested() ) {
804 QTextDocument *oldDoc = doc; 717 QTextDocument *oldDoc = para->document();
805 gotoIntoNested( pos ); 718 gotoIntoNested( pos );
806 if ( oldDoc == doc ) 719 if ( oldDoc == para->document() )
807 return TRUE; 720 return TRUE;
808 QPoint p( pos.x() - offsetX(), pos.y() - offsetY() ); 721 QPoint p( pos.x() - offsetX(), pos.y() - offsetY() );
809 if ( !place( p, document()->firstParag(), link ) ) 722 if ( !place( p, document()->firstParagraph(), link ) )
810 pop(); 723 pop();
811 } 724 }
812 return TRUE; 725 return TRUE;
813} 726}
814 727
815void QTextCursor::processNesting( Operation op ) 728void QTextCursor::processNesting( Operation op )
816{ 729{
817 if ( !doc ) 730 if ( !para->document() )
818 return; 731 return;
732 QTextDocument* doc = para->document();
819 push(); 733 push();
820 ox = string->at( idx )->x; 734 ox = para->at( idx )->x;
821 int bl, y; 735 int bl, y;
822 string->lineHeightOfChar( idx, &bl, &y ); 736 para->lineHeightOfChar( idx, &bl, &y );
823 oy = y + string->rect().y(); 737 oy = y + para->rect().y();
824 nested = TRUE;
825 bool ok = FALSE; 738 bool ok = FALSE;
826 739
827 switch ( op ) { 740 switch ( op ) {
828 case EnterBegin: 741 case EnterBegin:
829 ok = string->at( idx )->customItem()->enter( this, doc, string, idx, ox, oy ); 742 ok = para->at( idx )->customItem()->enter( this, doc, para, idx, ox, oy );
830 break; 743 break;
831 case EnterEnd: 744 case EnterEnd:
832 ok = string->at( idx )->customItem()->enter( this, doc, string, idx, ox, oy, TRUE ); 745 ok = para->at( idx )->customItem()->enter( this, doc, para, idx, ox, oy, TRUE );
833 break; 746 break;
834 case Next: 747 case Next:
835 ok = string->at( idx )->customItem()->next( this, doc, string, idx, ox, oy ); 748 ok = para->at( idx )->customItem()->next( this, doc, para, idx, ox, oy );
836 break; 749 break;
837 case Prev: 750 case Prev:
838 ok = string->at( idx )->customItem()->prev( this, doc, string, idx, ox, oy ); 751 ok = para->at( idx )->customItem()->prev( this, doc, para, idx, ox, oy );
839 break; 752 break;
840 case Down: 753 case Down:
841 ok = string->at( idx )->customItem()->down( this, doc, string, idx, ox, oy ); 754 ok = para->at( idx )->customItem()->down( this, doc, para, idx, ox, oy );
842 break; 755 break;
843 case Up: 756 case Up:
844 ok = string->at( idx )->customItem()->up( this, doc, string, idx, ox, oy ); 757 ok = para->at( idx )->customItem()->up( this, doc, para, idx, ox, oy );
845 break; 758 break;
846 } 759 }
847 if ( !ok ) 760 if ( !ok )
848 pop(); 761 pop();
849} 762}
850 763
851void QTextCursor::gotoRight() 764void QTextCursor::gotoRight()
852{ 765{
853 if ( string->string()->isRightToLeft() ) 766 if ( para->string()->isRightToLeft() )
854 gotoPreviousLetter(); 767 gotoPreviousLetter();
855 else 768 else
856 gotoNextLetter(); 769 gotoNextLetter();
857} 770}
858 771
859void QTextCursor::gotoNextLetter() 772void QTextCursor::gotoNextLetter()
860{ 773{
861 tmpIndex = -1; 774 tmpIndex = -1;
862 775
863 const QTextStringChar *tsc = string->at( idx ); 776 const QTextStringChar *tsc = para->at( idx );
864 if ( tsc && tsc->isCustom() && tsc->customItem()->isNested() ) { 777 if ( tsc && tsc->isCustom() && tsc->customItem()->isNested() ) {
865 processNesting( EnterBegin ); 778 processNesting( EnterBegin );
866 return; 779 return;
867 } 780 }
868 781
869 if ( idx < string->length() - 1 ) { 782 if ( idx < para->length() - 1 ) {
870 idx++; 783 idx++;
871 } else if ( string->next() ) { 784 } else if ( para->next() ) {
872 QTextParag *s = string->next(); 785 para = para->next();
873 while ( s && !s->isVisible() ) 786 while ( !para->isVisible() && para->next() )
874 s = s->next(); 787 para = para->next();
875 if ( s ) { 788 idx = 0;
876 string = s; 789 } else if ( nestedDepth() ) {
877 idx = 0; 790 pop();
878 } 791 processNesting( Next );
879 } else { 792 if ( idx == -1 ) {
880 if ( nested ) {
881 pop(); 793 pop();
882 processNesting( Next ); 794 if ( idx < para->length() - 1 ) {
883 if ( idx == -1 ) { 795 idx++;
884 pop(); 796 } else if ( para->next() ) {
885 if ( idx < string->length() - 1 ) { 797 para = para->next();
886 idx++; 798 idx = 0;
887 } else if ( string->next() ) {
888 string = string->next();
889 idx = 0;
890 }
891 } 799 }
892 } 800 }
893 } 801 }
894} 802}
895 803
896void QTextCursor::gotoUp() 804void QTextCursor::gotoUp()
897{ 805{
898 int indexOfLineStart; 806 int indexOfLineStart;
899 int line; 807 int line;
900 QTextStringChar *c = string->lineStartOfChar( idx, &indexOfLineStart, &line ); 808 QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
901 if ( !c ) 809 if ( !c )
902 return; 810 return;
903 811
904 tmpIndex = QMAX( tmpIndex, idx - indexOfLineStart ); 812 tmpIndex = QMAX( tmpIndex, idx - indexOfLineStart );
905 if ( indexOfLineStart == 0 ) { 813 if ( indexOfLineStart == 0 ) {
906 if ( !string->prev() ) { 814 if ( !para->prev() ) {
907 if ( !nested ) 815 if ( !nestedDepth() )
908 return; 816 return;
909 pop(); 817 pop();
910 processNesting( Up ); 818 processNesting( Up );
911 if ( idx == -1 ) { 819 if ( idx == -1 ) {
912 pop(); 820 pop();
913 if ( !string->prev() ) 821 if ( !para->prev() )
914 return; 822 return;
915 idx = tmpIndex = 0; 823 idx = tmpIndex = 0;
916 } else { 824 } else {
917 tmpIndex = -1; 825 tmpIndex = -1;
918 return; 826 return;
919 } 827 }
920 } 828 }
921 QTextParag *s = string->prev(); 829 QTextParagraph *p = para->prev();
922 while ( s && !s->isVisible() ) 830 while ( p && !p->isVisible() )
923 s = s->prev(); 831 p = p->prev();
924 if ( s ) 832 if ( p )
925 string = s; 833 para = p;
926 int lastLine = string->lines() - 1; 834 int lastLine = para->lines() - 1;
927 if ( !string->lineStartOfLine( lastLine, &indexOfLineStart ) ) 835 if ( !para->lineStartOfLine( lastLine, &indexOfLineStart ) )
928 return; 836 return;
929 if ( indexOfLineStart + tmpIndex < string->length() ) 837 if ( indexOfLineStart + tmpIndex < para->length() )
930 idx = indexOfLineStart + tmpIndex; 838 idx = indexOfLineStart + tmpIndex;
931 else 839 else
932 idx = string->length() - 1; 840 idx = para->length() - 1;
933 } else { 841 } else {
934 --line; 842 --line;
935 int oldIndexOfLineStart = indexOfLineStart; 843 int oldIndexOfLineStart = indexOfLineStart;
936 if ( !string->lineStartOfLine( line, &indexOfLineStart ) ) 844 if ( !para->lineStartOfLine( line, &indexOfLineStart ) )
937 return; 845 return;
938 if ( indexOfLineStart + tmpIndex < oldIndexOfLineStart ) 846 if ( indexOfLineStart + tmpIndex < oldIndexOfLineStart )
939 idx = indexOfLineStart + tmpIndex; 847 idx = indexOfLineStart + tmpIndex;
940 else 848 else
941 idx = oldIndexOfLineStart - 1; 849 idx = oldIndexOfLineStart - 1;
942 } 850 }
943} 851}
944 852
945void QTextCursor::gotoDown() 853void QTextCursor::gotoDown()
946{ 854{
947 int indexOfLineStart; 855 int indexOfLineStart;
948 int line; 856 int line;
949 QTextStringChar *c = string->lineStartOfChar( idx, &indexOfLineStart, &line ); 857 QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
950 if ( !c ) 858 if ( !c )
951 return; 859 return;
952 860
953 tmpIndex = QMAX( tmpIndex, idx - indexOfLineStart ); 861 tmpIndex = QMAX( tmpIndex, idx - indexOfLineStart );
954 if ( line == string->lines() - 1 ) { 862 if ( line == para->lines() - 1 ) {
955 if ( !string->next() ) { 863 if ( !para->next() ) {
956 if ( !nested ) 864 if ( !nestedDepth() )
957 return; 865 return;
958 pop(); 866 pop();
959 processNesting( Down ); 867 processNesting( Down );
960 if ( idx == -1 ) { 868 if ( idx == -1 ) {
961 pop(); 869 pop();
962 if ( !string->next() ) 870 if ( !para->next() )
963 return; 871 return;
964 idx = tmpIndex = 0; 872 idx = tmpIndex = 0;
965 } else { 873 } else {
966 tmpIndex = -1; 874 tmpIndex = -1;
967 return; 875 return;
968 } 876 }
969 } 877 }
970 QTextParag *s = string->next(); 878 QTextParagraph *s = para->next();
971 while ( s && !s->isVisible() ) 879 while ( s && !s->isVisible() )
972 s = s->next(); 880 s = s->next();
973 if ( s ) 881 if ( s )
974 string = s; 882 para = s;
975 if ( !string->lineStartOfLine( 0, &indexOfLineStart ) ) 883 if ( !para->lineStartOfLine( 0, &indexOfLineStart ) )
976 return; 884 return;
977 int end; 885 int end;
978 if ( string->lines() == 1 ) 886 if ( para->lines() == 1 )
979 end = string->length(); 887 end = para->length();
980 else 888 else
981 string->lineStartOfLine( 1, &end ); 889 para->lineStartOfLine( 1, &end );
982 if ( indexOfLineStart + tmpIndex < end ) 890 if ( indexOfLineStart + tmpIndex < end )
983 idx = indexOfLineStart + tmpIndex; 891 idx = indexOfLineStart + tmpIndex;
984 else 892 else
985 idx = end - 1; 893 idx = end - 1;
986 } else { 894 } else {
987 ++line; 895 ++line;
988 int end; 896 int end;
989 if ( line == string->lines() - 1 ) 897 if ( line == para->lines() - 1 )
990 end = string->length(); 898 end = para->length();
991 else 899 else
992 string->lineStartOfLine( line + 1, &end ); 900 para->lineStartOfLine( line + 1, &end );
993 if ( !string->lineStartOfLine( line, &indexOfLineStart ) ) 901 if ( !para->lineStartOfLine( line, &indexOfLineStart ) )
994 return; 902 return;
995 if ( indexOfLineStart + tmpIndex < end ) 903 if ( indexOfLineStart + tmpIndex < end )
996 idx = indexOfLineStart + tmpIndex; 904 idx = indexOfLineStart + tmpIndex;
997 else 905 else
998 idx = end - 1; 906 idx = end - 1;
999 } 907 }
@@ -1001,122 +909,95 @@ void QTextCursor::gotoDown()
1001 909
1002void QTextCursor::gotoLineEnd() 910void QTextCursor::gotoLineEnd()
1003{ 911{
1004 tmpIndex = -1; 912 tmpIndex = -1;
1005 int indexOfLineStart; 913 int indexOfLineStart;
1006 int line; 914 int line;
1007 QTextStringChar *c = string->lineStartOfChar( idx, &indexOfLineStart, &line ); 915 QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
1008 if ( !c ) 916 if ( !c )
1009 return; 917 return;
1010 918
1011 if ( line == string->lines() - 1 ) { 919 if ( line == para->lines() - 1 ) {
1012 idx = string->length() - 1; 920 idx = para->length() - 1;
1013 } else { 921 } else {
1014 c = string->lineStartOfLine( ++line, &indexOfLineStart ); 922 c = para->lineStartOfLine( ++line, &indexOfLineStart );
1015 indexOfLineStart--; 923 indexOfLineStart--;
1016 idx = indexOfLineStart; 924 idx = indexOfLineStart;
1017 } 925 }
1018} 926}
1019 927
1020void QTextCursor::gotoLineStart() 928void QTextCursor::gotoLineStart()
1021{ 929{
1022 tmpIndex = -1; 930 tmpIndex = -1;
1023 int indexOfLineStart; 931 int indexOfLineStart;
1024 int line; 932 int line;
1025 QTextStringChar *c = string->lineStartOfChar( idx, &indexOfLineStart, &line ); 933 QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
1026 if ( !c ) 934 if ( !c )
1027 return; 935 return;
1028 936
1029 idx = indexOfLineStart; 937 idx = indexOfLineStart;
1030} 938}
1031 939
1032void QTextCursor::gotoHome() 940void QTextCursor::gotoHome()
1033{ 941{
1034 tmpIndex = -1; 942 if ( topParagraph()->document() )
1035 if ( doc ) 943 gotoPosition( topParagraph()->document()->firstParagraph() );
1036 string = doc->firstParag(); 944 else
1037 idx = 0; 945 gotoLineStart();
1038} 946}
1039 947
1040void QTextCursor::gotoEnd() 948void QTextCursor::gotoEnd()
1041{ 949{
1042 if ( doc && !doc->lastParag()->isValid() ) 950 if ( topParagraph()->document() && topParagraph()->document()->lastParagraph()->isValid() )
1043 return; 951 gotoPosition( topParagraph()->document()->lastParagraph(),
1044 952 topParagraph()->document()->lastParagraph()->length() - 1);
1045 tmpIndex = -1; 953 else
1046 if ( doc ) 954 gotoLineEnd();
1047 string = doc->lastParag();
1048 idx = string->length() - 1;
1049} 955}
1050 956
1051void QTextCursor::gotoPageUp( int visibleHeight ) 957void QTextCursor::gotoPageUp( int visibleHeight )
1052{ 958{
1053 tmpIndex = -1; 959 int targetY = globalY() - visibleHeight;
1054 QTextParag *s = string; 960 QTextParagraph* old; int index;
1055 int h = visibleHeight; 961 do {
1056 int y = s->rect().y(); 962 old = para; index = idx;
1057 while ( s ) { 963 gotoUp();
1058 if ( y - s->rect().y() >= h ) 964 } while ( (old != para || index != idx) && globalY() > targetY );
1059 break;
1060 s = s->prev();
1061 }
1062
1063 if ( !s && doc )
1064 s = doc->firstParag();
1065
1066 string = s;
1067 idx = 0;
1068} 965}
1069 966
1070void QTextCursor::gotoPageDown( int visibleHeight ) 967void QTextCursor::gotoPageDown( int visibleHeight )
1071{ 968{
1072 tmpIndex = -1; 969 int targetY = globalY() + visibleHeight;
1073 QTextParag *s = string; 970 QTextParagraph* old; int index;
1074 int h = visibleHeight; 971 do {
1075 int y = s->rect().y(); 972 old = para; index = idx;
1076 while ( s ) { 973 gotoDown();
1077 if ( s->rect().y() - y >= h ) 974 } while ( (old != para || index != idx) && globalY() < targetY );
1078 break;
1079 s = s->next();
1080 }
1081
1082 if ( !s && doc ) {
1083 s = doc->lastParag();
1084 string = s;
1085 idx = string->length() - 1;
1086 return;
1087 }
1088
1089 if ( !s->isValid() )
1090 return;
1091
1092 string = s;
1093 idx = 0;
1094} 975}
1095 976
1096void QTextCursor::gotoWordRight() 977void QTextCursor::gotoWordRight()
1097{ 978{
1098 if ( string->string()->isRightToLeft() ) 979 if ( para->string()->isRightToLeft() )
1099 gotoPreviousWord(); 980 gotoPreviousWord();
1100 else 981 else
1101 gotoNextWord(); 982 gotoNextWord();
1102} 983}
1103 984
1104void QTextCursor::gotoWordLeft() 985void QTextCursor::gotoWordLeft()
1105{ 986{
1106 if ( string->string()->isRightToLeft() ) 987 if ( para->string()->isRightToLeft() )
1107 gotoNextWord(); 988 gotoNextWord();
1108 else 989 else
1109 gotoPreviousWord(); 990 gotoPreviousWord();
1110} 991}
1111 992
1112void QTextCursor::gotoPreviousWord() 993void QTextCursor::gotoPreviousWord()
1113{ 994{
1114 gotoPreviousLetter(); 995 gotoPreviousLetter();
1115 tmpIndex = -1; 996 tmpIndex = -1;
1116 QTextString *s = string->string(); 997 QTextString *s = para->string();
1117 bool allowSame = FALSE; 998 bool allowSame = FALSE;
1118 if ( idx == ((int)s->length()-1) ) 999 if ( idx == ((int)s->length()-1) )
1119 return; 1000 return;
1120 for ( int i = idx; i >= 0; --i ) { 1001 for ( int i = idx; i >= 0; --i ) {
1121 if ( s->at( i ).c.isSpace() || s->at( i ).c == '\t' || s->at( i ).c == '.' || 1002 if ( s->at( i ).c.isSpace() || s->at( i ).c == '\t' || s->at( i ).c == '.' ||
1122 s->at( i ).c == ',' || s->at( i ).c == ':' || s->at( i ).c == ';' ) { 1003 s->at( i ).c == ',' || s->at( i ).c == ':' || s->at( i ).c == ';' ) {
@@ -1132,13 +1013,13 @@ void QTextCursor::gotoPreviousWord()
1132 idx = 0; 1013 idx = 0;
1133} 1014}
1134 1015
1135void QTextCursor::gotoNextWord() 1016void QTextCursor::gotoNextWord()
1136{ 1017{
1137 tmpIndex = -1; 1018 tmpIndex = -1;
1138 QTextString *s = string->string(); 1019 QTextString *s = para->string();
1139 bool allowSame = FALSE; 1020 bool allowSame = FALSE;
1140 for ( int i = idx; i < (int)s->length(); ++i ) { 1021 for ( int i = idx; i < (int)s->length(); ++i ) {
1141 if ( ! (s->at( i ).c.isSpace() || s->at( i ).c == '\t' || s->at( i ).c == '.' || 1022 if ( ! (s->at( i ).c.isSpace() || s->at( i ).c == '\t' || s->at( i ).c == '.' ||
1142 s->at( i ).c == ',' || s->at( i ).c == ':' || s->at( i ).c == ';') ) { 1023 s->at( i ).c == ',' || s->at( i ).c == ':' || s->at( i ).c == ';') ) {
1143 if ( !allowSame ) 1024 if ( !allowSame )
1144 continue; 1025 continue;
@@ -1150,18 +1031,18 @@ void QTextCursor::gotoNextWord()
1150 allowSame = TRUE; 1031 allowSame = TRUE;
1151 1032
1152 } 1033 }
1153 1034
1154 if ( idx < ((int)s->length()-1) ) { 1035 if ( idx < ((int)s->length()-1) ) {
1155 gotoLineEnd(); 1036 gotoLineEnd();
1156 } else if ( string->next() ) { 1037 } else if ( para->next() ) {
1157 QTextParag *s = string->next(); 1038 QTextParagraph *p = para->next();
1158 while ( s && !s->isVisible() ) 1039 while ( p && !p->isVisible() )
1159 s = s->next(); 1040 p = p->next();
1160 if ( s ) { 1041 if ( s ) {
1161 string = s; 1042 para = p;
1162 idx = 0; 1043 idx = 0;
1163 } 1044 }
1164 } else { 1045 } else {
1165 gotoLineEnd(); 1046 gotoLineEnd();
1166 } 1047 }
1167} 1048}
@@ -1170,184 +1051,143 @@ bool QTextCursor::atParagStart()
1170{ 1051{
1171 return idx == 0; 1052 return idx == 0;
1172} 1053}
1173 1054
1174bool QTextCursor::atParagEnd() 1055bool QTextCursor::atParagEnd()
1175{ 1056{
1176 return idx == string->length() - 1; 1057 return idx == para->length() - 1;
1177} 1058}
1178 1059
1179void QTextCursor::splitAndInsertEmptyParag( bool ind, bool updateIds ) 1060void QTextCursor::splitAndInsertEmptyParagraph( bool ind, bool updateIds )
1180{ 1061{
1181 if ( !doc ) 1062 if ( !para->document() )
1182 return; 1063 return;
1183 tmpIndex = -1; 1064 tmpIndex = -1;
1184 QTextFormat *f = 0; 1065 QTextFormat *f = 0;
1185 if ( doc->useFormatCollection() ) { 1066 if ( para->document()->useFormatCollection() ) {
1186 f = string->at( idx )->format(); 1067 f = para->at( idx )->format();
1187 if ( idx == string->length() - 1 && idx > 0 ) 1068 if ( idx == para->length() - 1 && idx > 0 )
1188 f = string->at( idx - 1 )->format(); 1069 f = para->at( idx - 1 )->format();
1189 if ( f->isMisspelled() ) { 1070 if ( f->isMisspelled() ) {
1190 f->removeRef(); 1071 f->removeRef();
1191 f = doc->formatCollection()->format( f->font(), f->color() ); 1072 f = para->document()->formatCollection()->format( f->font(), f->color() );
1192 } 1073 }
1193 } 1074 }
1194 1075
1195 if ( atParagEnd() ) { 1076 if ( atParagEnd() ) {
1196 QTextParag *n = string->next(); 1077 QTextParagraph *n = para->next();
1197 QTextParag *s = doc->createParag( doc, string, n, updateIds ); 1078 QTextParagraph *s = para->document()->createParagraph( para->document(), para, n, updateIds );
1198 if ( f ) 1079 if ( f )
1199 s->setFormat( 0, 1, f, TRUE ); 1080 s->setFormat( 0, 1, f, TRUE );
1200 s->copyParagData( string ); 1081 s->copyParagData( para );
1201 if ( ind ) { 1082 if ( ind ) {
1202 int oi, ni; 1083 int oi, ni;
1203 s->indent( &oi, &ni ); 1084 s->indent( &oi, &ni );
1204 string = s; 1085 para = s;
1205 idx = ni; 1086 idx = ni;
1206 } else { 1087 } else {
1207 string = s; 1088 para = s;
1208 idx = 0; 1089 idx = 0;
1209 } 1090 }
1210 } else if ( atParagStart() ) { 1091 } else if ( atParagStart() ) {
1211 QTextParag *p = string->prev(); 1092 QTextParagraph *p = para->prev();
1212 QTextParag *s = doc->createParag( doc, p, string, updateIds ); 1093 QTextParagraph *s = para->document()->createParagraph( para->document(), p, para, updateIds );
1213 if ( f ) 1094 if ( f )
1214 s->setFormat( 0, 1, f, TRUE ); 1095 s->setFormat( 0, 1, f, TRUE );
1215 s->copyParagData( string ); 1096 s->copyParagData( para );
1216 if ( ind ) { 1097 if ( ind ) {
1217 s->indent(); 1098 s->indent();
1218 s->format(); 1099 s->format();
1219 indent(); 1100 indent();
1220 string->format(); 1101 para->format();
1221 } 1102 }
1222 } else { 1103 } else {
1223 QString str = string->string()->toString().mid( idx, 0xFFFFFF ); 1104 QString str = para->string()->toString().mid( idx, 0xFFFFFF );
1224 QTextParag *n = string->next(); 1105 QTextParagraph *n = para->next();
1225 QTextParag *s = doc->createParag( doc, string, n, updateIds ); 1106 QTextParagraph *s = para->document()->createParagraph( para->document(), para, n, updateIds );
1226 s->copyParagData( string ); 1107 s->copyParagData( para );
1227 s->remove( 0, 1 ); 1108 s->remove( 0, 1 );
1228 s->append( str, TRUE ); 1109 s->append( str, TRUE );
1229 for ( uint i = 0; i < str.length(); ++i ) { 1110 for ( uint i = 0; i < str.length(); ++i ) {
1230 s->setFormat( i, 1, string->at( idx + i )->format(), TRUE ); 1111 QTextStringChar* tsc = para->at( idx + i );
1231 if ( string->at( idx + i )->isCustom() ) { 1112 s->setFormat( i, 1, tsc->format(), TRUE );
1232 QTextCustomItem * item = string->at( idx + i )->customItem(); 1113 if ( tsc->isCustom() ) {
1114 QTextCustomItem * item = tsc->customItem();
1233 s->at( i )->setCustomItem( item ); 1115 s->at( i )->setCustomItem( item );
1234 string->at( idx + i )->loseCustomItem(); 1116 tsc->loseCustomItem();
1235 } 1117 }
1118 if ( tsc->isAnchor() )
1119 s->at( i )->setAnchor( tsc->anchorName(),
1120 tsc->anchorHref() );
1236 } 1121 }
1237 string->truncate( idx ); 1122 para->truncate( idx );
1238 if ( ind ) { 1123 if ( ind ) {
1239 int oi, ni; 1124 int oi, ni;
1240 s->indent( &oi, &ni ); 1125 s->indent( &oi, &ni );
1241 string = s; 1126 para = s;
1242 idx = ni; 1127 idx = ni;
1243 } else { 1128 } else {
1244 string = s; 1129 para = s;
1245 idx = 0; 1130 idx = 0;
1246 } 1131 }
1247 } 1132 }
1248 1133
1249 invalidateNested(); 1134 invalidateNested();
1250} 1135}
1251 1136
1252bool QTextCursor::remove() 1137bool QTextCursor::remove()
1253{ 1138{
1254 tmpIndex = -1; 1139 tmpIndex = -1;
1255 if ( !atParagEnd() ) { 1140 if ( !atParagEnd() ) {
1256 string->remove( idx, 1 ); 1141 para->remove( idx, 1 );
1257 int h = string->rect().height(); 1142 int h = para->rect().height();
1258 string->format( -1, TRUE ); 1143 para->format( -1, TRUE );
1259 if ( h != string->rect().height() ) 1144 if ( h != para->rect().height() )
1260 invalidateNested(); 1145 invalidateNested();
1261 else if ( doc && doc->parent() ) 1146 else if ( para->document() && para->document()->parent() )
1262 doc->nextDoubleBuffered = TRUE; 1147 para->document()->nextDoubleBuffered = TRUE;
1263 return FALSE; 1148 return FALSE;
1264 } else if ( string->next() ) { 1149 } else if ( para->next() ) {
1265 if ( string->length() == 1 ) { 1150 para->join( para->next() );
1266 string->next()->setPrev( string->prev() );
1267 if ( string->prev() )
1268 string->prev()->setNext( string->next() );
1269 QTextParag *p = string->next();
1270 delete string;
1271 string = p;
1272 string->invalidate( 0 );
1273 QTextParag *s = string;
1274 while ( s ) {
1275 s->id = s->p ? s->p->id + 1 : 0;
1276 s->state = -1;
1277 s->needPreProcess = TRUE;
1278 s->changed = TRUE;
1279 s = s->n;
1280 }
1281 string->format();
1282 } else {
1283 string->join( string->next() );
1284 }
1285 invalidateNested(); 1151 invalidateNested();
1286 return TRUE; 1152 return TRUE;
1287 } 1153 }
1288 return FALSE; 1154 return FALSE;
1289} 1155}
1290 1156
1291void QTextCursor::killLine()
1292{
1293 if ( atParagEnd() )
1294 return;
1295 string->remove( idx, string->length() - idx - 1 );
1296 int h = string->rect().height();
1297 string->format( -1, TRUE );
1298 if ( h != string->rect().height() )
1299 invalidateNested();
1300 else if ( doc && doc->parent() )
1301 doc->nextDoubleBuffered = TRUE;
1302}
1303
1304void QTextCursor::indent() 1157void QTextCursor::indent()
1305{ 1158{
1306 int oi = 0, ni = 0; 1159 int oi = 0, ni = 0;
1307 string->indent( &oi, &ni ); 1160 para->indent( &oi, &ni );
1308 if ( oi == ni ) 1161 if ( oi == ni )
1309 return; 1162 return;
1310 1163
1311 if ( idx >= oi ) 1164 if ( idx >= oi )
1312 idx += ni - oi; 1165 idx += ni - oi;
1313 else 1166 else
1314 idx = ni; 1167 idx = ni;
1315} 1168}
1316 1169
1317void QTextCursor::setDocument( QTextDocument *d )
1318{
1319 doc = d;
1320 string = d->firstParag();
1321 idx = 0;
1322 nested = FALSE;
1323 restoreState();
1324 tmpIndex = -1;
1325}
1326
1327// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1170// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1328 1171
1329QTextDocument::QTextDocument( QTextDocument *p ) 1172QTextDocument::QTextDocument( QTextDocument *p )
1330 : par( p ), parParag( 0 ), tc( 0 ), tArray( 0 ), tStopWidth( 0 ) 1173 : par( p ), parentPar( 0 ), tc( 0 ), tArray( 0 ), tStopWidth( 0 )
1331{ 1174{
1332 fCollection = new QTextFormatCollection; 1175 fCollection = new QTextFormatCollection;
1333 init(); 1176 init();
1334} 1177}
1335 1178
1336QTextDocument::QTextDocument( QTextDocument *p, QTextFormatCollection *f ) 1179QTextDocument::QTextDocument( QTextDocument *p, QTextFormatCollection *f )
1337 : par( p ), parParag( 0 ), tc( 0 ), tArray( 0 ), tStopWidth( 0 ) 1180 : par( p ), parentPar( 0 ), tc( 0 ), tArray( 0 ), tStopWidth( 0 )
1338{ 1181{
1339 fCollection = f; 1182 fCollection = f;
1340 init(); 1183 init();
1341} 1184}
1342 1185
1343void QTextDocument::init() 1186void QTextDocument::init()
1344{ 1187{
1345#if defined(PARSER_DEBUG)
1346 qDebug( debug_indent + "new QTextDocument (%p)", this );
1347#endif
1348 oTextValid = TRUE; 1188 oTextValid = TRUE;
1349 mightHaveCustomItems = FALSE; 1189 mightHaveCustomItems = FALSE;
1350 if ( par ) 1190 if ( par )
1351 par->insertChild( this ); 1191 par->insertChild( this );
1352 pProcessor = 0; 1192 pProcessor = 0;
1353 useFC = TRUE; 1193 useFC = TRUE;
@@ -1360,42 +1200,41 @@ void QTextDocument::init()
1360 focusIndicator.parag = 0; 1200 focusIndicator.parag = 0;
1361 minw = 0; 1201 minw = 0;
1362 wused = 0; 1202 wused = 0;
1363 minwParag = curParag = 0; 1203 minwParag = curParag = 0;
1364 align = AlignAuto; 1204 align = AlignAuto;
1365 nSelections = 1; 1205 nSelections = 1;
1366 addMargs = FALSE;
1367 1206
1368 sheet_ = QStyleSheet::defaultSheet(); 1207 setStyleSheet( QStyleSheet::defaultSheet() );
1369 factory_ = QMimeSourceFactory::defaultFactory(); 1208 factory_ = QMimeSourceFactory::defaultFactory();
1370 contxt = QString::null; 1209 contxt = QString::null;
1371 fCollection->setStyleSheet( sheet_ );
1372 1210
1373 underlLinks = par ? par->underlLinks : TRUE; 1211 underlLinks = par ? par->underlLinks : TRUE;
1374 backBrush = 0; 1212 backBrush = 0;
1375 buf_pixmap = 0; 1213 buf_pixmap = 0;
1376 nextDoubleBuffered = FALSE; 1214 nextDoubleBuffered = FALSE;
1377 1215
1378 if ( par ) 1216 if ( par )
1379 withoutDoubleBuffer = par->withoutDoubleBuffer; 1217 withoutDoubleBuffer = par->withoutDoubleBuffer;
1380 else 1218 else
1381 withoutDoubleBuffer = FALSE; 1219 withoutDoubleBuffer = FALSE;
1382 1220
1383 lParag = fParag = createParag( this, 0, 0 ); 1221 lParag = fParag = createParagraph( this, 0, 0 );
1384 tmpCursor = 0;
1385 1222
1386 cx = 0; 1223 cx = 0;
1387 cy = 2; 1224 cy = 2;
1388 if ( par ) 1225 if ( par )
1389 cx = cy = 0; 1226 cx = cy = 0;
1390 cw = 600; 1227 cw = 600;
1391 vw = 0; 1228 vw = 0;
1392 flow_ = new QTextFlow; 1229 flow_ = new QTextFlow;
1393 flow_->setWidth( cw ); 1230 flow_->setWidth( cw );
1394 1231
1395 leftmargin = rightmargin = 4; 1232 leftmargin = rightmargin = 4;
1233 scaleFontsFactor = 1;
1234
1396 1235
1397 selectionColors[ Standard ] = QApplication::palette().color( QPalette::Active, QColorGroup::Highlight ); 1236 selectionColors[ Standard ] = QApplication::palette().color( QPalette::Active, QColorGroup::Highlight );
1398 selectionText[ Standard ] = TRUE; 1237 selectionText[ Standard ] = TRUE;
1399 commandHistory = new QTextCommandHistory( 100 ); 1238 commandHistory = new QTextCommandHistory( 100 );
1400 tStopWidth = formatCollection()->defaultFormat()->width( 'x' ) * 8; 1239 tStopWidth = formatCollection()->defaultFormat()->width( 'x' ) * 8;
1401} 1240}
@@ -1420,20 +1259,22 @@ QTextDocument::~QTextDocument()
1420 1259
1421void QTextDocument::clear( bool createEmptyParag ) 1260void QTextDocument::clear( bool createEmptyParag )
1422{ 1261{
1423 if ( flow_ ) 1262 if ( flow_ )
1424 flow_->clear(); 1263 flow_->clear();
1425 while ( fParag ) { 1264 while ( fParag ) {
1426 QTextParag *p = fParag->next(); 1265 QTextParagraph *p = fParag->next();
1427 delete fParag; 1266 delete fParag;
1428 fParag = p; 1267 fParag = p;
1429 } 1268 }
1430 fParag = lParag = 0; 1269 fParag = lParag = 0;
1431 if ( createEmptyParag ) 1270 if ( createEmptyParag )
1432 fParag = lParag = createParag( this ); 1271 fParag = lParag = createParagraph( this );
1433 selections.clear(); 1272 selections.clear();
1273 oText = QString::null;
1274 oTextValid = TRUE;
1434} 1275}
1435 1276
1436int QTextDocument::widthUsed() const 1277int QTextDocument::widthUsed() const
1437{ 1278{
1438 return wused + border_tolerance; 1279 return wused + border_tolerance;
1439} 1280}
@@ -1446,18 +1287,18 @@ int QTextDocument::height() const
1446 int fh = flow_->boundingRect().bottom(); 1287 int fh = flow_->boundingRect().bottom();
1447 return QMAX( h, fh ); 1288 return QMAX( h, fh );
1448} 1289}
1449 1290
1450 1291
1451 1292
1452QTextParag *QTextDocument::createParag( QTextDocument *d, QTextParag *pr, QTextParag *nx, bool updateIds ) 1293QTextParagraph *QTextDocument::createParagraph( QTextDocument *d, QTextParagraph *pr, QTextParagraph *nx, bool updateIds )
1453{ 1294{
1454 return new QTextParag( d, pr, nx, updateIds ); 1295 return new QTextParagraph( d, pr, nx, updateIds );
1455} 1296}
1456 1297
1457bool QTextDocument::setMinimumWidth( int needed, int used, QTextParag *p ) 1298bool QTextDocument::setMinimumWidth( int needed, int used, QTextParagraph *p )
1458{ 1299{
1459 if ( needed == -1 ) { 1300 if ( needed == -1 ) {
1460 minw = 0; 1301 minw = 0;
1461 wused = 0; 1302 wused = 0;
1462 p = 0; 1303 p = 0;
1463 } 1304 }
@@ -1482,24 +1323,24 @@ void QTextDocument::setPlainText( const QString &text )
1482 oTextValid = TRUE; 1323 oTextValid = TRUE;
1483 oText = text; 1324 oText = text;
1484 1325
1485 int lastNl = 0; 1326 int lastNl = 0;
1486 int nl = text.find( '\n' ); 1327 int nl = text.find( '\n' );
1487 if ( nl == -1 ) { 1328 if ( nl == -1 ) {
1488 lParag = createParag( this, lParag, 0 ); 1329 lParag = createParagraph( this, lParag, 0 );
1489 if ( !fParag ) 1330 if ( !fParag )
1490 fParag = lParag; 1331 fParag = lParag;
1491 QString s = text; 1332 QString s = text;
1492 if ( !s.isEmpty() ) { 1333 if ( !s.isEmpty() ) {
1493 if ( s[ (int)s.length() - 1 ] == '\r' ) 1334 if ( s[ (int)s.length() - 1 ] == '\r' )
1494 s.remove( s.length() - 1, 1 ); 1335 s.remove( s.length() - 1, 1 );
1495 lParag->append( s ); 1336 lParag->append( s );
1496 } 1337 }
1497 } else { 1338 } else {
1498 for (;;) { 1339 for (;;) {
1499 lParag = createParag( this, lParag, 0 ); 1340 lParag = createParagraph( this, lParag, 0 );
1500 if ( !fParag ) 1341 if ( !fParag )
1501 fParag = lParag; 1342 fParag = lParag;
1502 QString s = text.mid( lastNl, nl - lastNl ); 1343 QString s = text.mid( lastNl, nl - lastNl );
1503 if ( !s.isEmpty() ) { 1344 if ( !s.isEmpty() ) {
1504 if ( s[ (int)s.length() - 1 ] == '\r' ) 1345 if ( s[ (int)s.length() - 1 ] == '\r' )
1505 s.remove( s.length() - 1, 1 ); 1346 s.remove( s.length() - 1, 1 );
@@ -1511,13 +1352,13 @@ void QTextDocument::setPlainText( const QString &text )
1511 nl = text.find( '\n', nl + 1 ); 1352 nl = text.find( '\n', nl + 1 );
1512 if ( nl == -1 ) 1353 if ( nl == -1 )
1513 nl = 0xffffff; 1354 nl = 0xffffff;
1514 } 1355 }
1515 } 1356 }
1516 if ( !lParag ) 1357 if ( !lParag )
1517 lParag = fParag = createParag( this, 0, 0 ); 1358 lParag = fParag = createParagraph( this, 0, 0 );
1518} 1359}
1519 1360
1520struct Q_EXPORT QTextDocumentTag { 1361struct Q_EXPORT QTextDocumentTag {
1521 QTextDocumentTag(){} 1362 QTextDocumentTag(){}
1522 QTextDocumentTag( const QString&n, const QStyleSheetItem* s, const QTextFormat& f ) 1363 QTextDocumentTag( const QString&n, const QStyleSheetItem* s, const QTextFormat& f )
1523 :name(n),style(s), format(f), alignment(Qt3::AlignAuto), direction(QChar::DirON),liststyle(QStyleSheetItem::ListDisc) { 1364 :name(n),style(s), format(f), alignment(Qt3::AlignAuto), direction(QChar::DirON),liststyle(QStyleSheetItem::ListDisc) {
@@ -1556,191 +1397,186 @@ struct Q_EXPORT QTextDocumentTag {
1556 1397
1557#if defined(Q_FULL_TEMPLATE_INSTANTIATION) 1398#if defined(Q_FULL_TEMPLATE_INSTANTIATION)
1558 bool operator==( const QTextDocumentTag& ) const { return FALSE; } 1399 bool operator==( const QTextDocumentTag& ) const { return FALSE; }
1559#endif 1400#endif
1560}; 1401};
1561 1402
1562#define NEWPAR do{ if ( !hasNewPar ) curpar = createParag( this, curpar ); \ 1403
1563 if ( curpar->isBr ) curpar->isBr = FALSE; \ 1404#define NEWPAR do{ if ( !hasNewPar) { \
1405 if ( !textEditMode && curpar && curpar->length()>1 && curpar->at( curpar->length()-2)->c == QChar_linesep ) \
1406 curpar->remove( curpar->length()-2, 1 ); \
1407 curpar = createParagraph( this, curpar, curpar->next() ); styles.append( vec ); vec = 0;} \
1564 hasNewPar = TRUE; \ 1408 hasNewPar = TRUE; \
1565 curpar->setAlignment( curtag.alignment ); \ 1409 curpar->rtext = TRUE; \
1566 curpar->setDirection( (QChar::Direction)curtag.direction ); \ 1410 curpar->align = curtag.alignment; \
1411 curpar->lstyle = curtag.liststyle; \
1412 curpar->litem = ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ); \
1413 curpar->str->setDirection( (QChar::Direction)curtag.direction ); \
1567 space = TRUE; \ 1414 space = TRUE; \
1568 QPtrVector<QStyleSheetItem> vec( (uint)tags.count() + 1); \ 1415 delete vec; vec = new QPtrVector<QStyleSheetItem>( (uint)tags.count() + 1); \
1569 int i = 0; \ 1416 int i = 0; \
1570 for ( QValueStack<QTextDocumentTag>::Iterator it = tags.begin(); it != tags.end(); ++it ) \ 1417 for ( QValueStack<QTextDocumentTag>::Iterator it = tags.begin(); it != tags.end(); ++it ) \
1571 vec.insert( i++, (*it).style ); \ 1418 vec->insert( i++, (*it).style ); \
1572 vec.insert( i, curtag.style ); \ 1419 vec->insert( i, curtag.style ); \
1573 curpar->setStyleSheetItems( vec ); }while(FALSE) 1420 }while(FALSE)
1574 1421
1575 1422
1576void QTextDocument::setRichText( const QString &text, const QString &context ) 1423void QTextDocument::setRichText( const QString &text, const QString &context )
1577{ 1424{
1578 setTextFormat( Qt::RichText );
1579 if ( !context.isEmpty() ) 1425 if ( !context.isEmpty() )
1580 setContext( context ); 1426 setContext( context );
1581 clear(); 1427 clear();
1582 fParag = lParag = createParag( this ); 1428 fParag = lParag = createParagraph( this );
1429 oTextValid = TRUE;
1430 oText = text;
1583 setRichTextInternal( text ); 1431 setRichTextInternal( text );
1432 fParag->rtext = TRUE;
1584} 1433}
1585 1434
1586static QStyleSheetItem::ListStyle chooseListStyle( const QStyleSheetItem *nstyle, 1435void QTextDocument::setRichTextInternal( const QString &text, QTextCursor* cursor )
1587 const QMap<QString, QString> &attr,
1588 QStyleSheetItem::ListStyle curListStyle )
1589{
1590 if ( nstyle->name() == "ol" || nstyle->name() == "ul" ) {
1591 curListStyle = nstyle->listStyle();
1592 QMap<QString, QString>::ConstIterator it = attr.find( "type" );
1593 if ( it != attr.end() ) {
1594 QString sl = *it;
1595 if ( sl == "1" ) {
1596 curListStyle = QStyleSheetItem::ListDecimal;
1597 } else if ( sl == "a" ) {
1598 curListStyle = QStyleSheetItem::ListLowerAlpha;
1599 } else if ( sl == "A" ) {
1600 curListStyle = QStyleSheetItem::ListUpperAlpha;
1601 } else {
1602 sl = sl.lower();
1603 if ( sl == "square" )
1604 curListStyle = QStyleSheetItem::ListSquare;
1605 else if ( sl == "disc" )
1606 curListStyle = QStyleSheetItem::ListDisc;
1607 else if ( sl == "circle" )
1608 curListStyle = QStyleSheetItem::ListCircle;
1609 }
1610 }
1611 }
1612 return curListStyle;
1613}
1614
1615void QTextDocument::setRichTextInternal( const QString &text )
1616{ 1436{
1617 oTextValid = TRUE; 1437 QTextParagraph* curpar = lParag;
1618 oText = text;
1619 QTextParag* curpar = lParag;
1620 int pos = 0; 1438 int pos = 0;
1621 QValueStack<QTextDocumentTag> tags; 1439 QValueStack<QTextDocumentTag> tags;
1622 QTextDocumentTag initag( "", sheet_->item(""), *formatCollection()->defaultFormat() ); 1440 QTextDocumentTag initag( "", sheet_->item(""), *formatCollection()->defaultFormat() );
1623 QTextDocumentTag curtag = initag; 1441 QTextDocumentTag curtag = initag;
1624 bool space = TRUE; 1442 bool space = TRUE;
1443 bool canMergeLi = FALSE;
1444
1445 bool textEditMode = FALSE;
1625 1446
1626 const QChar* doc = text.unicode(); 1447 const QChar* doc = text.unicode();
1627 int length = text.length(); 1448 int length = text.length();
1628 bool hasNewPar = curpar->length() <= 1; 1449 bool hasNewPar = curpar->length() <= 1;
1629 QString lastClose;
1630 QString anchorName; 1450 QString anchorName;
1451
1452 // style sheet handling for margin and line spacing calculation below
1453 QTextParagraph* stylesPar = curpar;
1454 QPtrVector<QStyleSheetItem>* vec = 0;
1455 QPtrList< QPtrVector<QStyleSheetItem> > styles;
1456 styles.setAutoDelete( TRUE );
1457
1458 if ( cursor ) {
1459 cursor->splitAndInsertEmptyParagraph();
1460 QTextCursor tmp = *cursor;
1461 tmp.gotoPreviousLetter();
1462 stylesPar = curpar = tmp.paragraph();
1463 hasNewPar = TRUE;
1464 textEditMode = TRUE;
1465 } else {
1466 NEWPAR;
1467 }
1468
1469 // set rtext spacing to FALSE for the initial paragraph.
1470 curpar->rtext = FALSE;
1471
1472 QString wellKnownTags = "br hr wsp table qt body meta title";
1473
1631 while ( pos < length ) { 1474 while ( pos < length ) {
1632 if ( hasPrefix(doc, length, pos, '<' ) ){ 1475 if ( hasPrefix(doc, length, pos, '<' ) ){
1633 if ( !hasPrefix( doc, length, pos+1, QChar('/') ) ) { 1476 if ( !hasPrefix( doc, length, pos+1, QChar('/') ) ) {
1634 // open tag 1477 // open tag
1635 QMap<QString, QString> attr; 1478 QMap<QString, QString> attr;
1636 bool emptyTag = FALSE; 1479 bool emptyTag = FALSE;
1637 QString tagname = parseOpenTag(doc, length, pos, attr, emptyTag); 1480 QString tagname = parseOpenTag(doc, length, pos, attr, emptyTag);
1638 if ( tagname.isEmpty() ) 1481 if ( tagname.isEmpty() )
1639 continue; // nothing we could do with this, probably parse error 1482 continue; // nothing we could do with this, probably parse error
1640 1483
1641 if ( tagname == "title" ) {
1642 QString title;
1643 while ( pos < length ) {
1644 if ( hasPrefix( doc, length, pos, QChar('<') ) && hasPrefix( doc, length, pos+1, QChar('/') ) &&
1645 parseCloseTag( doc, length, pos ) == "title" )
1646 break;
1647 title += doc[ pos ];
1648 ++pos;
1649 }
1650 attribs.replace( "title", title );
1651 }
1652
1653 const QStyleSheetItem* nstyle = sheet_->item(tagname); 1484 const QStyleSheetItem* nstyle = sheet_->item(tagname);
1654 1485
1655 if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
1656 // if ( tagname == "br" ) {
1657 // // our standard br emty-tag handling breaks
1658 // // inside list items, we would get another
1659 // // list item in this case. As workaround, fake
1660 // // a new paragraph instead
1661 // tagname = "p";
1662 // nstyle = sheet_->item( tagname );
1663 // }
1664 if ( nstyle )
1665 hasNewPar = FALSE; // we want empty paragraphs in this case
1666 }
1667
1668 if ( nstyle ) { 1486 if ( nstyle ) {
1669 // we might have to close some 'forgotten' tags 1487 // we might have to close some 'forgotten' tags
1670 while ( !nstyle->allowedInContext( curtag.style ) ) { 1488 while ( !nstyle->allowedInContext( curtag.style ) ) {
1671 QString msg; 1489 QString msg;
1672 msg.sprintf( "QText Warning: Document not valid ( '%s' not allowed in '%s' #%d)", 1490 msg.sprintf( "QText Warning: Document not valid ( '%s' not allowed in '%s' #%d)",
1673 tagname.ascii(), curtag.style->name().ascii(), pos); 1491 tagname.ascii(), curtag.style->name().ascii(), pos);
1674 sheet_->error( msg ); 1492 sheet_->error( msg );
1675 if ( tags.isEmpty() ) 1493 if ( tags.isEmpty() )
1676 break; 1494 break;
1677 curtag = tags.pop(); 1495 curtag = tags.pop();
1678 } 1496 }
1679 1497
1680 // special handling for p. We do not want to nest there for HTML compatibility 1498 /* special handling for p and li for HTML
1681 if ( nstyle->displayMode() == QStyleSheetItem::DisplayBlock ) { 1499 compatibility. We do not want to embed blocks in
1500 p, and we do not want new blocks inside non-empty
1501 lis. Plus we want to merge empty lis sometimes. */
1502 if( nstyle->displayMode() == QStyleSheetItem::DisplayListItem ) {
1503 canMergeLi = TRUE;
1504 } else if ( nstyle->displayMode() == QStyleSheetItem::DisplayBlock ) {
1682 while ( curtag.style->name() == "p" ) { 1505 while ( curtag.style->name() == "p" ) {
1683 if ( tags.isEmpty() ) 1506 if ( tags.isEmpty() )
1684 break; 1507 break;
1685 curtag = tags.pop(); 1508 curtag = tags.pop();
1686 } 1509 }
1687 }
1688 1510
1511 if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
1512 // we are in a li and a new block comes along
1513 if ( nstyle->name() == "ul" || nstyle->name() == "ol" )
1514 hasNewPar = FALSE; // we want an empty li (like most browsers)
1515 if ( !hasNewPar ) {
1516 /* do not add new blocks inside
1517 non-empty lis */
1518 while ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
1519 if ( tags.isEmpty() )
1520 break;
1521 curtag = tags.pop();
1522 }
1523 } else if ( canMergeLi ) {
1524 /* we have an empty li and a block
1525 comes along, merge them */
1526 nstyle = curtag.style;
1527 }
1528 canMergeLi = FALSE;
1529 }
1530 }
1689 } 1531 }
1690 1532
1691 QTextCustomItem* custom = 0; 1533 QTextCustomItem* custom = 0;
1692 // some well-known empty tags 1534
1693 if ( tagname == "br" ) { 1535 // some well-known tags, some have a nstyle, some not
1694 emptyTag = TRUE; 1536 if ( wellKnownTags.find( tagname ) != -1 ) {
1695 hasNewPar = FALSE; 1537 if ( tagname == "br" ) {
1696 if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) { 1538 emptyTag = space = TRUE;
1697 // when linebreaking a list item, we do not 1539 int index = QMAX( curpar->length(),1) - 1;
1698 // actually want a new list item but just a 1540 QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
1699 // new line. Fake this by pushing a paragraph 1541 curpar->append( QChar_linesep );
1700 // onto the stack 1542 curpar->setFormat( index, 1, &format );
1701 tags.push( curtag ); 1543 } else if ( tagname == "hr" ) {
1702 curtag.name = tagname; 1544 emptyTag = space = TRUE;
1703 curtag.style = nstyle; 1545 custom = sheet_->tag( tagname, attr, contxt, *factory_ , emptyTag, this );
1704 } 1546 NEWPAR;
1705 NEWPAR; 1547 } else if ( tagname == "table" ) {
1706 curpar->isBr = TRUE; 1548 emptyTag = space = TRUE;
1707 curpar->setAlignment( curtag.alignment ); 1549 QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
1708 } else if ( tagname == "hr" ) { 1550 curpar->setAlignment( curtag.alignment );
1709 emptyTag = TRUE; 1551 custom = parseTable( attr, format, doc, length, pos, curpar );
1710 custom = sheet_->tag( tagname, attr, contxt, *factory_ , emptyTag, this ); 1552 } else if ( tagname == "qt" || tagname == "body" ) {
1711 NEWPAR; 1553 if ( attr.contains( "bgcolor" ) ) {
1712 } else if ( tagname == "table" ) { 1554 QBrush *b = new QBrush( QColor( attr["bgcolor"] ) );
1713 QTextFormat format = curtag.format.makeTextFormat( nstyle, attr );
1714 curpar->setAlignment( curtag.alignment );
1715 custom = parseTable( attr, format, doc, length, pos, curpar );
1716 (void)eatSpace( doc, length, pos );
1717 emptyTag = TRUE;
1718 } else if ( tagname == "qt" ) {
1719 for ( QMap<QString, QString>::Iterator it = attr.begin(); it != attr.end(); ++it ) {
1720 if ( it.key() == "bgcolor" ) {
1721 QBrush *b = new QBrush( QColor( *it ) );
1722 setPaper( b ); 1555 setPaper( b );
1723 } else if ( it.key() == "background" ) { 1556 }
1557 if ( attr.contains( "background" ) ) {
1724 QImage img; 1558 QImage img;
1725 const QMimeSource* m = factory_->data( *it, contxt ); 1559 QString bg = attr["background"];
1560 const QMimeSource* m = factory_->data( bg, contxt );
1726 if ( !m ) { 1561 if ( !m ) {
1727 qWarning("QRichText: no mimesource for %s", (*it).latin1() ); 1562 qWarning("QRichText: no mimesource for %s", bg.latin1() );
1728 } else { 1563 } else {
1729 if ( !QImageDrag::decode( m, img ) ) { 1564 if ( !QImageDrag::decode( m, img ) ) {
1730 qWarning("QTextImage: cannot decode %s", (*it).latin1() ); 1565 qWarning("QTextImage: cannot decode %s", bg.latin1() );
1731 } 1566 }
1732 } 1567 }
1733 if ( !img.isNull() ) { 1568 if ( !img.isNull() ) {
1734 QPixmap pm; 1569 QPixmap pm;
1735 pm.convertFromImage( img ); 1570 pm.convertFromImage( img );
1736 QBrush *b = new QBrush( QColor(), pm ); 1571 QBrush *b = new QBrush( QColor(), pm );
1737 setPaper( b ); 1572 setPaper( b );
1738 } 1573 }
1739 } else if ( it.key() == "text" ) { 1574 }
1740 QColor c( *it ); 1575 if ( attr.contains( "text" ) ) {
1576 QColor c( attr["text"] );
1741 if ( formatCollection()->defaultFormat()->color() != c ) { 1577 if ( formatCollection()->defaultFormat()->color() != c ) {
1742 QDict<QTextFormat> formats = formatCollection()->dict(); 1578 QDict<QTextFormat> formats = formatCollection()->dict();
1743 QDictIterator<QTextFormat> it( formats ); 1579 QDictIterator<QTextFormat> it( formats );
1744 while ( it.current() ) { 1580 while ( it.current() ) {
1745 if ( it.current() == formatCollection()->defaultFormat() ) { 1581 if ( it.current() == formatCollection()->defaultFormat() ) {
1746 ++it; 1582 ++it;
@@ -1749,141 +1585,200 @@ void QTextDocument::setRichTextInternal( const QString &text )
1749 it.current()->setColor( c ); 1585 it.current()->setColor( c );
1750 ++it; 1586 ++it;
1751 } 1587 }
1752 formatCollection()->defaultFormat()->setColor( c ); 1588 formatCollection()->defaultFormat()->setColor( c );
1753 curtag.format.setColor( c ); 1589 curtag.format.setColor( c );
1754 } 1590 }
1755 } else if ( it.key() == "link" ) {
1756 linkColor = QColor( *it );
1757 } else if ( it.key() == "title" ) {
1758 attribs.replace( it.key(), *it );
1759 } 1591 }
1592 if ( attr.contains( "link" ) )
1593 linkColor = QColor( attr["link"] );
1594 if ( attr.contains( "title" ) )
1595 attribs.replace( "title", attr["title"] );
1596
1597 if ( textEditMode ) {
1598 if ( attr.contains("style" ) ) {
1599 QString a = attr["style"];
1600 for ( int s = 0; s < a.contains(';')+1; s++ ) {
1601 QString style = QTextDocument::section( a, ";", s, s );
1602 if ( style.startsWith("font-size:" ) && QTextDocument::endsWith(style, "pt") ) {
1603 scaleFontsFactor = double( formatCollection()->defaultFormat()->fn.pointSize() ) /
1604 style.mid( 10, style.length() - 12 ).toInt();
1605 }
1606 }
1607 }
1608 nstyle = 0; // ignore body in textEditMode
1609 }
1610 // end qt- and body-tag handling
1611 } else if ( tagname == "meta" ) {
1612 if ( attr["name"] == "qrichtext" && attr["content"] == "1" )
1613 textEditMode = TRUE;
1614 } else if ( tagname == "title" ) {
1615 QString title;
1616 while ( pos < length ) {
1617 if ( hasPrefix( doc, length, pos, QChar('<') ) && hasPrefix( doc, length, pos+1, QChar('/') ) &&
1618 parseCloseTag( doc, length, pos ) == "title" )
1619 break;
1620 title += doc[ pos ];
1621 ++pos;
1622 }
1623 attribs.replace( "title", title );
1760 } 1624 }
1761 } else { 1625 } // end of well-known tag handling
1626
1627 if ( !custom ) // try generic custom item
1762 custom = sheet_->tag( tagname, attr, contxt, *factory_ , emptyTag, this ); 1628 custom = sheet_->tag( tagname, attr, contxt, *factory_ , emptyTag, this );
1763 }
1764 1629
1765 if ( !nstyle && !custom ) // we have no clue what this tag could be, ignore it 1630 if ( !nstyle && !custom ) // we have no clue what this tag could be, ignore it
1766 continue; 1631 continue;
1767 1632
1768 if ( custom ) { 1633 if ( custom ) {
1769 int index = curpar->length() - 1; 1634 int index = QMAX( curpar->length(),1) - 1;
1770 if ( index < 0 ) 1635 QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
1771 index = 0;
1772 QTextFormat format = curtag.format.makeTextFormat( nstyle, attr );
1773 curpar->append( QChar('*') ); 1636 curpar->append( QChar('*') );
1774 curpar->setFormat( index, 1, &format ); 1637 curpar->setFormat( index, 1, &format );
1775 curpar->at( index )->setCustomItem( custom ); 1638 curpar->at( index )->setCustomItem( custom );
1776 if ( !curtag.anchorHref.isEmpty() ) 1639 if ( !curtag.anchorHref.isEmpty() )
1777 curpar->at(index)->setAnchor( QString::null, curtag.anchorHref ); 1640 curpar->at(index)->setAnchor( QString::null, curtag.anchorHref );
1778 if ( !anchorName.isEmpty() ) { 1641 if ( !anchorName.isEmpty() ) {
1779 curpar->at(index)->setAnchor( anchorName, curpar->at(index)->anchorHref() ); 1642 curpar->at(index)->setAnchor( anchorName, curpar->at(index)->anchorHref() );
1780 anchorName = QString::null; 1643 anchorName = QString::null;
1781 } 1644 }
1782 registerCustomItem( custom, curpar ); 1645 registerCustomItem( custom, curpar );
1783 hasNewPar = FALSE; 1646 hasNewPar = FALSE;
1784 } else if ( !emptyTag ) { 1647 } else if ( !emptyTag ) {
1785 // ignore whitespace for inline elements if there was already one 1648 /* if we do nesting, push curtag on the stack,
1786 if ( nstyle->whiteSpaceMode() == QStyleSheetItem::WhiteSpaceNormal 1649 otherwise reinint curag. */
1787 && ( space || nstyle->displayMode() != QStyleSheetItem::DisplayInline ) ) 1650 if ( curtag.style->name() != tagname || nstyle->selfNesting() ) {
1788 eatSpace( doc, length, pos );
1789
1790 // if we do nesting, push curtag on the stack,
1791 // otherwise reinint curag.
1792 if ( nstyle != curtag.style || nstyle->selfNesting() ) {
1793 tags.push( curtag ); 1651 tags.push( curtag );
1794 } else { 1652 } else {
1795 if ( !tags.isEmpty() ) 1653 if ( !tags.isEmpty() )
1796 curtag = tags.top(); 1654 curtag = tags.top();
1797 else 1655 else
1798 curtag = initag; 1656 curtag = initag;
1799 } 1657 }
1800 1658
1801 const QStyleSheetItem* ostyle = curtag.style;
1802
1803 curtag.name = tagname; 1659 curtag.name = tagname;
1804 curtag.style = nstyle; 1660 curtag.style = nstyle;
1805 curtag.name = tagname; 1661 curtag.name = tagname;
1806 curtag.style = nstyle; 1662 curtag.style = nstyle;
1807 if ( nstyle->whiteSpaceMode() != QStyleSheetItem::WhiteSpaceNormal ) 1663 if ( int(nstyle->whiteSpaceMode()) != QStyleSheetItem::Undefined )
1808 curtag.wsm = nstyle->whiteSpaceMode(); 1664 curtag.wsm = nstyle->whiteSpaceMode();
1809 curtag.liststyle = chooseListStyle( nstyle, attr, curtag.liststyle ); 1665
1810 curtag.format = curtag.format.makeTextFormat( nstyle, attr ); 1666 /* ignore whitespace for inline elements if there
1667 was already one*/
1668 if ( !textEditMode && curtag.wsm == QStyleSheetItem::WhiteSpaceNormal
1669 && ( space || nstyle->displayMode() != QStyleSheetItem::DisplayInline ) )
1670 eatSpace( doc, length, pos );
1671
1672 curtag.format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
1811 if ( nstyle->isAnchor() ) { 1673 if ( nstyle->isAnchor() ) {
1812 if ( !anchorName.isEmpty() ) 1674 if ( !anchorName.isEmpty() )
1813 anchorName += "#" + attr["name"]; 1675 anchorName += "#" + attr["name"];
1814 else 1676 else
1815 anchorName = attr["name"]; 1677 anchorName = attr["name"];
1816 curtag.anchorHref = attr["href"]; 1678 curtag.anchorHref = attr["href"];
1817 } 1679 }
1818 1680
1819 if ( nstyle->alignment() != QStyleSheetItem::Undefined ) 1681 if ( nstyle->alignment() != QStyleSheetItem::Undefined )
1820 curtag.alignment = nstyle->alignment(); 1682 curtag.alignment = nstyle->alignment();
1821 1683
1822 if ( ostyle->displayMode() == QStyleSheetItem::DisplayListItem && 1684 if ( (int) nstyle->listStyle() != QStyleSheetItem::Undefined )
1823 curpar->length() <= 1 1685 curtag.liststyle = nstyle->listStyle();
1824 && nstyle->displayMode() == QStyleSheetItem::DisplayBlock ) { 1686
1825 // do not do anything, we reuse the paragraph we have 1687 if ( nstyle->displayMode() == QStyleSheetItem::DisplayBlock
1826 } else if ( nstyle->displayMode() != QStyleSheetItem::DisplayInline && nstyle->displayMode() != QStyleSheetItem::DisplayNone ) { 1688 || nstyle->displayMode() == QStyleSheetItem::DisplayListItem ) {
1689
1690 if ( nstyle->name() == "ol" || nstyle->name() == "ul" || nstyle->name() == "li") {
1691 QString type = attr["type"];
1692 if ( !type.isEmpty() ) {
1693 if ( type == "1" ) {
1694 curtag.liststyle = QStyleSheetItem::ListDecimal;
1695 } else if ( type == "a" ) {
1696 curtag.liststyle = QStyleSheetItem::ListLowerAlpha;
1697 } else if ( type == "A" ) {
1698 curtag.liststyle = QStyleSheetItem::ListUpperAlpha;
1699 } else {
1700 type = type.lower();
1701 if ( type == "square" )
1702 curtag.liststyle = QStyleSheetItem::ListSquare;
1703 else if ( type == "disc" )
1704 curtag.liststyle = QStyleSheetItem::ListDisc;
1705 else if ( type == "circle" )
1706 curtag.liststyle = QStyleSheetItem::ListCircle;
1707 }
1708 }
1709 }
1710
1711
1712 /* Internally we treat ordered and bullet
1713 lists the same for margin calculations. In
1714 order to have fast pointer compares in the
1715 xMargin() functions we restrict ourselves to
1716 <ol>. Once we calculate the margins in the
1717 parser rathern than later, the unelegance of
1718 this approach goes awy
1719 */
1720 if ( nstyle->name() == "ul" )
1721 curtag.style = sheet_->item( "ol" );
1722
1723 if ( attr.contains( "align" ) ) {
1724 QString align = attr["align"];
1725 if ( align == "center" )
1726 curtag.alignment = Qt::AlignCenter;
1727 else if ( align == "right" )
1728 curtag.alignment = Qt::AlignRight;
1729 else if ( align == "justify" )
1730 curtag.alignment = Qt3::AlignJustify;
1731 }
1732 if ( attr.contains( "dir" ) ) {
1733 QString dir = attr["dir"];
1734 if ( dir == "rtl" )
1735 curtag.direction = QChar::DirR;
1736 else if ( dir == "ltr" )
1737 curtag.direction = QChar::DirL;
1738 }
1739
1827 NEWPAR; 1740 NEWPAR;
1828 }
1829 1741
1830 if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) { 1742 if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
1831 curpar->setListStyle( curtag.liststyle ); 1743 if ( attr.contains( "value " ) )
1832 if ( attr.find( "value" ) != attr.end() ) 1744 curpar->setListValue( attr["value"].toInt() );
1833 curpar->setListValue( (*attr.find( "value" )).toInt() ); 1745 }
1834 }
1835 1746
1836 if ( nstyle->displayMode() != QStyleSheetItem::DisplayInline ) 1747 if ( attr.contains( "style" ) ) {
1837 curpar->setFormat( &curtag.format ); 1748 QString a = attr["style"];
1838 1749 bool ok = TRUE;
1839 if ( attr.contains( "align" ) && 1750 for ( int s = 0; ok && s < a.contains(';')+1; s++ ) {
1840 ( curtag.name == "p" || 1751 QString style = QTextDocument::section( a, ";", s, s );
1841 curtag.name == "div" || 1752 if ( style.startsWith("margin-top:" ) && QTextDocument::endsWith(style, "px") )
1842 curtag.name == "li" || 1753 curpar->utm = 1+style.mid(11, style.length() - 13).toInt(&ok);
1843 curtag.name[ 0 ] == 'h' ) ) { 1754 else if ( style.startsWith("margin-bottom:" ) && QTextDocument::endsWith(style, "px") )
1844 QString align = attr["align"]; 1755 curpar->ubm = 1+style.mid(14, style.length() - 16).toInt(&ok);
1845 if ( align == "center" ) 1756 else if ( style.startsWith("margin-left:" ) && QTextDocument::endsWith(style, "px") )
1846 curtag.alignment = Qt::AlignCenter; 1757 curpar->ulm = 1+style.mid(12, style.length() - 14).toInt(&ok);
1847 else if ( align == "right" ) 1758 else if ( style.startsWith("margin-right:" ) && QTextDocument::endsWith(style, "px") )
1848 curtag.alignment = Qt::AlignRight; 1759 curpar->urm = 1+style.mid(13, style.length() - 15).toInt(&ok);
1849 else if ( align == "justify" ) 1760 else if ( style.startsWith("text-indent:" ) && QTextDocument::endsWith(style, "px") )
1850 curtag.alignment = Qt3::AlignJustify; 1761 curpar->uflm = 1+style.mid(12, style.length() - 14).toInt(&ok);
1851 } 1762 }
1852 if ( attr.contains( "dir" ) && 1763 if ( !ok ) // be pressmistic
1853 ( curtag.name == "p" || 1764 curpar->utm = curpar->ubm = curpar->urm = curpar->ulm = 0;
1854 curtag.name == "div" || 1765 }
1855 curtag.name == "li" ||
1856 curtag.name[ 0 ] == 'h' ) ) {
1857 QString dir = attr["dir"];
1858 if ( dir == "rtl" )
1859 curtag.direction = QChar::DirR;
1860 else if ( dir == "ltr" )
1861 curtag.direction = QChar::DirL;
1862 }
1863 if ( nstyle->displayMode() != QStyleSheetItem::DisplayInline ) {
1864 curpar->setAlignment( curtag.alignment );
1865 curpar->setDirection( (QChar::Direction)curtag.direction );
1866 } 1766 }
1867 } 1767 }
1868 } else { 1768 } else {
1869 QString tagname = parseCloseTag( doc, length, pos ); 1769 QString tagname = parseCloseTag( doc, length, pos );
1870 lastClose = tagname;
1871 if ( tagname.isEmpty() ) 1770 if ( tagname.isEmpty() )
1872 continue; // nothing we could do with this, probably parse error 1771 continue; // nothing we could do with this, probably parse error
1873 if ( !sheet_->item( tagname ) ) // ignore unknown tags 1772 if ( !sheet_->item( tagname ) ) // ignore unknown tags
1874 continue; 1773 continue;
1875 1774
1876
1877 // we close a block item. Since the text may continue, we need to have a new paragraph 1775 // we close a block item. Since the text may continue, we need to have a new paragraph
1878 bool needNewPar = curtag.style->displayMode() == QStyleSheetItem::DisplayBlock; 1776 bool needNewPar = curtag.style->displayMode() == QStyleSheetItem::DisplayBlock
1777 || curtag.style->displayMode() == QStyleSheetItem::DisplayListItem;
1879 1778
1880 if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
1881 needNewPar = TRUE;
1882 hasNewPar = FALSE; // we want empty paragraphs in this case
1883 }
1884 1779
1885 // html slopiness: handle unbalanched tag closing 1780 // html slopiness: handle unbalanched tag closing
1886 while ( curtag.name != tagname ) { 1781 while ( curtag.name != tagname ) {
1887 QString msg; 1782 QString msg;
1888 msg.sprintf( "QText Warning: Document not valid ( '%s' not closed before '%s' #%d)", 1783 msg.sprintf( "QText Warning: Document not valid ( '%s' not closed before '%s' #%d)",
1889 curtag.name.ascii(), tagname.ascii(), pos); 1784 curtag.name.ascii(), tagname.ascii(), pos);
@@ -1898,49 +1793,69 @@ void QTextDocument::setRichTextInternal( const QString &text )
1898 if ( !tags.isEmpty() ) 1793 if ( !tags.isEmpty() )
1899 curtag = tags.pop(); 1794 curtag = tags.pop();
1900 else 1795 else
1901 curtag = initag; 1796 curtag = initag;
1902 1797
1903 if ( needNewPar ) { 1798 if ( needNewPar ) {
1904 if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) { 1799 if ( textEditMode && tagname == "p" ) // preserve empty paragraphs
1905 tags.push( curtag ); 1800 hasNewPar = FALSE;
1906 curtag.name = "p";
1907 curtag.style = sheet_->item( curtag.name ); // a list item continues, use p for that
1908 }
1909 NEWPAR; 1801 NEWPAR;
1910 } 1802 }
1911 } 1803 }
1912 } else { 1804 } else {
1913 // normal contents 1805 // normal contents
1914 QString s; 1806 QString s;
1915 QChar c; 1807 QChar c;
1916 while ( pos < length && !hasPrefix(doc, length, pos, QChar('<') ) ){ 1808 while ( pos < length && !hasPrefix(doc, length, pos, QChar('<') ) ){
1917 QStyleSheetItem::WhiteSpaceMode wsm = curtag.wsm; 1809 if ( textEditMode ) {
1918 if ( s.length() > 4096 ) 1810 // text edit mode: we handle all white space but ignore newlines
1919 wsm = (QStyleSheetItem::WhiteSpaceMode)QStyleSheetItem_WhiteSpaceNormalWithNewlines; 1811 c = parseChar( doc, length, pos, QStyleSheetItem::WhiteSpacePre );
1920 1812 if ( c == QChar_linesep )
1921 c = parseChar( doc, length, pos, wsm ); 1813 break;
1814 } else {
1815 int l = pos;
1816 c = parseChar( doc, length, pos, curtag.wsm );
1817
1818 // in white space pre mode: treat any space as non breakable
1819 if ( c == ' ' && curtag.wsm == QStyleSheetItem::WhiteSpacePre )
1820 c = QChar::nbsp;
1821
1822 if ( c == ' ' || c == QChar_linesep ) {
1823 /* avoid overlong paragraphs by forcing a new
1824 paragraph after 4096 characters. This case can
1825 occur when loading undiscovered plain text
1826 documents in rich text mode. Instead of hanging
1827 forever, we do the trick.
1828 */
1829 if ( curtag.wsm == QStyleSheetItem::WhiteSpaceNormal && s.length() > 4096 ) do {
1830 if ( doc[l] == '\n' ) {
1831 hasNewPar = FALSE; // for a new paragraph ...
1832 NEWPAR;
1833 hasNewPar = FALSE; // ... and make it non-reusable
1834 c = '\n'; // make sure we break below
1835 break;
1836 }
1837 } while ( ++l < pos );
1838 }
1839 }
1922 1840
1923 if ( c == '\n' ) // happens only in whitespacepre-mode or with WhiteSpaceNormalWithNewlines. 1841 if ( c == '\n' )
1924 break; // we want a new line in this case 1842 break; // break on newlines, pre delievers a QChar_linesep
1925 1843
1926 bool c_isSpace = c.isSpace() && c.unicode() != 0x00a0U && 1844 bool c_isSpace = c.isSpace() && c.unicode() != 0x00a0U && !textEditMode;
1927 curtag.wsm != QStyleSheetItem_WhiteSpaceNoCompression;
1928 1845
1929 if ( curtag.wsm == QStyleSheetItem::WhiteSpaceNormal && c_isSpace && space ) 1846 if ( curtag.wsm == QStyleSheetItem::WhiteSpaceNormal && c_isSpace && space )
1930 continue; 1847 continue;
1931 if ( c == '\r' ) 1848 if ( c == '\r' )
1932 continue; 1849 continue;
1933 space = c_isSpace; 1850 space = c_isSpace;
1934 s += c; 1851 s += c;
1935 } 1852 }
1936 if ( !s.isEmpty() && curtag.style->displayMode() != QStyleSheetItem::DisplayNone ) { 1853 if ( !s.isEmpty() && curtag.style->displayMode() != QStyleSheetItem::DisplayNone ) {
1937 hasNewPar = FALSE; 1854 hasNewPar = FALSE;
1938 int index = curpar->length() - 1; 1855 int index = QMAX( curpar->length(),1) - 1;
1939 if ( index < 0 )
1940 index = 0;
1941 curpar->append( s ); 1856 curpar->append( s );
1942 QTextFormat* f = formatCollection()->format( &curtag.format ); 1857 QTextFormat* f = formatCollection()->format( &curtag.format );
1943 curpar->setFormat( index, s.length(), f, FALSE ); // do not use collection because we have done that already 1858 curpar->setFormat( index, s.length(), f, FALSE ); // do not use collection because we have done that already
1944 f->ref += s.length() -1; // that what friends are for... 1859 f->ref += s.length() -1; // that what friends are for...
1945 if ( !curtag.anchorHref.isEmpty() ) { 1860 if ( !curtag.anchorHref.isEmpty() ) {
1946 for ( int i = 0; i < int(s.length()); i++ ) 1861 for ( int i = 0; i < int(s.length()); i++ )
@@ -1948,31 +1863,185 @@ void QTextDocument::setRichTextInternal( const QString &text )
1948 } 1863 }
1949 if ( !anchorName.isEmpty() ) { 1864 if ( !anchorName.isEmpty() ) {
1950 curpar->at(index)->setAnchor( anchorName, curpar->at(index)->anchorHref() ); 1865 curpar->at(index)->setAnchor( anchorName, curpar->at(index)->anchorHref() );
1951 anchorName = QString::null; 1866 anchorName = QString::null;
1952 } 1867 }
1953 } 1868 }
1954 if ( c == '\n' ) { // happens in WhiteSpacePre mode
1955 hasNewPar = FALSE;
1956 tags.push( curtag );
1957 NEWPAR;
1958 curtag = tags.pop();
1959 }
1960 } 1869 }
1961 } 1870 }
1962 1871 if ( hasNewPar && curpar != fParag && !cursor ) {
1963 if ( hasNewPar && curpar != fParag ) {
1964 // cleanup unused last paragraphs 1872 // cleanup unused last paragraphs
1965 curpar = curpar->p; 1873 curpar = curpar->p;
1966 delete curpar->n; 1874 delete curpar->n;
1967 } 1875 }
1968
1969 if ( !anchorName.isEmpty() ) { 1876 if ( !anchorName.isEmpty() ) {
1970 curpar->at(curpar->length() - 1)->setAnchor( anchorName, curpar->at( curpar->length() - 1 )->anchorHref() ); 1877 curpar->at(curpar->length() - 1)->setAnchor( anchorName, curpar->at( curpar->length() - 1 )->anchorHref() );
1971 anchorName = QString::null; 1878 anchorName = QString::null;
1972 } 1879 }
1880
1881
1882 setRichTextMarginsInternal( styles, stylesPar );
1883
1884 if ( cursor ) {
1885 cursor->gotoPreviousLetter();
1886 cursor->remove();
1887 }
1888
1889}
1890
1891void QTextDocument::setRichTextMarginsInternal( QPtrList< QPtrVector<QStyleSheetItem> >& styles, QTextParagraph* stylesPar )
1892{
1893 // margin and line spacing calculation
1894 QPtrVector<QStyleSheetItem>* prevStyle = 0;
1895 QPtrVector<QStyleSheetItem>* curStyle = styles.first();
1896 QPtrVector<QStyleSheetItem>* nextStyle = styles.next();
1897 while ( stylesPar ) {
1898 if ( !curStyle ) {
1899 stylesPar = stylesPar->next();
1900 prevStyle = curStyle;
1901 curStyle = nextStyle;
1902 nextStyle = styles.next();
1903 continue;
1904 }
1905
1906 int i, mar;
1907 QStyleSheetItem* mainStyle = curStyle->size() ? (*curStyle)[curStyle->size()-1] : 0;
1908 if ( mainStyle && mainStyle->displayMode() == QStyleSheetItem::DisplayListItem )
1909 stylesPar->setListItem( TRUE );
1910 int numLists = 0;
1911 for ( i = 0; i < (int)curStyle->size(); ++i ) {
1912 if ( (*curStyle)[ i ]->displayMode() == QStyleSheetItem::DisplayBlock
1913 && int((*curStyle)[ i ]->listStyle()) != QStyleSheetItem::Undefined )
1914 numLists++;
1915 }
1916 stylesPar->ldepth = numLists;
1917 if ( stylesPar->next() && nextStyle ) {
1918 // also set the depth of the next paragraph, required for the margin calculation
1919 numLists = 0;
1920 for ( i = 0; i < (int)nextStyle->size(); ++i ) {
1921 if ( (*nextStyle)[ i ]->displayMode() == QStyleSheetItem::DisplayBlock
1922 && int((*nextStyle)[ i ]->listStyle()) != QStyleSheetItem::Undefined )
1923 numLists++;
1924 }
1925 stylesPar->next()->ldepth = numLists;
1926 }
1927
1928 // do the top margin
1929 QStyleSheetItem* item = mainStyle;
1930 int m;
1931 if (stylesPar->utm > 0 ) {
1932 m = stylesPar->utm-1;
1933 stylesPar->utm = 0;
1934 } else {
1935 m = QMAX(0, item->margin( QStyleSheetItem::MarginTop ) );
1936 if ( item->displayMode() == QStyleSheetItem::DisplayListItem
1937 && stylesPar->ldepth )
1938 m /= stylesPar->ldepth;
1939 }
1940 for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
1941 item = (*curStyle)[ i ];
1942 if ( prevStyle && i < (int) prevStyle->size() &&
1943 ( item->displayMode() == QStyleSheetItem::DisplayBlock &&
1944 (*prevStyle)[ i ] == item ) )
1945 break;
1946 // emulate CSS2' standard 0 vertical margin for multiple ul or ol tags
1947 if ( int(item->listStyle()) != QStyleSheetItem::Undefined &&
1948 ( ( i> 0 && (*curStyle)[ i-1 ] == item ) || (*curStyle)[i+1] == item ) )
1949 continue;
1950 mar = QMAX( 0, item->margin( QStyleSheetItem::MarginTop ) );
1951 m = QMAX( m, mar );
1952 }
1953 stylesPar->utm = m - stylesPar->topMargin();
1954
1955 // do the bottom margin
1956 item = mainStyle;
1957 if (stylesPar->ubm > 0 ) {
1958 m = stylesPar->ubm-1;
1959 stylesPar->ubm = 0;
1960 } else {
1961 m = QMAX(0, item->margin( QStyleSheetItem::MarginBottom ) );
1962 if ( item->displayMode() == QStyleSheetItem::DisplayListItem
1963 && stylesPar->ldepth )
1964 m /= stylesPar->ldepth;
1965 }
1966 for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
1967 item = (*curStyle)[ i ];
1968 if ( nextStyle && i < (int) nextStyle->size() &&
1969 ( item->displayMode() == QStyleSheetItem::DisplayBlock &&
1970 (*nextStyle)[ i ] == item ) )
1971 break;
1972 // emulate CSS2' standard 0 vertical margin for multiple ul or ol tags
1973 if ( int(item->listStyle()) != QStyleSheetItem::Undefined &&
1974 ( ( i> 0 && (*curStyle)[ i-1 ] == item ) || (*curStyle)[i+1] == item ) )
1975 continue;
1976 mar = QMAX(0, item->margin( QStyleSheetItem::MarginBottom ) );
1977 m = QMAX( m, mar );
1978 }
1979 stylesPar->ubm = m - stylesPar->bottomMargin();
1980
1981 // do the left margin, simplyfied
1982 item = mainStyle;
1983 if (stylesPar->ulm > 0 ) {
1984 m = stylesPar->ulm-1;
1985 stylesPar->ulm = 0;
1986 } else {
1987 m = QMAX( 0, item->margin( QStyleSheetItem::MarginLeft ) );
1988 }
1989 for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
1990 item = (*curStyle)[ i ];
1991 m += QMAX( 0, item->margin( QStyleSheetItem::MarginLeft ) );
1992 }
1993 stylesPar->ulm = m - stylesPar->leftMargin();
1994
1995 // do the right margin, simplyfied
1996 item = mainStyle;
1997 if (stylesPar->urm > 0 ) {
1998 m = stylesPar->urm-1;
1999 stylesPar->urm = 0;
2000 } else {
2001 m = QMAX( 0, item->margin( QStyleSheetItem::MarginRight ) );
2002 }
2003 for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
2004 item = (*curStyle)[ i ];
2005 m += QMAX( 0, item->margin( QStyleSheetItem::MarginRight ) );
2006 }
2007 stylesPar->urm = m - stylesPar->rightMargin();
2008
2009 // do the first line margin, which really should be called text-indent
2010 item = mainStyle;
2011 if (stylesPar->uflm > 0 ) {
2012 m = stylesPar->uflm-1;
2013 stylesPar->uflm = 0;
2014 } else {
2015 m = QMAX( 0, item->margin( QStyleSheetItem::MarginFirstLine ) );
2016 }
2017 for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
2018 item = (*curStyle)[ i ];
2019 mar = QMAX( 0, item->margin( QStyleSheetItem::MarginFirstLine ) );
2020 m = QMAX( m, mar );
2021 }
2022 stylesPar->uflm =m - stylesPar->firstLineMargin();
2023
2024 // do the bogus line "spacing", which really is just an extra margin
2025 item = mainStyle;
2026 for ( i = (int)curStyle->size() - 1 ; i >= 0; --i ) {
2027 item = (*curStyle)[ i ];
2028 if ( item->lineSpacing() != QStyleSheetItem::Undefined ) {
2029 stylesPar->ulinespacing = item->lineSpacing();
2030 if ( formatCollection() &&
2031 stylesPar->ulinespacing < formatCollection()->defaultFormat()->height() )
2032 stylesPar->ulinespacing += formatCollection()->defaultFormat()->height();
2033 break;
2034 }
2035 }
2036
2037 stylesPar = stylesPar->next();
2038 prevStyle = curStyle;
2039 curStyle = nextStyle;
2040 nextStyle = styles.next();
2041 }
1973} 2042}
1974 2043
1975void QTextDocument::setText( const QString &text, const QString &context ) 2044void QTextDocument::setText( const QString &text, const QString &context )
1976{ 2045{
1977 focusIndicator.parag = 0; 2046 focusIndicator.parag = 0;
1978 selections.clear(); 2047 selections.clear();
@@ -1980,178 +2049,237 @@ void QTextDocument::setText( const QString &text, const QString &context )
1980 txtFormat == Qt::RichText ) 2049 txtFormat == Qt::RichText )
1981 setRichText( text, context ); 2050 setRichText( text, context );
1982 else 2051 else
1983 setPlainText( text ); 2052 setPlainText( text );
1984} 2053}
1985 2054
1986QString QTextDocument::plainText( QTextParag *p ) const 2055QString QTextDocument::plainText() const
1987{ 2056{
1988 if ( !p ) { 2057 QString buffer;
1989 QString buffer; 2058 QString s;
1990 QString s; 2059 QTextParagraph *p = fParag;
1991 QTextParag *p = fParag; 2060 while ( p ) {
1992 while ( p ) { 2061 if ( !p->mightHaveCustomItems ) {
1993 if ( !p->mightHaveCustomItems ) { 2062 s = p->string()->toString();
1994 s = p->string()->toString(); 2063 } else {
1995 } else { 2064 for ( int i = 0; i < p->length() - 1; ++i ) {
1996 for ( int i = 0; i < p->length() - 1; ++i ) { 2065 if ( p->at( i )->isCustom() ) {
1997 if ( p->at( i )->isCustom() ) { 2066 if ( p->at( i )->customItem()->isNested() ) {
1998 if ( p->at( i )->customItem()->isNested() ) { 2067 s += "\n";
1999 s += "\n"; 2068 QTextTable *t = (QTextTable*)p->at( i )->customItem();
2000 QTextTable *t = (QTextTable*)p->at( i )->customItem(); 2069 QPtrList<QTextTableCell> cells = t->tableCells();
2001 QPtrList<QTextTableCell> cells = t->tableCells(); 2070 for ( QTextTableCell *c = cells.first(); c; c = cells.next() )
2002 for ( QTextTableCell *c = cells.first(); c; c = cells.next() ) 2071 s += c->richText()->plainText() + "\n";
2003 s += c->richText()->plainText() + "\n"; 2072 s += "\n";
2004 s += "\n";
2005 }
2006 } else {
2007 s += p->at( i )->c;
2008 } 2073 }
2074 } else {
2075 s += p->at( i )->c;
2009 } 2076 }
2010 } 2077 }
2011 s.remove( s.length() - 1, 1 );
2012 if ( p->next() )
2013 s += "\n";
2014 buffer += s;
2015 p = p->next();
2016 } 2078 }
2017 return buffer; 2079 s.remove( s.length() - 1, 1 );
2018 } else { 2080 if ( p->next() )
2019 return p->string()->toString(); 2081 s += "\n";
2082 buffer += s;
2083 p = p->next();
2020 } 2084 }
2085 return buffer;
2021} 2086}
2022 2087
2023static QString align_to_string( const QString &tag, int a ) 2088static QString align_to_string( int a )
2024{ 2089{
2025 if ( tag == "p" || tag == "li" || ( tag[0] == 'h' && tag[1].isDigit() ) ) { 2090 if ( a & Qt::AlignRight )
2026 if ( a & Qt::AlignRight ) 2091 return " align=\"right\"";
2027 return " align=\"right\""; 2092 if ( a & Qt::AlignHCenter )
2028 if ( a & Qt::AlignCenter ) 2093 return " align=\"center\"";
2029 return " align=\"center\""; 2094 if ( a & Qt3::AlignJustify )
2030 if ( a & Qt3::AlignJustify ) 2095 return " align=\"justify\"";
2031 return " align=\"justify\""; 2096 return QString::null;
2032 }
2033 return "";
2034} 2097}
2035 2098
2036static QString direction_to_string( const QString &tag, int d ) 2099static QString direction_to_string( int d )
2037{ 2100{
2038 if ( d != QChar::DirON && 2101 if ( d != QChar::DirON )
2039 ( tag == "p" || tag == "div" || tag == "li" || ( tag[0] == 'h' && tag[1].isDigit() ) ) )
2040 return ( d == QChar::DirL? " dir=\"ltr\"" : " dir=\"rtl\"" ); 2102 return ( d == QChar::DirL? " dir=\"ltr\"" : " dir=\"rtl\"" );
2041 return ""; 2103 return QString::null;
2042} 2104}
2043 2105
2044QString QTextDocument::richText( QTextParag *p ) const 2106static QString list_value_to_string( int v )
2045{ 2107{
2046 QString s,n; 2108 if ( v != -1 )
2047 if ( !p ) { 2109 return " listvalue=\"" + QString::number( v ) + "\"";
2048 p = fParag; 2110 return QString::null;
2049 QPtrVector<QStyleSheetItem> lastItems, items; 2111}
2050 while ( p ) { 2112
2051 items = p->styleSheetItems(); 2113static QString list_style_to_string( int v )
2052 if ( items.size() ) { 2114{
2053 QStyleSheetItem *item = items[ items.size() - 1 ]; 2115 switch( v ) {
2054 items.resize( items.size() - 1 ); 2116 case QStyleSheetItem::ListDecimal: return "\"1\"";
2055 if ( items.size() > lastItems.size() ) { 2117 case QStyleSheetItem::ListLowerAlpha: return "\"a\"";
2056 for ( int i = lastItems.size(); i < (int)items.size(); ++i ) { 2118 case QStyleSheetItem::ListUpperAlpha: return "\"A\"";
2057 n = items[i]->name(); 2119 case QStyleSheetItem::ListDisc: return "\"disc\"";
2058 if ( n.isEmpty() || n == "li" ) 2120 case QStyleSheetItem::ListSquare: return "\"square\"";
2059 continue; 2121 case QStyleSheetItem::ListCircle: return "\"circle\"";
2060 s += "<" + n + align_to_string( n, p->alignment() ) + ">"; 2122 default:
2061 } 2123 return QString::null;
2062 } else { 2124 }
2063 QString end; 2125}
2064 for ( int i = items.size(); i < (int)lastItems.size(); ++i ) { 2126
2065 n = lastItems[i]->name(); 2127static inline bool list_is_ordered( int v )
2066 if ( n.isEmpty() || n == "li" || n == "br" ) 2128{
2067 continue; 2129 return v == QStyleSheetItem::ListDecimal ||
2068 end.prepend( "</" + lastItems[ i ]->name() + ">" ); 2130 v == QStyleSheetItem::ListLowerAlpha ||
2069 } 2131 v == QStyleSheetItem::ListUpperAlpha;
2070 s += end; 2132}
2071 } 2133
2072 lastItems = items; 2134
2073 n = item->name(); 2135static QString margin_to_string( QStyleSheetItem* style, int t, int b, int l, int r, int fl )
2074 if ( n == "li" && p->listValue() != -1 ) { 2136{
2075 s += "<li value=\"" + QString::number( p->listValue() ) + "\">"; 2137 QString s;
2076 } else { 2138 if ( l > 0 )
2077 QString ps = p->richText(); 2139 s += QString(!!s?";":"") + "margin-left:" + QString::number(l+QMAX(0,style->margin(QStyleSheetItem::MarginLeft))) + "px";
2078 if ( ps.isEmpty() ) 2140 if ( r > 0 )
2079 s += "<br>"; // empty paragraph 2141 s += QString(!!s?";":"") + "margin-right:" + QString::number(r+QMAX(0,style->margin(QStyleSheetItem::MarginRight))) + "px";
2080 else if ( !n.isEmpty() ) { 2142 if ( t > 0 )
2081 s += "<" + n + align_to_string( n, p->alignment() ) 2143 s += QString(!!s?";":"") + "margin-top:" + QString::number(t+QMAX(0,style->margin(QStyleSheetItem::MarginTop))) + "px";
2082 + direction_to_string( n, p->direction() ) + ">" + ps; 2144 if ( b > 0 )
2083 if ( n != "li" && n != "br") 2145 s += QString(!!s?";":"") + "margin-bottom:" + QString::number(b+QMAX(0,style->margin(QStyleSheetItem::MarginBottom))) + "px";
2084 s += "</" + n + ">"; 2146 if ( fl > 0 )
2085 } else 2147 s += QString(!!s?";":"") + "text-indent:" + QString::number(fl+QMAX(0,style->margin(QStyleSheetItem::MarginFirstLine))) + "px";
2086 s += ps; 2148 if ( !!s )
2087 } 2149 return " style=\"" + s + "\"";
2088 } else { 2150 return QString::null;
2089 QString end; 2151}
2090 for ( int i = 0; i < (int)lastItems.size(); ++i ) { 2152
2091 QString n = lastItems[i]->name(); 2153QString QTextDocument::richText() const
2092 if ( n.isEmpty() || n == "li" || n == "br" ) 2154{
2093 continue; 2155 QString s = "";
2094 end.prepend( "</" + n + ">" ); 2156 if ( !par ) {
2095 } 2157 s += "<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body style=\"font-size:" ;
2096 s += end; 2158 s += QString::number( formatCollection()->defaultFormat()->font().pointSize() );
2097 QString ps = p->richText(); 2159 s += "pt;font-family:";
2098 if ( ps.isEmpty() ) 2160 s += formatCollection()->defaultFormat()->font().family();
2099 s += "<br>"; // empty paragraph 2161 s +="\">";
2100 else 2162 }
2101 s += "<p" + align_to_string( "p", p->alignment() ) + direction_to_string( "p", p->direction() ) 2163 QTextParagraph* p = fParag;
2102 + ">" + ps + "</p>"; 2164
2103 lastItems = items; 2165 QStyleSheetItem* item_p = styleSheet()->item("p");
2166 QStyleSheetItem* item_ul = styleSheet()->item("ul");
2167 QStyleSheetItem* item_ol = styleSheet()->item("ol");
2168 QStyleSheetItem* item_li = styleSheet()->item("li");
2169 if ( !item_p || !item_ul || !item_ol || !item_li ) {
2170 qWarning( "QTextEdit: cannot export HTML due to insufficient stylesheet (lack of p, ul, ol, or li)" );
2171 return QString::null;
2172 }
2173 int pastListDepth = 0;
2174 int listDepth = 0;
2175 int futureListDepth = 0;
2176 QMemArray<int> listStyles(10);
2177
2178 while ( p ) {
2179 listDepth = p->listDepth();
2180 if ( listDepth < pastListDepth ) {
2181 for ( int i = listDepth+1; i <= pastListDepth; i++ )
2182 s += list_is_ordered( listStyles[i] ) ? "</ol>" : "</ul>";
2183 s += '\n';
2184 } else if ( listDepth > pastListDepth ) {
2185 s += '\n';
2186 listStyles.resize( QMAX( (int)listStyles.size(), listDepth+1 ) );
2187 QString list_type;
2188 listStyles[listDepth] = p->listStyle();
2189 if ( !list_is_ordered( p->listStyle() ) || item_ol->listStyle() != p->listStyle() )
2190 list_type = " type=" + list_style_to_string( p->listStyle() );
2191 for ( int i = pastListDepth; i < listDepth; i++ ) {
2192 s += list_is_ordered( p->listStyle() ) ? "<ol" : "<ul" ;
2193 s += list_type + ">";
2104 } 2194 }
2105 if ( ( p = p->next() ) ) 2195 } else {
2106 s += '\n'; 2196 s += '\n';
2107 } 2197 }
2108 } else { 2198
2109 s = p->richText(); 2199 QString ps = p->richText();
2200
2201 // for the bottom margin we need to know whether we are at the end of a list
2202 futureListDepth = 0;
2203 if ( listDepth > 0 && p->next() )
2204 futureListDepth = p->next()->listDepth();
2205
2206 if ( richTextExportStart && richTextExportStart->paragraph() ==p &&
2207 richTextExportStart->index() == 0 )
2208 s += "<selstart/>";
2209
2210 if ( p->isListItem() ) {
2211 s += "<li";
2212 if ( p->listStyle() != listStyles[listDepth] )
2213 s += " type=" + list_style_to_string( p->listStyle() );
2214 s +=align_to_string( p->alignment() );
2215 s += margin_to_string( item_li, p->utm, p->ubm, p->ulm, p->urm, p->uflm );
2216 s += list_value_to_string( p->listValue() );
2217 s += direction_to_string( p->direction() );
2218 s +=">";
2219 s += ps;
2220 s += "</li>";
2221 } else {
2222 // normal paragraph item
2223 s += "<p";
2224 s += align_to_string( p->alignment() );
2225 s += margin_to_string( item_p, p->utm, p->ubm, p->ulm, p->urm, p->uflm );
2226 s +=direction_to_string( p->direction() );
2227 s += ">";
2228 s += ps;
2229 s += "</p>";
2230 }
2231 pastListDepth = listDepth;
2232 p = p->next();
2233 }
2234 while ( listDepth > 0 ) {
2235 s += list_is_ordered( listStyles[listDepth] ) ? "</ol>" : "</ul>";
2236 listDepth--;
2110 } 2237 }
2111 2238
2239 if ( !par )
2240 s += "\n</body></html>\n";
2241
2112 return s; 2242 return s;
2113} 2243}
2114 2244
2115QString QTextDocument::text() const 2245QString QTextDocument::text() const
2116{ 2246{
2117 if ( plainText().simplifyWhiteSpace().isEmpty() )
2118 return QString("");
2119 if ( txtFormat == Qt::AutoText && preferRichText || txtFormat == Qt::RichText ) 2247 if ( txtFormat == Qt::AutoText && preferRichText || txtFormat == Qt::RichText )
2120 return richText(); 2248 return richText();
2121 return plainText( 0 ); 2249 return plainText();
2122} 2250}
2123 2251
2124QString QTextDocument::text( int parag ) const 2252QString QTextDocument::text( int parag ) const
2125{ 2253{
2126 QTextParag *p = paragAt( parag ); 2254 QTextParagraph *p = paragAt( parag );
2127 if ( !p ) 2255 if ( !p )
2128 return QString::null; 2256 return QString::null;
2129 2257
2130 if ( txtFormat == Qt::AutoText && preferRichText || txtFormat == Qt::RichText ) 2258 if ( txtFormat == Qt::AutoText && preferRichText || txtFormat == Qt::RichText )
2131 return richText( p ); 2259 return p->richText();
2132 else 2260 else
2133 return plainText( p ); 2261 return p->string()->toString();
2134} 2262}
2135 2263
2136void QTextDocument::invalidate() 2264void QTextDocument::invalidate()
2137{ 2265{
2138 QTextParag *s = fParag; 2266 QTextParagraph *s = fParag;
2139 while ( s ) { 2267 while ( s ) {
2140 s->invalidate( 0 ); 2268 s->invalidate( 0 );
2141 s = s->next(); 2269 s = s->next();
2142 } 2270 }
2143} 2271}
2144 2272
2145void QTextDocument::selectionStart( int id, int &paragId, int &index ) 2273void QTextDocument::selectionStart( int id, int &paragId, int &index )
2146{ 2274{
2147 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id ); 2275 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2148 if ( it == selections.end() ) 2276 if ( it == selections.end() )
2149 return; 2277 return;
2150 QTextDocumentSelection &sel = *it; 2278 QTextDocumentSelection &sel = *it;
2151 paragId = !sel.swapped ? sel.startCursor.parag()->paragId() : sel.endCursor.parag()->paragId(); 2279 paragId = !sel.swapped ? sel.startCursor.paragraph()->paragId() : sel.endCursor.paragraph()->paragId();
2152 index = !sel.swapped ? sel.startCursor.index() : sel.endCursor.index(); 2280 index = !sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
2153} 2281}
2154 2282
2155QTextCursor QTextDocument::selectionStartCursor( int id) 2283QTextCursor QTextDocument::selectionStartCursor( int id)
2156{ 2284{
2157 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id ); 2285 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
@@ -2177,38 +2305,16 @@ QTextCursor QTextDocument::selectionEndCursor( int id)
2177void QTextDocument::selectionEnd( int id, int &paragId, int &index ) 2305void QTextDocument::selectionEnd( int id, int &paragId, int &index )
2178{ 2306{
2179 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id ); 2307 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2180 if ( it == selections.end() ) 2308 if ( it == selections.end() )
2181 return; 2309 return;
2182 QTextDocumentSelection &sel = *it; 2310 QTextDocumentSelection &sel = *it;
2183 paragId = sel.swapped ? sel.startCursor.parag()->paragId() : sel.endCursor.parag()->paragId(); 2311 paragId = sel.swapped ? sel.startCursor.paragraph()->paragId() : sel.endCursor.paragraph()->paragId();
2184 index = sel.swapped ? sel.startCursor.index() : sel.endCursor.index(); 2312 index = sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
2185} 2313}
2186 2314
2187QTextParag *QTextDocument::selectionStart( int id )
2188{
2189 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2190 if ( it == selections.end() )
2191 return 0;
2192 QTextDocumentSelection &sel = *it;
2193 if ( sel.startCursor.parag()->paragId() < sel.endCursor.parag()->paragId() )
2194 return sel.startCursor.parag();
2195 return sel.endCursor.parag();
2196}
2197
2198QTextParag *QTextDocument::selectionEnd( int id )
2199{
2200 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2201 if ( it == selections.end() )
2202 return 0;
2203 QTextDocumentSelection &sel = *it;
2204 if ( sel.startCursor.parag()->paragId() > sel.endCursor.parag()->paragId() )
2205 return sel.startCursor.parag();
2206 return sel.endCursor.parag();
2207}
2208
2209void QTextDocument::addSelection( int id ) 2315void QTextDocument::addSelection( int id )
2210{ 2316{
2211 nSelections = QMAX( nSelections, id + 1 ); 2317 nSelections = QMAX( nSelections, id + 1 );
2212} 2318}
2213 2319
2214static void setSelectionEndHelper( int id, QTextDocumentSelection &sel, QTextCursor &start, QTextCursor &end ) 2320static void setSelectionEndHelper( int id, QTextDocumentSelection &sel, QTextCursor &start, QTextCursor &end )
@@ -2217,58 +2323,57 @@ static void setSelectionEndHelper( int id, QTextDocumentSelection &sel, QTextCur
2217 QTextCursor c2 = end; 2323 QTextCursor c2 = end;
2218 if ( sel.swapped ) { 2324 if ( sel.swapped ) {
2219 c1 = end; 2325 c1 = end;
2220 c2 = start; 2326 c2 = start;
2221 } 2327 }
2222 2328
2223 c1.parag()->removeSelection( id ); 2329 c1.paragraph()->removeSelection( id );
2224 c2.parag()->removeSelection( id ); 2330 c2.paragraph()->removeSelection( id );
2225 if ( c1.parag() != c2.parag() ) { 2331 if ( c1.paragraph() != c2.paragraph() ) {
2226 c1.parag()->setSelection( id, c1.index(), c1.parag()->length() - 1 ); 2332 c1.paragraph()->setSelection( id, c1.index(), c1.paragraph()->length() - 1 );
2227 c2.parag()->setSelection( id, 0, c2.index() ); 2333 c2.paragraph()->setSelection( id, 0, c2.index() );
2228 } else { 2334 } else {
2229 c1.parag()->setSelection( id, QMIN( c1.index(), c2.index() ), QMAX( c1.index(), c2.index() ) ); 2335 c1.paragraph()->setSelection( id, QMIN( c1.index(), c2.index() ), QMAX( c1.index(), c2.index() ) );
2230 } 2336 }
2231 2337
2232 sel.startCursor = start; 2338 sel.startCursor = start;
2233 sel.endCursor = end; 2339 sel.endCursor = end;
2234 if ( sel.startCursor.parag() == sel.endCursor.parag() ) 2340 if ( sel.startCursor.paragraph() == sel.endCursor.paragraph() )
2235 sel.swapped = sel.startCursor.index() > sel.endCursor.index(); 2341 sel.swapped = sel.startCursor.index() > sel.endCursor.index();
2236} 2342}
2237 2343
2238bool QTextDocument::setSelectionEnd( int id, QTextCursor *cursor ) 2344bool QTextDocument::setSelectionEnd( int id, const QTextCursor &cursor )
2239{ 2345{
2240 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id ); 2346 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2241 if ( it == selections.end() ) 2347 if ( it == selections.end() )
2242 return FALSE; 2348 return FALSE;
2243 QTextDocumentSelection &sel = *it; 2349 QTextDocumentSelection &sel = *it;
2244 2350
2245 QTextCursor start = sel.startCursor; 2351 QTextCursor start = sel.startCursor;
2246 QTextCursor end = *cursor; 2352 QTextCursor end = cursor;
2247 2353
2248 if ( start == end ) { 2354 if ( start == end ) {
2249 removeSelection( id ); 2355 removeSelection( id );
2250 setSelectionStart( id, cursor ); 2356 setSelectionStart( id, cursor );
2251 return TRUE; 2357 return TRUE;
2252 } 2358 }
2253 2359
2254 if ( sel.endCursor.parag() == end.parag() ) { 2360 if ( sel.endCursor.paragraph() == end.paragraph() ) {
2255 setSelectionEndHelper( id, sel, start, end ); 2361 setSelectionEndHelper( id, sel, start, end );
2256 return TRUE; 2362 return TRUE;
2257 } 2363 }
2258 2364
2259 bool inSelection = FALSE; 2365 bool inSelection = FALSE;
2260 QTextCursor c( this ); 2366 QTextCursor c( this );
2261 QTextCursor tmp = sel.startCursor; 2367 QTextCursor tmp = sel.startCursor;
2262 if ( sel.swapped ) 2368 if ( sel.swapped )
2263 tmp = sel.endCursor; 2369 tmp = sel.endCursor;
2264 tmp.restoreState(); 2370 tmp.restoreState();
2265 QTextCursor tmp2 = *cursor; 2371 QTextCursor tmp2 = cursor;
2266 tmp2.restoreState(); 2372 tmp2.restoreState();
2267 c.setParag( tmp.parag()->paragId() < tmp2.parag()->paragId() ? tmp.parag() : tmp2.parag() ); 2373 c.setParagraph( tmp.paragraph()->paragId() < tmp2.paragraph()->paragId() ? tmp.paragraph() : tmp2.paragraph() );
2268 QTextCursor old;
2269 bool hadStart = FALSE; 2374 bool hadStart = FALSE;
2270 bool hadEnd = FALSE; 2375 bool hadEnd = FALSE;
2271 bool hadStartParag = FALSE; 2376 bool hadStartParag = FALSE;
2272 bool hadEndParag = FALSE; 2377 bool hadEndParag = FALSE;
2273 bool hadOldStart = FALSE; 2378 bool hadOldStart = FALSE;
2274 bool hadOldEnd = FALSE; 2379 bool hadOldEnd = FALSE;
@@ -2276,76 +2381,88 @@ bool QTextDocument::setSelectionEnd( int id, QTextCursor *cursor )
2276 sel.swapped = FALSE; 2381 sel.swapped = FALSE;
2277 for ( ;; ) { 2382 for ( ;; ) {
2278 if ( c == start ) 2383 if ( c == start )
2279 hadStart = TRUE; 2384 hadStart = TRUE;
2280 if ( c == end ) 2385 if ( c == end )
2281 hadEnd = TRUE; 2386 hadEnd = TRUE;
2282 if ( c.parag() == start.parag() ) 2387 if ( c.paragraph() == start.paragraph() )
2283 hadStartParag = TRUE; 2388 hadStartParag = TRUE;
2284 if ( c.parag() == end.parag() ) 2389 if ( c.paragraph() == end.paragraph() )
2285 hadEndParag = TRUE; 2390 hadEndParag = TRUE;
2286 if ( c == sel.startCursor ) 2391 if ( c == sel.startCursor )
2287 hadOldStart = TRUE; 2392 hadOldStart = TRUE;
2288 if ( c == sel.endCursor ) 2393 if ( c == sel.endCursor )
2289 hadOldEnd = TRUE; 2394 hadOldEnd = TRUE;
2290 2395
2291 if ( !sel.swapped && 2396 if ( !sel.swapped &&
2292 ( hadEnd && !hadStart || 2397 ( hadEnd && !hadStart ||
2293 hadEnd && hadStart && start.parag() == end.parag() && start.index() > end.index() ) ) 2398 hadEnd && hadStart && start.paragraph() == end.paragraph() && start.index() > end.index() ) )
2294 sel.swapped = TRUE; 2399 sel.swapped = TRUE;
2295 2400
2296 if ( c == end && hadStartParag || 2401 if ( c == end && hadStartParag ||
2297 c == start && hadEndParag ) { 2402 c == start && hadEndParag ) {
2298 QTextCursor tmp = c; 2403 QTextCursor tmp = c;
2299 tmp.restoreState(); 2404 tmp.restoreState();
2300 if ( tmp.parag() != c.parag() ) { 2405 if ( tmp.paragraph() != c.paragraph() ) {
2301 int sstart = tmp.parag()->selectionStart( id ); 2406 int sstart = tmp.paragraph()->selectionStart( id );
2302 tmp.parag()->removeSelection( id ); 2407 tmp.paragraph()->removeSelection( id );
2303 tmp.parag()->setSelection( id, sstart, tmp.index() ); 2408 tmp.paragraph()->setSelection( id, sstart, tmp.index() );
2304 } 2409 }
2305 } 2410 }
2306 2411
2307 if ( inSelection && 2412 if ( inSelection &&
2308 ( c == end && hadStart || c == start && hadEnd ) ) 2413 ( c == end && hadStart || c == start && hadEnd ) )
2309 leftSelection = TRUE; 2414 leftSelection = TRUE;
2310 else if ( !leftSelection && !inSelection && ( hadStart || hadEnd ) ) 2415 else if ( !leftSelection && !inSelection && ( hadStart || hadEnd ) )
2311 inSelection = TRUE; 2416 inSelection = TRUE;
2312 2417
2313 bool noSelectionAnymore = hadOldStart && hadOldEnd && leftSelection && !inSelection && !c.parag()->hasSelection( id ) && c.atParagEnd(); 2418 bool noSelectionAnymore = hadOldStart && hadOldEnd && leftSelection && !inSelection && !c.paragraph()->hasSelection( id ) && c.atParagEnd();
2314 c.parag()->removeSelection( id ); 2419 c.paragraph()->removeSelection( id );
2315 if ( inSelection ) { 2420 if ( inSelection ) {
2316 if ( c.parag() == start.parag() && start.parag() == end.parag() ) { 2421 if ( c.paragraph() == start.paragraph() && start.paragraph() == end.paragraph() ) {
2317 c.parag()->setSelection( id, QMIN( start.index(), end.index() ), QMAX( start.index(), end.index() ) ); 2422 c.paragraph()->setSelection( id, QMIN( start.index(), end.index() ), QMAX( start.index(), end.index() ) );
2318 } else if ( c.parag() == start.parag() && !hadEndParag ) { 2423 } else if ( c.paragraph() == start.paragraph() && !hadEndParag ) {
2319 c.parag()->setSelection( id, start.index(), c.parag()->length() - 1 ); 2424 c.paragraph()->setSelection( id, start.index(), c.paragraph()->length() - 1 );
2320 } else if ( c.parag() == end.parag() && !hadStartParag ) { 2425 } else if ( c.paragraph() == end.paragraph() && !hadStartParag ) {
2321 c.parag()->setSelection( id, end.index(), c.parag()->length() - 1 ); 2426 c.paragraph()->setSelection( id, end.index(), c.paragraph()->length() - 1 );
2322 } else if ( c.parag() == end.parag() && hadEndParag ) { 2427 } else if ( c.paragraph() == end.paragraph() && hadEndParag ) {
2323 c.parag()->setSelection( id, 0, end.index() ); 2428 c.paragraph()->setSelection( id, 0, end.index() );
2324 } else if ( c.parag() == start.parag() && hadStartParag ) { 2429 } else if ( c.paragraph() == start.paragraph() && hadStartParag ) {
2325 c.parag()->setSelection( id, 0, start.index() ); 2430 c.paragraph()->setSelection( id, 0, start.index() );
2326 } else { 2431 } else {
2327 c.parag()->setSelection( id, 0, c.parag()->length() - 1 ); 2432 c.paragraph()->setSelection( id, 0, c.paragraph()->length() - 1 );
2328 } 2433 }
2329 } 2434 }
2330 2435
2331 if ( leftSelection ) 2436 if ( leftSelection )
2332 inSelection = FALSE; 2437 inSelection = FALSE;
2333 2438
2334 old = c; 2439 if ( noSelectionAnymore )
2335 c.gotoNextLetter();
2336 if ( old == c || noSelectionAnymore )
2337 break; 2440 break;
2441 // *ugle*hack optimization
2442 QTextParagraph *p = c.paragraph();
2443 if ( p->mightHaveCustomItems || p == start.paragraph() || p == end.paragraph() || p == lastParagraph() ) {
2444 c.gotoNextLetter();
2445 if ( p == lastParagraph() && c.atParagEnd() )
2446 break;
2447 } else {
2448 if ( p->document()->parent() )
2449 do {
2450 c.gotoNextLetter();
2451 } while ( c.paragraph() == p );
2452 else
2453 c.setParagraph( p->next() );
2454 }
2338 } 2455 }
2339 2456
2340 if ( !sel.swapped ) 2457 if ( !sel.swapped )
2341 sel.startCursor.parag()->setSelection( id, sel.startCursor.index(), sel.startCursor.parag()->length() - 1 ); 2458 sel.startCursor.paragraph()->setSelection( id, sel.startCursor.index(), sel.startCursor.paragraph()->length() - 1 );
2342 2459
2343 sel.startCursor = start; 2460 sel.startCursor = start;
2344 sel.endCursor = end; 2461 sel.endCursor = end;
2345 if ( sel.startCursor.parag() == sel.endCursor.parag() ) 2462 if ( sel.startCursor.paragraph() == sel.endCursor.paragraph() )
2346 sel.swapped = sel.startCursor.index() > sel.endCursor.index(); 2463 sel.swapped = sel.startCursor.index() > sel.endCursor.index();
2347 2464
2348 setSelectionEndHelper( id, sel, start, end ); 2465 setSelectionEndHelper( id, sel, start, end );
2349 2466
2350 return TRUE; 2467 return TRUE;
2351} 2468}
@@ -2355,112 +2472,55 @@ void QTextDocument::selectAll( int id )
2355 removeSelection( id ); 2472 removeSelection( id );
2356 2473
2357 QTextDocumentSelection sel; 2474 QTextDocumentSelection sel;
2358 sel.swapped = FALSE; 2475 sel.swapped = FALSE;
2359 QTextCursor c( this ); 2476 QTextCursor c( this );
2360 2477
2361 c.setParag( fParag ); 2478 c.setParagraph( fParag );
2362 c.setIndex( 0 ); 2479 c.setIndex( 0 );
2363 sel.startCursor = c; 2480 sel.startCursor = c;
2364 2481
2365 c.setParag( lParag ); 2482 c.setParagraph( lParag );
2366 c.setIndex( lParag->length() - 1 ); 2483 c.setIndex( lParag->length() - 1 );
2367 sel.endCursor = c; 2484 sel.endCursor = c;
2368 2485
2369 QTextParag *p = fParag; 2486 selections.insert( id, sel );
2487
2488 QTextParagraph *p = fParag;
2370 while ( p ) { 2489 while ( p ) {
2371 p->setSelection( id, 0, p->length() - 1 ); 2490 p->setSelection( id, 0, p->length() - 1 );
2372 for ( int i = 0; i < (int)p->length(); ++i ) {
2373 if ( p->at( i )->isCustom() && p->at( i )->customItem()->isNested() ) {
2374 QTextTable *t = (QTextTable*)p->at( i )->customItem();
2375 QPtrList<QTextTableCell> tableCells = t->tableCells();
2376 for ( QTextTableCell *c = tableCells.first(); c; c = tableCells.next() )
2377 c->richText()->selectAll( id );
2378 }
2379 }
2380 p = p->next(); 2491 p = p->next();
2381 } 2492 }
2382 2493
2383 selections.insert( id, sel ); 2494 for ( QTextDocument *d = childList.first(); d; d = childList.next() )
2495 d->selectAll( id );
2384} 2496}
2385 2497
2386bool QTextDocument::removeSelection( int id ) 2498bool QTextDocument::removeSelection( int id )
2387{ 2499{
2388 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id ); 2500 if ( !selections.contains( id ) )
2389 if ( it == selections.end() )
2390 return FALSE; 2501 return FALSE;
2391 2502
2392 QTextDocumentSelection &sel = *it; 2503 QTextDocumentSelection &sel = selections[ id ];
2393
2394 if ( sel.startCursor == sel.endCursor ) {
2395 selections.remove( id );
2396 return TRUE;
2397 }
2398
2399 if ( !mightHaveCustomItems ) {
2400 QTextCursor start = sel.startCursor;
2401 QTextCursor end = sel.endCursor;
2402 if ( sel.swapped ) {
2403 start = sel.endCursor;
2404 end = sel.startCursor;
2405 }
2406 2504
2407 for ( QTextParag *p = start.parag(); p; p = p->next() ) { 2505 QTextCursor start = sel.swapped ? sel.endCursor : sel.startCursor;
2506 QTextCursor end = sel.swapped ? sel.startCursor : sel.endCursor;
2507 QTextParagraph* p = 0;
2508 while ( start != end ) {
2509 if ( p != start.paragraph() ) {
2510 p = start.paragraph();
2408 p->removeSelection( id ); 2511 p->removeSelection( id );
2409 if ( p == end.parag() )
2410 break;
2411 } 2512 }
2412 2513 start.gotoNextLetter();
2413 selections.remove( id );
2414 return TRUE;
2415 }
2416
2417 QTextCursor c( this );
2418 QTextCursor tmp = sel.startCursor;
2419 if ( sel.swapped )
2420 tmp = sel.endCursor;
2421 tmp.restoreState();
2422 c.setParag( tmp.parag() );
2423 QTextCursor old;
2424 bool hadStart = FALSE;
2425 bool hadEnd = FALSE;
2426 QTextParag *lastParag = 0;
2427 bool leftSelection = FALSE;
2428 bool inSelection = FALSE;
2429 sel.swapped = FALSE;
2430 for ( ;; ) {
2431 if ( c.parag() == sel.startCursor.parag() )
2432 hadStart = TRUE;
2433 if ( c.parag() == sel.endCursor.parag() )
2434 hadEnd = TRUE;
2435
2436 if ( inSelection &&
2437 ( c == sel.endCursor && hadStart || c == sel.startCursor && hadEnd ) )
2438 leftSelection = TRUE;
2439 else if ( !leftSelection && !inSelection && ( c.parag() == sel.startCursor.parag() || c.parag() == sel.endCursor.parag() ) )
2440 inSelection = TRUE;
2441
2442 bool noSelectionAnymore = leftSelection && !inSelection && !c.parag()->hasSelection( id ) && c.atParagEnd();
2443
2444 if ( lastParag != c.parag() )
2445 c.parag()->removeSelection( id );
2446
2447 old = c;
2448 lastParag = c.parag();
2449 c.gotoNextLetter();
2450 if ( old == c || noSelectionAnymore )
2451 break;
2452 } 2514 }
2453
2454 selections.remove( id ); 2515 selections.remove( id );
2455 return TRUE; 2516 return TRUE;
2456} 2517}
2457 2518
2458QString QTextDocument::selectedText( int id, bool withCustom ) const 2519QString QTextDocument::selectedText( int id, bool asRichText ) const
2459{ 2520{
2460 // ######## TODO: look at textFormat() and return rich text or plain text (like the text() method!)
2461 QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( id ); 2521 QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( id );
2462 if ( it == selections.end() ) 2522 if ( it == selections.end() )
2463 return QString::null; 2523 return QString::null;
2464 2524
2465 QTextDocumentSelection sel = *it; 2525 QTextDocumentSelection sel = *it;
2466 2526
@@ -2478,41 +2538,53 @@ QString QTextDocument::selectedText( int id, bool withCustom ) const
2478 to paragraphs within the same text document. 2538 to paragraphs within the same text document.
2479 2539
2480 Meaning if you select text in two table cells, you will get the 2540 Meaning if you select text in two table cells, you will get the
2481 entire table. This is still far better than the 3.0.2, where 2541 entire table. This is still far better than the 3.0.2, where
2482 you always got the entire table. 2542 you always got the entire table.
2483 2543
2484 ### Fix this properly for 3.0.4. 2544 ### Fix this properly when refactoring
2485 */ 2545 */
2486 while ( c2.nestedDepth() > c1.nestedDepth() ) 2546 while ( c2.nestedDepth() > c1.nestedDepth() )
2487 c2.oneUp(); 2547 c2.oneUp();
2488 while ( c1.nestedDepth() > c2.nestedDepth() ) 2548 while ( c1.nestedDepth() > c2.nestedDepth() )
2489 c1.oneUp(); 2549 c1.oneUp();
2490 while ( c1.nestedDepth() && c2.nestedDepth() && 2550 while ( c1.nestedDepth() && c2.nestedDepth() &&
2491 c1.parag()->document() != c2.parag()->document() ) { 2551 c1.paragraph()->document() != c2.paragraph()->document() ) {
2492 c1.oneUp(); 2552 c1.oneUp();
2493 c2.oneUp(); 2553 c2.oneUp();
2494 } 2554 }
2495 // do not trust sel_swapped with tables. Fix this properly for 3.0.4 as well 2555 // do not trust sel_swapped with tables. Fix this properly when refactoring as well
2496 if ( c1.parag()->paragId() > c2.parag()->paragId() || 2556 if ( c1.paragraph()->paragId() > c2.paragraph()->paragId() ||
2497 (c1.parag() == c2.parag() && c1.index() > c2.index() ) ) { 2557 (c1.paragraph() == c2.paragraph() && c1.index() > c2.index() ) ) {
2498 QTextCursor tmp = c1; 2558 QTextCursor tmp = c1;
2499 c2 = c1; 2559 c2 = c1;
2500 c1 = tmp; 2560 c1 = tmp;
2501 } 2561 }
2502 2562
2503 // end selection 3.0.3 improvement 2563 // end selection 3.0.3 improvement
2504 2564
2565 if ( asRichText && !parent() ) {
2566 richTextExportStart = &c1;
2567 richTextExportEnd = &c2;
2505 2568
2506 if ( c1.parag() == c2.parag() ) { 2569 QString sel = richText();
2507 QString s; 2570 int from = sel.find( "<selstart/>" );
2508 QTextParag *p = c1.parag(); 2571 int to = sel.findRev( "<selend/>" );
2572 if ( from >= 0 && from <= to )
2573 sel = sel.mid( from, to - from );
2574 richTextExportStart = richTextExportEnd = 0;
2575 return sel;
2576 }
2577
2578 QString s;
2579 if ( c1.paragraph() == c2.paragraph() ) {
2580 QTextParagraph *p = c1.paragraph();
2509 int end = c2.index(); 2581 int end = c2.index();
2510 if ( p->at( QMAX( 0, end - 1 ) )->isCustom() ) 2582 if ( p->at( QMAX( 0, end - 1 ) )->isCustom() )
2511 ++end; 2583 ++end;
2512 if ( !withCustom || !p->mightHaveCustomItems ) { 2584 if ( !p->mightHaveCustomItems ) {
2513 s += p->string()->toString().mid( c1.index(), end - c1.index() ); 2585 s += p->string()->toString().mid( c1.index(), end - c1.index() );
2514 } else { 2586 } else {
2515 for ( int i = c1.index(); i < end; ++i ) { 2587 for ( int i = c1.index(); i < end; ++i ) {
2516 if ( p->at( i )->isCustom() ) { 2588 if ( p->at( i )->isCustom() ) {
2517 if ( p->at( i )->customItem()->isNested() ) { 2589 if ( p->at( i )->customItem()->isNested() ) {
2518 s += "\n"; 2590 s += "\n";
@@ -2524,47 +2596,53 @@ QString QTextDocument::selectedText( int id, bool withCustom ) const
2524 } 2596 }
2525 } else { 2597 } else {
2526 s += p->at( i )->c; 2598 s += p->at( i )->c;
2527 } 2599 }
2528 } 2600 }
2529 } 2601 }
2530 return s; 2602 } else {
2531 } 2603 QTextParagraph *p = c1.paragraph();
2532 2604 int start = c1.index();
2533 QString s; 2605 while ( p ) {
2534 QTextParag *p = c1.parag(); 2606 int end = p == c2.paragraph() ? c2.index() : p->length() - 1;
2535 int start = c1.index(); 2607 if ( p == c2.paragraph() && p->at( QMAX( 0, end - 1 ) )->isCustom() )
2536 while ( p ) { 2608 ++end;
2537 int end = p == c2.parag() ? c2.index() : p->length() - 1; 2609 if ( !p->mightHaveCustomItems ) {
2538 if ( p == c2.parag() && p->at( QMAX( 0, end - 1 ) )->isCustom() ) 2610 s += p->string()->toString().mid( start, end - start );
2539 ++end; 2611 if ( p != c2.paragraph() )
2540 if ( !withCustom || !p->mightHaveCustomItems ) { 2612 s += "\n";
2541 s += p->string()->toString().mid( start, end - start ); 2613 } else {
2542 if ( p != c2.parag() ) 2614 for ( int i = start; i < end; ++i ) {
2543 s += "\n"; 2615 if ( p->at( i )->isCustom() ) {
2544 } else { 2616 if ( p->at( i )->customItem()->isNested() ) {
2545 for ( int i = start; i < end; ++i ) { 2617 s += "\n";
2546 if ( p->at( i )->isCustom() ) { 2618 QTextTable *t = (QTextTable*)p->at( i )->customItem();
2547 if ( p->at( i )->customItem()->isNested() ) { 2619 QPtrList<QTextTableCell> cells = t->tableCells();
2548 s += "\n"; 2620 for ( QTextTableCell *c = cells.first(); c; c = cells.next() )
2549 QTextTable *t = (QTextTable*)p->at( i )->customItem(); 2621 s += c->richText()->plainText() + "\n";
2550 QPtrList<QTextTableCell> cells = t->tableCells(); 2622 s += "\n";
2551 for ( QTextTableCell *c = cells.first(); c; c = cells.next() ) 2623 }
2552 s += c->richText()->plainText() + "\n"; 2624 } else {
2553 s += "\n"; 2625 s += p->at( i )->c;
2554 } 2626 }
2555 } else {
2556 s += p->at( i )->c;
2557 } 2627 }
2558 } 2628 }
2629 start = 0;
2630 if ( p == c2.paragraph() )
2631 break;
2632 p = p->next();
2559 } 2633 }
2560 start = 0;
2561 if ( p == c2.parag() )
2562 break;
2563 p = p->next();
2564 } 2634 }
2635 // ### workaround for plain text export until we get proper
2636 // mime types: turn unicode line seperators into the more
2637 // widely understood \n. Makes copy and pasting code snipplets
2638 // from within Assistent possible
2639 QChar* uc = (QChar*) s.unicode();
2640 for ( uint ii = 0; ii < s.length(); ii++ )
2641 if ( uc[(int)ii] == QChar_linesep )
2642 uc[(int)ii] = QChar('\n');
2565 return s; 2643 return s;
2566} 2644}
2567 2645
2568void QTextDocument::setFormat( int id, QTextFormat *f, int flags ) 2646void QTextDocument::setFormat( int id, QTextFormat *f, int flags )
2569{ 2647{
2570 QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( id ); 2648 QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( id );
@@ -2580,34 +2658,24 @@ void QTextDocument::setFormat( int id, QTextFormat *f, int flags )
2580 c1 = sel.endCursor; 2658 c1 = sel.endCursor;
2581 } 2659 }
2582 2660
2583 c2.restoreState(); 2661 c2.restoreState();
2584 c1.restoreState(); 2662 c1.restoreState();
2585 2663
2586 if ( c1.parag() == c2.parag() ) { 2664 if ( c1.paragraph() == c2.paragraph() ) {
2587 c1.parag()->setFormat( c1.index(), c2.index() - c1.index(), f, TRUE, flags ); 2665 c1.paragraph()->setFormat( c1.index(), c2.index() - c1.index(), f, TRUE, flags );
2588 return; 2666 return;
2589 } 2667 }
2590 2668
2591 c1.parag()->setFormat( c1.index(), c1.parag()->length() - c1.index(), f, TRUE, flags ); 2669 c1.paragraph()->setFormat( c1.index(), c1.paragraph()->length() - c1.index(), f, TRUE, flags );
2592 QTextParag *p = c1.parag()->next(); 2670 QTextParagraph *p = c1.paragraph()->next();
2593 while ( p && p != c2.parag() ) { 2671 while ( p && p != c2.paragraph() ) {
2594 p->setFormat( 0, p->length(), f, TRUE, flags ); 2672 p->setFormat( 0, p->length(), f, TRUE, flags );
2595 p = p->next(); 2673 p = p->next();
2596 } 2674 }
2597 c2.parag()->setFormat( 0, c2.index(), f, TRUE, flags ); 2675 c2.paragraph()->setFormat( 0, c2.index(), f, TRUE, flags );
2598}
2599
2600void QTextDocument::copySelectedText( int id )
2601{
2602#ifndef QT_NO_CLIPBOARD
2603 if ( !hasSelection( id ) )
2604 return;
2605
2606 QApplication::clipboard()->setText( selectedText( id ) );
2607#endif
2608} 2676}
2609 2677
2610void QTextDocument::removeSelectedText( int id, QTextCursor *cursor ) 2678void QTextDocument::removeSelectedText( int id, QTextCursor *cursor )
2611{ 2679{
2612 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id ); 2680 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2613 if ( it == selections.end() ) 2681 if ( it == selections.end() )
@@ -2629,67 +2697,67 @@ void QTextDocument::removeSelectedText( int id, QTextCursor *cursor )
2629 c2.restoreState(); 2697 c2.restoreState();
2630 c1.restoreState(); 2698 c1.restoreState();
2631 2699
2632 *cursor = c1; 2700 *cursor = c1;
2633 removeSelection( id ); 2701 removeSelection( id );
2634 2702
2635 if ( c1.parag() == c2.parag() ) { 2703 if ( c1.paragraph() == c2.paragraph() ) {
2636 c1.parag()->remove( c1.index(), c2.index() - c1.index() ); 2704 c1.paragraph()->remove( c1.index(), c2.index() - c1.index() );
2637 return; 2705 return;
2638 } 2706 }
2639 2707
2640 if ( c1.parag() == fParag && c1.index() == 0 && 2708 if ( c1.paragraph() == fParag && c1.index() == 0 &&
2641 c2.parag() == lParag && c2.index() == lParag->length() - 1 ) 2709 c2.paragraph() == lParag && c2.index() == lParag->length() - 1 )
2642 cursor->setValid( FALSE ); 2710 cursor->setValid( FALSE );
2643 2711
2644 bool didGoLeft = FALSE; 2712 bool didGoLeft = FALSE;
2645 if ( c1.index() == 0 && c1.parag() != fParag ) { 2713 if ( c1.index() == 0 && c1.paragraph() != fParag ) {
2646 cursor->gotoPreviousLetter(); 2714 cursor->gotoPreviousLetter();
2647 if ( cursor->isValid() ) 2715 if ( cursor->isValid() )
2648 didGoLeft = TRUE; 2716 didGoLeft = TRUE;
2649 } 2717 }
2650 2718
2651 c1.parag()->remove( c1.index(), c1.parag()->length() - 1 - c1.index() ); 2719 c1.paragraph()->remove( c1.index(), c1.paragraph()->length() - 1 - c1.index() );
2652 QTextParag *p = c1.parag()->next(); 2720 QTextParagraph *p = c1.paragraph()->next();
2653 int dy = 0; 2721 int dy = 0;
2654 QTextParag *tmp; 2722 QTextParagraph *tmp;
2655 while ( p && p != c2.parag() ) { 2723 while ( p && p != c2.paragraph() ) {
2656 tmp = p->next(); 2724 tmp = p->next();
2657 dy -= p->rect().height(); 2725 dy -= p->rect().height();
2658 delete p; 2726 delete p;
2659 p = tmp; 2727 p = tmp;
2660 } 2728 }
2661 c2.parag()->remove( 0, c2.index() ); 2729 c2.paragraph()->remove( 0, c2.index() );
2662 while ( p ) { 2730 while ( p ) {
2663 p->move( dy ); 2731 p->move( dy );
2664 p->invalidate( 0 ); 2732 p->invalidate( 0 );
2665 p->setEndState( -1 ); 2733 p->setEndState( -1 );
2666 p = p->next(); 2734 p = p->next();
2667 } 2735 }
2668 2736
2669 c1.parag()->join( c2.parag() ); 2737 c1.paragraph()->join( c2.paragraph() );
2670 2738
2671 if ( didGoLeft ) 2739 if ( didGoLeft )
2672 cursor->gotoNextLetter(); 2740 cursor->gotoNextLetter();
2673} 2741}
2674 2742
2675void QTextDocument::indentSelection( int id ) 2743void QTextDocument::indentSelection( int id )
2676{ 2744{
2677 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id ); 2745 QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
2678 if ( it == selections.end() ) 2746 if ( it == selections.end() )
2679 return; 2747 return;
2680 2748
2681 QTextDocumentSelection sel = *it; 2749 QTextDocumentSelection sel = *it;
2682 QTextParag *startParag = sel.startCursor.parag(); 2750 QTextParagraph *startParag = sel.startCursor.paragraph();
2683 QTextParag *endParag = sel.endCursor.parag(); 2751 QTextParagraph *endParag = sel.endCursor.paragraph();
2684 if ( sel.endCursor.parag()->paragId() < sel.startCursor.parag()->paragId() ) { 2752 if ( sel.endCursor.paragraph()->paragId() < sel.startCursor.paragraph()->paragId() ) {
2685 endParag = sel.startCursor.parag(); 2753 endParag = sel.startCursor.paragraph();
2686 startParag = sel.endCursor.parag(); 2754 startParag = sel.endCursor.paragraph();
2687 } 2755 }
2688 2756
2689 QTextParag *p = startParag; 2757 QTextParagraph *p = startParag;
2690 while ( p && p != endParag ) { 2758 while ( p && p != endParag ) {
2691 p->indent(); 2759 p->indent();
2692 p = p->next(); 2760 p = p->next();
2693 } 2761 }
2694} 2762}
2695 2763
@@ -2705,90 +2773,75 @@ QTextCursor *QTextDocument::undo( QTextCursor *c )
2705 2773
2706QTextCursor *QTextDocument::redo( QTextCursor *c ) 2774QTextCursor *QTextDocument::redo( QTextCursor *c )
2707{ 2775{
2708 return commandHistory->redo( c ); 2776 return commandHistory->redo( c );
2709} 2777}
2710 2778
2711bool QTextDocument::find( const QString &expr, bool cs, bool wo, bool forward, 2779bool QTextDocument::find( QTextCursor& cursor, const QString &e, bool cs, bool wo, bool forward )
2712 int *parag, int *index, QTextCursor *cursor )
2713{ 2780{
2714 QTextParag *p = forward ? fParag : lParag; 2781 removeSelection( Standard );
2715 if ( parag ) 2782 QTextParagraph *p = 0;
2716 p = paragAt( *parag ); 2783 QString expr = e;
2717 else if ( cursor ) 2784 // if we search for 'word only' than we have to be sure that
2718 p = cursor->parag(); 2785 // the expression contains no space or punct character at the
2719 bool first = TRUE; 2786 // beginning or in the end. Otherwise we would run into a
2720 2787 // endlessloop.
2721 while ( p ) { 2788 if ( wo ) {
2722 QString s = p->string()->toString(); 2789 for ( ;; ) {
2723 s.remove( s.length() - 1, 1 ); // get rid of trailing space 2790 if ( expr[ 0 ].isSpace() || expr[ 0 ].isPunct() )
2724 int start = forward ? 0 : s.length() - 1; 2791 expr = expr.right( expr.length() - 1 );
2725 if ( first && index ) 2792 else
2726 start = *index; 2793 break;
2727 else if ( first )
2728 start = cursor->index();
2729 if ( !forward && first ) {
2730 start -= expr.length() + 1;
2731 if ( start < 0 ) {
2732 first = FALSE;
2733 p = p->prev();
2734 continue;
2735 }
2736 } 2794 }
2737 first = FALSE;
2738
2739 for ( ;; ) { 2795 for ( ;; ) {
2740 int res = forward ? s.find( expr, start, cs ) : s.findRev( expr, start, cs ); 2796 if ( expr.at( expr.length() - 1 ).isSpace() || expr.at( expr.length() - 1 ).isPunct() )
2741 if ( res == -1 ) 2797 expr = expr.left( expr.length() - 1 );
2798 else
2742 break; 2799 break;
2743 2800 }
2744 bool ok = TRUE; 2801 }
2745 if ( wo ) { 2802 for (;;) {
2803 if ( p != cursor.paragraph() ) {
2804 p = cursor.paragraph();
2805 QString s = cursor.paragraph()->string()->toString();
2806 int start = cursor.index();
2807 for ( ;; ) {
2808 int res = forward ? s.find( expr, start, cs ) : s.findRev( expr, start, cs );
2746 int end = res + expr.length(); 2809 int end = res + expr.length();
2747 if ( ( res == 0 || s[ res - 1 ].isSpace() || s[ res - 1 ].isPunct() ) && 2810 if ( res == -1 || ( !forward && start < end ) )
2748 ( end == (int)s.length() || s[ end ].isSpace() || s[ end ].isPunct() ) )
2749 ok = TRUE;
2750 else
2751 ok = FALSE;
2752 }
2753 if ( ok ) {
2754 cursor->setParag( p );
2755 cursor->setIndex( res );
2756 setSelectionStart( Standard, cursor );
2757 cursor->setIndex( res + expr.length() );
2758 setSelectionEnd( Standard, cursor );
2759 if ( parag )
2760 *parag = p->paragId();
2761 if ( index )
2762 *index = res;
2763 return TRUE;
2764 }
2765 if ( forward ) {
2766 start = res + 1;
2767 } else {
2768 if ( res == 0 )
2769 break; 2811 break;
2770 start = res - 1; 2812 if ( !wo || ( ( res == 0 || s[ res - 1 ].isSpace() || s[ res - 1 ].isPunct() ) &&
2813 ( end == (int)s.length() || s[ end ].isSpace() || s[ end ].isPunct() ) ) ) {
2814 removeSelection( Standard );
2815 cursor.setIndex( forward ? end : res );
2816 setSelectionStart( Standard, cursor );
2817 cursor.setIndex( forward ? res : end );
2818 setSelectionEnd( Standard, cursor );
2819 return TRUE;
2820 }
2821 start = res + (forward ? 1 : -1);
2771 } 2822 }
2772 } 2823 }
2773 p = forward ? p->next() : p->prev(); 2824 if ( forward ) {
2825 if ( cursor.paragraph() == lastParagraph() && cursor.atParagEnd () )
2826 break;
2827 cursor.gotoNextLetter();
2828 } else {
2829 if ( cursor.paragraph() == firstParagraph() && cursor.atParagStart() )
2830 break;
2831 cursor.gotoPreviousLetter();
2832 }
2774 } 2833 }
2775
2776 return FALSE; 2834 return FALSE;
2777} 2835}
2778 2836
2779void QTextDocument::setTextFormat( Qt::TextFormat f ) 2837void QTextDocument::setTextFormat( Qt::TextFormat f )
2780{ 2838{
2781 txtFormat = f; 2839 txtFormat = f;
2782 if ( txtFormat == Qt::RichText && fParag && fParag == lParag && fParag->length() <= 1 ) { 2840 if ( fParag == lParag && fParag->length() <= 1 )
2783 QPtrVector<QStyleSheetItem> v = fParag->styleSheetItems(); 2841 fParag->rtext = ( f == Qt::RichText );
2784 v.resize( v.size() + 1 );
2785 v.insert( v.size() - 1, styleSheet()->item( "p" ) );
2786 fParag->setStyleSheetItems( v );
2787 }
2788
2789} 2842}
2790 2843
2791Qt::TextFormat QTextDocument::textFormat() const 2844Qt::TextFormat QTextDocument::textFormat() const
2792{ 2845{
2793 return txtFormat; 2846 return txtFormat;
2794} 2847}
@@ -2797,23 +2850,23 @@ bool QTextDocument::inSelection( int selId, const QPoint &pos ) const
2797{ 2850{
2798 QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( selId ); 2851 QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( selId );
2799 if ( it == selections.end() ) 2852 if ( it == selections.end() )
2800 return FALSE; 2853 return FALSE;
2801 2854
2802 QTextDocumentSelection sel = *it; 2855 QTextDocumentSelection sel = *it;
2803 QTextParag *startParag = sel.startCursor.parag(); 2856 QTextParagraph *startParag = sel.startCursor.paragraph();
2804 QTextParag *endParag = sel.endCursor.parag(); 2857 QTextParagraph *endParag = sel.endCursor.paragraph();
2805 if ( sel.startCursor.parag() == sel.endCursor.parag() && 2858 if ( sel.startCursor.paragraph() == sel.endCursor.paragraph() &&
2806 sel.startCursor.parag()->selectionStart( selId ) == sel.endCursor.parag()->selectionEnd( selId ) ) 2859 sel.startCursor.paragraph()->selectionStart( selId ) == sel.endCursor.paragraph()->selectionEnd( selId ) )
2807 return FALSE; 2860 return FALSE;
2808 if ( sel.endCursor.parag()->paragId() < sel.startCursor.parag()->paragId() ) { 2861 if ( sel.endCursor.paragraph()->paragId() < sel.startCursor.paragraph()->paragId() ) {
2809 endParag = sel.startCursor.parag(); 2862 endParag = sel.startCursor.paragraph();
2810 startParag = sel.endCursor.parag(); 2863 startParag = sel.endCursor.paragraph();
2811 } 2864 }
2812 2865
2813 QTextParag *p = startParag; 2866 QTextParagraph *p = startParag;
2814 while ( p ) { 2867 while ( p ) {
2815 if ( p->rect().contains( pos ) ) { 2868 if ( p->rect().contains( pos ) ) {
2816 bool inSel = FALSE; 2869 bool inSel = FALSE;
2817 int selStart = p->selectionStart( selId ); 2870 int selStart = p->selectionStart( selId );
2818 int selEnd = p->selectionEnd( selId ); 2871 int selEnd = p->selectionEnd( selId );
2819 int y = 0; 2872 int y = 0;
@@ -2852,66 +2905,47 @@ void QTextDocument::doLayout( QPainter *p, int w )
2852 withoutDoubleBuffer = ( p != 0 ); 2905 withoutDoubleBuffer = ( p != 0 );
2853 QPainter * oldPainter = QTextFormat::painter(); 2906 QPainter * oldPainter = QTextFormat::painter();
2854 QTextFormat::setPainter( p ); 2907 QTextFormat::setPainter( p );
2855 flow_->setWidth( w ); 2908 flow_->setWidth( w );
2856 cw = w; 2909 cw = w;
2857 vw = w; 2910 vw = w;
2858 QTextParag *parag = fParag; 2911 QTextParagraph *parag = fParag;
2859 while ( parag ) { 2912 while ( parag ) {
2860 parag->invalidate( 0 ); 2913 parag->invalidate( 0 );
2861 if ( p ) 2914 if ( p )
2862 parag->adjustToPainter( p ); 2915 parag->adjustToPainter( p );
2863 parag->format(); 2916 parag->format();
2864 parag = parag->next(); 2917 parag = parag->next();
2865 } 2918 }
2866 QTextFormat::setPainter( oldPainter ); 2919 QTextFormat::setPainter( oldPainter );
2867} 2920}
2868 2921
2869QPixmap *QTextDocument::bufferPixmap( const QSize &s ) 2922QPixmap *QTextDocument::bufferPixmap( const QSize &s )
2870{ 2923{
2871 if ( !buf_pixmap ) { 2924 if ( !buf_pixmap )
2872 int w = QABS( s.width() ); 2925 buf_pixmap = new QPixmap( s.expandedTo( QSize(1,1) ) );
2873 int h = QABS( s.height() ); 2926 else if ( buf_pixmap->size() != s )
2874 buf_pixmap = new QPixmap( w, h ); 2927 buf_pixmap->resize( s.expandedTo( buf_pixmap->size() ) );
2875 } else {
2876 if ( buf_pixmap->width() < s.width() ||
2877 buf_pixmap->height() < s.height() ) {
2878 buf_pixmap->resize( QMAX( s.width(), buf_pixmap->width() ),
2879 QMAX( s.height(), buf_pixmap->height() ) );
2880 }
2881 }
2882
2883 return buf_pixmap; 2928 return buf_pixmap;
2884} 2929}
2885 2930
2886void QTextDocument::draw( QPainter *p, const QRect &rect, const QColorGroup &cg, const QBrush *paper ) 2931void QTextDocument::draw( QPainter *p, const QRect &rect, const QColorGroup &cg, const QBrush *paper )
2887{ 2932{
2888 if ( !firstParag() ) 2933 if ( !firstParagraph() )
2889 return; 2934 return;
2890 2935
2891 if ( paper ) { 2936 if ( paper ) {
2892 p->setBrushOrigin( 0, 0 ); 2937 p->setBrushOrigin( 0, 0 );
2893 2938
2894 p->fillRect( rect, *paper ); 2939 p->fillRect( rect, *paper );
2895 } 2940 }
2896 2941
2897 if ( formatCollection()->defaultFormat()->color() != cg.text() ) { 2942 if ( formatCollection()->defaultFormat()->color() != cg.text() )
2898 QDict<QTextFormat> formats = formatCollection()->dict(); 2943 setDefaultFormat( formatCollection()->defaultFormat()->font(), cg.text() );
2899 QDictIterator<QTextFormat> it( formats );
2900 while ( it.current() ) {
2901 if ( it.current() == formatCollection()->defaultFormat() ) {
2902 ++it;
2903 continue;
2904 }
2905 it.current()->setColor( cg.text() );
2906 ++it;
2907 }
2908 formatCollection()->defaultFormat()->setColor( cg.text() );
2909 }
2910 2944
2911 QTextParag *parag = firstParag(); 2945 QTextParagraph *parag = firstParagraph();
2912 while ( parag ) { 2946 while ( parag ) {
2913 if ( !parag->isValid() ) 2947 if ( !parag->isValid() )
2914 parag->format(); 2948 parag->format();
2915 int y = parag->rect().y(); 2949 int y = parag->rect().y();
2916 QRect pr( parag->rect() ); 2950 QRect pr( parag->rect() );
2917 pr.setX( 0 ); 2951 pr.setX( 0 );
@@ -2929,13 +2963,13 @@ void QTextDocument::draw( QPainter *p, const QRect &rect, const QColorGroup &cg,
2929 parag = parag->next(); 2963 parag = parag->next();
2930 if ( !flow()->isEmpty() ) 2964 if ( !flow()->isEmpty() )
2931 flow()->drawFloatingItems( p, rect.x(), rect.y(), rect.width(), rect.height(), cg, FALSE ); 2965 flow()->drawFloatingItems( p, rect.x(), rect.y(), rect.width(), rect.height(), cg, FALSE );
2932 } 2966 }
2933} 2967}
2934 2968
2935void QTextDocument::drawParag( QPainter *p, QTextParag *parag, int cx, int cy, int cw, int ch, 2969void QTextDocument::drawParagraph( QPainter *p, QTextParagraph *parag, int cx, int cy, int cw, int ch,
2936 QPixmap *&doubleBuffer, const QColorGroup &cg, 2970 QPixmap *&doubleBuffer, const QColorGroup &cg,
2937 bool drawCursor, QTextCursor *cursor, bool resetChanged ) 2971 bool drawCursor, QTextCursor *cursor, bool resetChanged )
2938{ 2972{
2939 QPainter *painter = 0; 2973 QPainter *painter = 0;
2940 if ( resetChanged ) 2974 if ( resetChanged )
2941 parag->setChanged( FALSE ); 2975 parag->setChanged( FALSE );
@@ -2962,29 +2996,17 @@ void QTextDocument::drawParag( QPainter *p, QTextParag *parag, int cx, int cy, i
2962 painter = p; 2996 painter = p;
2963 painter->translate( ir.x(), ir.y() ); 2997 painter->translate( ir.x(), ir.y() );
2964 } 2998 }
2965 2999
2966 painter->setBrushOrigin( -ir.x(), -ir.y() ); 3000 painter->setBrushOrigin( -ir.x(), -ir.y() );
2967 3001
2968 if ( useDoubleBuffer || is_printer( painter ) ) { 3002 if ( useDoubleBuffer || is_printer( painter ) )
2969 if ( !parag->backgroundColor() ) 3003 painter->fillRect( QRect( 0, 0, ir.width(), ir.height() ), parag->backgroundBrush( cg ) );
2970 painter->fillRect( QRect( 0, 0, ir.width(), ir.height() ), 3004 else if ( cursor && cursor->paragraph() == parag )
2971 cg.brush( QColorGroup::Base ) ); 3005 painter->fillRect( QRect( parag->at( cursor->index() )->x, 0, 2, ir.height() ),
2972 else 3006 parag->backgroundBrush( cg ) );
2973 painter->fillRect( QRect( 0, 0, ir.width(), ir.height() ),
2974 *parag->backgroundColor() );
2975 } else {
2976 if ( cursor && cursor->parag() == parag ) {
2977 if ( !parag->backgroundColor() )
2978 painter->fillRect( QRect( parag->at( cursor->index() )->x, 0, 2, ir.height() ),
2979 cg.brush( QColorGroup::Base ) );
2980 else
2981 painter->fillRect( QRect( parag->at( cursor->index() )->x, 0, 2, ir.height() ),
2982 *parag->backgroundColor() );
2983 }
2984 }
2985 3007
2986 painter->translate( -( ir.x() - parag->rect().x() ), 3008 painter->translate( -( ir.x() - parag->rect().x() ),
2987 -( ir.y() - parag->rect().y() ) ); 3009 -( ir.y() - parag->rect().y() ) );
2988 parag->paint( *painter, cg, drawCursor ? cursor : 0, TRUE, cx, cy, cw, ch ); 3010 parag->paint( *painter, cg, drawCursor ? cursor : 0, TRUE, cx, cy, cw, ch );
2989 3011
2990 if ( useDoubleBuffer ) { 3012 if ( useDoubleBuffer ) {
@@ -2992,126 +3014,130 @@ void QTextDocument::drawParag( QPainter *p, QTextParag *parag, int cx, int cy, i
2992 painter = 0; 3014 painter = 0;
2993 p->drawPixmap( ir.topLeft(), *doubleBuffer, QRect( QPoint( 0, 0 ), ir.size() ) ); 3015 p->drawPixmap( ir.topLeft(), *doubleBuffer, QRect( QPoint( 0, 0 ), ir.size() ) );
2994 } else { 3016 } else {
2995 painter->translate( -ir.x(), -ir.y() ); 3017 painter->translate( -ir.x(), -ir.y() );
2996 } 3018 }
2997 3019
2998 if ( parag->rect().x() + parag->rect().width() < parag->document()->x() + parag->document()->width() ) { 3020 if ( useDoubleBuffer ) {
2999 p->fillRect( parag->rect().x() + parag->rect().width(), parag->rect().y(), 3021 if ( parag->rect().x() + parag->rect().width() < parag->document()->x() + parag->document()->width() ) {
3000 ( parag->document()->x() + parag->document()->width() ) - 3022 p->fillRect( parag->rect().x() + parag->rect().width(), parag->rect().y(),
3001 ( parag->rect().x() + parag->rect().width() ), 3023 ( parag->document()->x() + parag->document()->width() ) -
3002 parag->rect().height(), cg.brush( QColorGroup::Base ) ); 3024 ( parag->rect().x() + parag->rect().width() ),
3025 parag->rect().height(), cg.brush( QColorGroup::Base ) );
3026 }
3003 } 3027 }
3004 3028
3005 parag->document()->nextDoubleBuffered = FALSE; 3029 parag->document()->nextDoubleBuffered = FALSE;
3006} 3030}
3007 3031
3008QTextParag *QTextDocument::draw( QPainter *p, int cx, int cy, int cw, int ch, const QColorGroup &cg, 3032QTextParagraph *QTextDocument::draw( QPainter *p, int cx, int cy, int cw, int ch, const QColorGroup &cg,
3009 bool onlyChanged, bool drawCursor, QTextCursor *cursor, bool resetChanged ) 3033 bool onlyChanged, bool drawCursor, QTextCursor *cursor, bool resetChanged )
3010{ 3034{
3011 if ( withoutDoubleBuffer || par && par->withoutDoubleBuffer ) { 3035 if ( withoutDoubleBuffer || par && par->withoutDoubleBuffer ) {
3012 withoutDoubleBuffer = TRUE; 3036 withoutDoubleBuffer = TRUE;
3013 QRect r; 3037 QRect r;
3014 draw( p, r, cg ); 3038 draw( p, r, cg );
3015 return 0; 3039 return 0;
3016 } 3040 }
3017 withoutDoubleBuffer = FALSE; 3041 withoutDoubleBuffer = FALSE;
3018 3042
3019 if ( !firstParag() ) 3043 if ( !firstParagraph() )
3020 return 0; 3044 return 0;
3021 3045
3022 if ( drawCursor && cursor )
3023 tmpCursor = cursor;
3024 if ( cx < 0 && cy < 0 ) { 3046 if ( cx < 0 && cy < 0 ) {
3025 cx = 0; 3047 cx = 0;
3026 cy = 0; 3048 cy = 0;
3027 cw = width(); 3049 cw = width();
3028 ch = height(); 3050 ch = height();
3029 } 3051 }
3030 3052
3031 QTextParag *lastFormatted = 0; 3053 QTextParagraph *lastFormatted = 0;
3032 QTextParag *parag = firstParag(); 3054 QTextParagraph *parag = firstParagraph();
3033 3055
3034 QPixmap *doubleBuffer = 0; 3056 QPixmap *doubleBuffer = 0;
3035 QPainter painter; 3057 QPainter painter;
3036 3058
3059 bool fullWidthSelection = FALSE;
3037 while ( parag ) { 3060 while ( parag ) {
3038 lastFormatted = parag; 3061 lastFormatted = parag;
3039 if ( !parag->isValid() ) 3062 if ( !parag->isValid() )
3040 parag->format(); 3063 parag->format();
3041 3064
3042 if ( !parag->rect().intersects( QRect( cx, cy, cw, ch ) ) ) { 3065 QRect pr = parag->rect();
3043 QRect pr( parag->rect() ); 3066 if ( fullWidthSelection )
3044 pr.setWidth( parag->document()->width() ); 3067 pr.setWidth( parag->document()->width() );
3045 if ( pr.intersects( QRect( cx, cy, cw, ch ) ) ) 3068 if ( pr.y() > cy + ch )
3046 p->fillRect( pr.intersect( QRect( cx, cy, cw, ch ) ), cg.brush( QColorGroup::Base ) ); 3069 goto floating;
3047 if ( parag->rect().y() > cy + ch ) { 3070 if ( !pr.intersects( QRect( cx, cy, cw, ch ) ) || ( onlyChanged && !parag->hasChanged() ) ) {
3048 tmpCursor = 0;
3049 goto floating;
3050 }
3051 parag = parag->next();
3052 continue;
3053 }
3054
3055 if ( !parag->hasChanged() && onlyChanged ) {
3056 parag = parag->next(); 3071 parag = parag->next();
3057 continue; 3072 continue;
3058 } 3073 }
3059 3074
3060 drawParag( p, parag, cx, cy, cw, ch, doubleBuffer, cg, drawCursor, cursor, resetChanged ); 3075 drawParagraph( p, parag, cx, cy, cw, ch, doubleBuffer, cg, drawCursor, cursor, resetChanged );
3061 parag = parag->next(); 3076 parag = parag->next();
3062 } 3077 }
3063 3078
3064 parag = lastParag(); 3079 parag = lastParagraph();
3065 3080
3066 floating: 3081 floating:
3067 if ( parag->rect().y() + parag->rect().height() < parag->document()->height() ) { 3082 if ( parag->rect().y() + parag->rect().height() < parag->document()->height() ) {
3068 if ( !parag->document()->parent() ) { // !useDoubleBuffer 3083 if ( !parag->document()->parent() ) {
3069 p->fillRect( 0, parag->rect().y() + parag->rect().height(), parag->document()->width(), 3084 p->fillRect( 0, parag->rect().y() + parag->rect().height(), parag->document()->width(),
3070 parag->document()->height() - ( parag->rect().y() + parag->rect().height() ), 3085 parag->document()->height() - ( parag->rect().y() + parag->rect().height() ),
3071 cg.brush( QColorGroup::Base ) ); 3086 cg.brush( QColorGroup::Base ) );
3072 } 3087 }
3073 if ( !flow()->isEmpty() ) { 3088 if ( !flow()->isEmpty() ) {
3074 QRect cr( cx, cy, cw, ch ); 3089 QRect cr( cx, cy, cw, ch );
3075 // cr = cr.intersect( QRect( 0, parag->rect().y() + parag->rect().height(), parag->document()->width(),
3076 // parag->document()->height() - ( parag->rect().y() + parag->rect().height() ) ) );
3077 flow()->drawFloatingItems( p, cr.x(), cr.y(), cr.width(), cr.height(), cg, FALSE ); 3090 flow()->drawFloatingItems( p, cr.x(), cr.y(), cr.width(), cr.height(), cg, FALSE );
3078 } 3091 }
3079 } 3092 }
3080 3093
3081 if ( buf_pixmap && buf_pixmap->height() > 300 ) { 3094 if ( buf_pixmap && buf_pixmap->height() > 300 ) {
3082 delete buf_pixmap; 3095 delete buf_pixmap;
3083 buf_pixmap = 0; 3096 buf_pixmap = 0;
3084 } 3097 }
3085 3098
3086 tmpCursor = 0;
3087 return lastFormatted; 3099 return lastFormatted;
3088} 3100}
3089 3101
3090void QTextDocument::setDefaultFont( const QFont &f ) 3102/*
3103 #### this function only sets the default font size in the format collection
3104 */
3105void QTextDocument::setDefaultFormat( const QFont &font, const QColor &color )
3091{ 3106{
3092 int s = f.pointSize(); 3107 bool reformat = font != fCollection->defaultFormat()->font();
3093 bool usePixels = FALSE; 3108 for ( QTextDocument *d = childList.first(); d; d = childList.next() )
3094 if ( s == -1 ) { 3109 d->setDefaultFormat( font, color );
3095 s = f.pixelSize(); 3110 fCollection->updateDefaultFormat( font, color, sheet_ );
3096 usePixels = TRUE; 3111
3112 if ( !reformat )
3113 return;
3114 tStopWidth = formatCollection()->defaultFormat()->width( 'x' ) * 8;
3115
3116 // invalidate paragraphs and custom items
3117 QTextParagraph *p = fParag;
3118 while ( p ) {
3119 p->invalidate( 0 );
3120 for ( int i = 0; i < p->length() - 1; ++i )
3121 if ( p->at( i )->isCustom() )
3122 p->at( i )->customItem()->invalidate();
3123 p = p->next();
3097 } 3124 }
3098 updateFontSizes( s, usePixels );
3099} 3125}
3100 3126
3101void QTextDocument::registerCustomItem( QTextCustomItem *i, QTextParag *p ) 3127void QTextDocument::registerCustomItem( QTextCustomItem *i, QTextParagraph *p )
3102{ 3128{
3103 if ( i && i->placement() != QTextCustomItem::PlaceInline ) { 3129 if ( i && i->placement() != QTextCustomItem::PlaceInline ) {
3104 flow_->registerFloatingItem( i ); 3130 flow_->registerFloatingItem( i );
3105 p->registerFloatingItem( i ); 3131 p->registerFloatingItem( i );
3106 i->setParagraph( p ); 3132 i->setParagraph( p );
3107 } 3133 }
3108 p->mightHaveCustomItems = mightHaveCustomItems = TRUE; 3134 p->mightHaveCustomItems = mightHaveCustomItems = TRUE;
3109} 3135}
3110 3136
3111void QTextDocument::unregisterCustomItem( QTextCustomItem *i, QTextParag *p ) 3137void QTextDocument::unregisterCustomItem( QTextCustomItem *i, QTextParagraph *p )
3112{ 3138{
3113 flow_->unregisterFloatingItem( i ); 3139 flow_->unregisterFloatingItem( i );
3114 p->unregisterFloatingItem( i ); 3140 p->unregisterFloatingItem( i );
3115 i->setParagraph( 0 ); 3141 i->setParagraph( 0 );
3116} 3142}
3117 3143
@@ -3140,13 +3166,13 @@ bool QTextDocument::focusNextPrevChild( bool next )
3140 } else { 3166 } else {
3141 focusIndicator.parag->setChanged( TRUE ); 3167 focusIndicator.parag->setChanged( TRUE );
3142 } 3168 }
3143 focusIndicator.href = QString::null; 3169 focusIndicator.href = QString::null;
3144 3170
3145 if ( next ) { 3171 if ( next ) {
3146 QTextParag *p = focusIndicator.parag; 3172 QTextParagraph *p = focusIndicator.parag;
3147 int index = focusIndicator.start + focusIndicator.len; 3173 int index = focusIndicator.start + focusIndicator.len;
3148 while ( p ) { 3174 while ( p ) {
3149 for ( int i = index; i < p->length(); ++i ) { 3175 for ( int i = index; i < p->length(); ++i ) {
3150 if ( p->at( i )->isAnchor() ) { 3176 if ( p->at( i )->isAnchor() ) {
3151 p->setChanged( TRUE ); 3177 p->setChanged( TRUE );
3152 focusIndicator.parag = p; 3178 focusIndicator.parag = p;
@@ -3199,13 +3225,13 @@ bool QTextDocument::focusNextPrevChild( bool next )
3199 } 3225 }
3200 } 3226 }
3201 index = 0; 3227 index = 0;
3202 p = p->next(); 3228 p = p->next();
3203 } 3229 }
3204 } else { 3230 } else {
3205 QTextParag *p = focusIndicator.parag; 3231 QTextParagraph *p = focusIndicator.parag;
3206 int index = focusIndicator.start - 1; 3232 int index = focusIndicator.start - 1;
3207 if ( focusIndicator.len == 0 && index < focusIndicator.parag->length() - 1 ) 3233 if ( focusIndicator.len == 0 && index < focusIndicator.parag->length() - 1 )
3208 index++; 3234 index++;
3209 while ( p ) { 3235 while ( p ) {
3210 for ( int i = index; i >= 0; --i ) { 3236 for ( int i = index; i >= 0; --i ) {
3211 if ( p->at( i )->isAnchor() ) { 3237 if ( p->at( i )->isAnchor() ) {
@@ -3279,13 +3305,13 @@ bool QTextDocument::focusNextPrevChild( bool next )
3279 return FALSE; 3305 return FALSE;
3280} 3306}
3281 3307
3282int QTextDocument::length() const 3308int QTextDocument::length() const
3283{ 3309{
3284 int l = 0; 3310 int l = 0;
3285 QTextParag *p = fParag; 3311 QTextParagraph *p = fParag;
3286 while ( p ) { 3312 while ( p ) {
3287 l += p->length() - 1; // don't count trailing space 3313 l += p->length() - 1; // don't count trailing space
3288 p = p->next(); 3314 p = p->next();
3289 } 3315 }
3290 return l; 3316 return l;
3291} 3317}
@@ -3382,37 +3408,42 @@ QTextString::QTextString( const QTextString &s )
3382 dir = s.dir; 3408 dir = s.dir;
3383 data = s.subString(); 3409 data = s.subString();
3384} 3410}
3385 3411
3386void QTextString::insert( int index, const QString &s, QTextFormat *f ) 3412void QTextString::insert( int index, const QString &s, QTextFormat *f )
3387{ 3413{
3414 insert( index, s.unicode(), s.length(), f );
3415}
3416
3417void QTextString::insert( int index, const QChar *unicode, int len, QTextFormat *f )
3418{
3388 int os = data.size(); 3419 int os = data.size();
3389 data.resize( data.size() + s.length() ); 3420 data.resize( data.size() + len );
3390 if ( index < os ) { 3421 if ( index < os ) {
3391 memmove( data.data() + index + s.length(), data.data() + index, 3422 memmove( data.data() + index + len, data.data() + index,
3392 sizeof( QTextStringChar ) * ( os - index ) ); 3423 sizeof( QTextStringChar ) * ( os - index ) );
3393 } 3424 }
3394 for ( int i = 0; i < (int)s.length(); ++i ) { 3425 for ( int i = 0; i < len; ++i ) {
3395 data[ (int)index + i ].x = 0; 3426 data[ (int)index + i ].x = 0;
3396 data[ (int)index + i ].lineStart = 0; 3427 data[ (int)index + i ].lineStart = 0;
3397 data[ (int)index + i ].d.format = 0; 3428 data[ (int)index + i ].d.format = 0;
3398 data[ (int)index + i ].type = QTextStringChar::Regular; 3429 data[ (int)index + i ].type = QTextStringChar::Regular;
3399 data[ (int)index + i ].rightToLeft = 0; 3430 data[ (int)index + i ].rightToLeft = 0;
3400 data[ (int)index + i ].startOfRun = 0; 3431 data[ (int)index + i ].startOfRun = 0;
3401 data[ (int)index + i ].c = s[ i ]; 3432 data[ (int)index + i ].c = unicode[i];
3402 data[ (int)index + i ].setFormat( f ); 3433 data[ (int)index + i ].setFormat( f );
3403 } 3434 }
3404 bidiDirty = TRUE; 3435 bidiDirty = TRUE;
3405} 3436}
3406 3437
3407QTextString::~QTextString() 3438QTextString::~QTextString()
3408{ 3439{
3409 clear(); 3440 clear();
3410} 3441}
3411 3442
3412void QTextString::insert( int index, QTextStringChar *c ) 3443void QTextString::insert( int index, QTextStringChar *c, bool doAddRefFormat )
3413{ 3444{
3414 int os = data.size(); 3445 int os = data.size();
3415 data.resize( data.size() + 1 ); 3446 data.resize( data.size() + 1 );
3416 if ( index < os ) { 3447 if ( index < os ) {
3417 memmove( data.data() + index + 1, data.data() + index, 3448 memmove( data.data() + index + 1, data.data() + index,
3418 sizeof( QTextStringChar ) * ( os - index ) ); 3449 sizeof( QTextStringChar ) * ( os - index ) );
@@ -3420,12 +3451,14 @@ void QTextString::insert( int index, QTextStringChar *c )
3420 data[ (int)index ].c = c->c; 3451 data[ (int)index ].c = c->c;
3421 data[ (int)index ].x = 0; 3452 data[ (int)index ].x = 0;
3422 data[ (int)index ].lineStart = 0; 3453 data[ (int)index ].lineStart = 0;
3423 data[ (int)index ].rightToLeft = 0; 3454 data[ (int)index ].rightToLeft = 0;
3424 data[ (int)index ].d.format = 0; 3455 data[ (int)index ].d.format = 0;
3425 data[ (int)index ].type = QTextStringChar::Regular; 3456 data[ (int)index ].type = QTextStringChar::Regular;
3457 if ( doAddRefFormat && c->format() )
3458 c->format()->addRef();
3426 data[ (int)index ].setFormat( c->format() ); 3459 data[ (int)index ].setFormat( c->format() );
3427 bidiDirty = TRUE; 3460 bidiDirty = TRUE;
3428} 3461}
3429 3462
3430void QTextString::truncate( int index ) 3463void QTextString::truncate( int index )
3431{ 3464{
@@ -3542,52 +3575,47 @@ void QTextString::checkBidi() const
3542 3575
3543void QTextDocument::setStyleSheet( QStyleSheet *s ) 3576void QTextDocument::setStyleSheet( QStyleSheet *s )
3544{ 3577{
3545 if ( !s ) 3578 if ( !s )
3546 return; 3579 return;
3547 sheet_ = s; 3580 sheet_ = s;
3548 fCollection->setStyleSheet( s ); 3581 list_tm = list_bm = par_tm = par_bm = 12;
3549 updateStyles(); 3582 list_lm = 40;
3550} 3583 li_tm = li_bm = 0;
3551 3584 QStyleSheetItem* item = s->item( "ol" );
3552void QTextDocument::updateStyles() 3585 if ( item ) {
3553{ 3586 list_tm = QMAX(0,item->margin( QStyleSheetItem::MarginTop ));
3554 invalidate(); 3587 list_bm = QMAX(0,item->margin( QStyleSheetItem::MarginBottom ));
3555 if ( par ) 3588 list_lm = QMAX(0,item->margin( QStyleSheetItem::MarginLeft ));
3556 underlLinks = par->underlLinks; 3589 }
3557 fCollection->updateStyles(); 3590 if ( (item = s->item( "li" ) ) ) {
3558 for ( QTextDocument *d = childList.first(); d; d = childList.next() ) 3591 li_tm = QMAX(0,item->margin( QStyleSheetItem::MarginTop ));
3559 d->updateStyles(); 3592 li_bm = QMAX(0,item->margin( QStyleSheetItem::MarginBottom ));
3560} 3593 }
3561 3594 if ( (item = s->item( "p" ) ) ) {
3562void QTextDocument::updateFontSizes( int base, bool usePixels ) 3595 par_tm = QMAX(0,item->margin( QStyleSheetItem::MarginTop ));
3563{ 3596 par_bm = QMAX(0,item->margin( QStyleSheetItem::MarginBottom ));
3564 for ( QTextDocument *d = childList.first(); d; d = childList.next() ) 3597 }
3565 d->updateFontSizes( base, usePixels );
3566 invalidate();
3567 fCollection->updateFontSizes( base, usePixels );
3568} 3598}
3569 3599
3570void QTextDocument::updateFontAttributes( const QFont &f, const QFont &old ) 3600void QTextDocument::setUnderlineLinks( bool b ) {
3571{ 3601 underlLinks = b;
3572 for ( QTextDocument *d = childList.first(); d; d = childList.next() ) 3602 for ( QTextDocument *d = childList.first(); d; d = childList.next() )
3573 d->updateFontAttributes( f, old ); 3603 d->setUnderlineLinks( b );
3574 invalidate();
3575 fCollection->updateFontAttributes( f, old );
3576} 3604}
3577 3605
3578void QTextStringChar::setFormat( QTextFormat *f ) 3606void QTextStringChar::setFormat( QTextFormat *f )
3579{ 3607{
3580 if ( type == Regular ) { 3608 if ( type == Regular ) {
3581 d.format = f; 3609 d.format = f;
3582 } else { 3610 } else {
3583 if ( !d.custom ) { 3611 if ( !d.custom ) {
3584 d.custom = new CustomData; 3612 d.custom = new CustomData;
3585 d.custom->custom = 0; 3613 d.custom->custom = 0;
3586 } 3614 }
3587 d.custom->format = f; 3615 d.custom->format = f;
3588 } 3616 }
3589} 3617}
3590 3618
3591void QTextStringChar::setCustomItem( QTextCustomItem *i ) 3619void QTextStringChar::setCustomItem( QTextCustomItem *i )
3592{ 3620{
3593 if ( type == Regular ) { 3621 if ( type == Regular ) {
@@ -3648,13 +3676,13 @@ void QTextStringChar::setAnchor( const QString& name, const QString& href )
3648 3676
3649 3677
3650int QTextString::width( int idx ) const 3678int QTextString::width( int idx ) const
3651{ 3679{
3652 int w = 0; 3680 int w = 0;
3653 QTextStringChar *c = &at( idx ); 3681 QTextStringChar *c = &at( idx );
3654 if ( c->c.unicode() == 0xad ) 3682 if ( c->c.unicode() == 0xad || c->c.unicode() == 0x2028 )
3655 return 0; 3683 return 0;
3656 if( c->isCustom() ) { 3684 if( c->isCustom() ) {
3657 if( c->customItem()->placement() == QTextCustomItem::PlaceInline ) 3685 if( c->customItem()->placement() == QTextCustomItem::PlaceInline )
3658 w = c->customItem()->width; 3686 w = c->customItem()->width;
3659 } else { 3687 } else {
3660 int r = c->c.row(); 3688 int r = c->c.row();
@@ -3696,93 +3724,66 @@ QMemArray<QTextStringChar> QTextString::subString( int start, int len ) const
3696 if ( c->format() ) 3724 if ( c->format() )
3697 c->format()->addRef(); 3725 c->format()->addRef();
3698 } 3726 }
3699 return a; 3727 return a;
3700} 3728}
3701 3729
3702QTextStringChar *QTextStringChar::clone() const
3703{
3704 QTextStringChar *chr = new QTextStringChar;
3705 chr->c = c;
3706 chr->x = 0;
3707 chr->lineStart = 0;
3708 chr->rightToLeft = 0;
3709 chr->d.format = 0;
3710 chr->type = QTextStringChar::Regular;
3711 chr->setFormat( format() );
3712 if ( chr->format() )
3713 chr->format()->addRef();
3714 return chr;
3715}
3716
3717// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3730// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3718 3731
3719QTextParag::QTextParag( QTextDocument *d, QTextParag *pr, QTextParag *nx, bool updateIds ) 3732QTextParagraph::QTextParagraph( QTextDocument *d, QTextParagraph *pr, QTextParagraph *nx, bool updateIds )
3720 : invalid( 0 ), p( pr ), n( nx ), docOrPseudo( d ), align( 0 ),mSelections( 0 ), 3733 : invalid( 0 ), p( pr ), n( nx ), docOrPseudo( d ),
3721 mStyleSheetItemsVec( 0 ), mFloatingItems( 0 ), listS( QStyleSheetItem::ListDisc ), 3734 changed(FALSE), firstFormat(TRUE), firstPProcess(TRUE), needPreProcess(FALSE), fullWidth(TRUE),
3722 numSubParag( -1 ), tm( -1 ), bm( -1 ), lm( -1 ), rm( -1 ), flm( -1 ), 3735 lastInFrame(FALSE), visible(TRUE), breakable(TRUE), movedDown(FALSE),
3723 tArray(0), tabStopWidth(0), eData( 0 ) 3736 mightHaveCustomItems(FALSE), hasdoc( d != 0 ), litem(FALSE), rtext(FALSE),
3724{ 3737 align( 0 ),mSelections( 0 ),
3725 listS = QStyleSheetItem::ListDisc; 3738 mFloatingItems( 0 ), lstyle( QStyleSheetItem::ListDisc ),
3726 if ( ! (hasdoc = docOrPseudo != 0 ) ) 3739 utm( 0 ), ubm( 0 ), ulm( 0 ), urm( 0 ), uflm( 0 ), ulinespacing( 0 ),
3727 docOrPseudo = new QTextParagPseudoDocument; 3740 tArray(0), tabStopWidth(0), eData( 0 ), ldepth( 0 )
3741{
3742 lstyle = QStyleSheetItem::ListDisc;
3743 if ( !hasdoc )
3744 docOrPseudo = new QTextParagraphPseudoDocument;
3728 bgcol = 0; 3745 bgcol = 0;
3729 breakable = TRUE;
3730 isBr = FALSE;
3731 movedDown = FALSE;
3732 mightHaveCustomItems = FALSE;
3733 visible = TRUE;
3734 list_val = -1; 3746 list_val = -1;
3735 newLinesAllowed = FALSE; 3747 QTextFormat* defFormat = formatCollection()->defaultFormat();
3736 lastInFrame = FALSE;
3737 defFormat = formatCollection()->defaultFormat();
3738 if ( !hasdoc ) { 3748 if ( !hasdoc ) {
3739 tabStopWidth = defFormat->width( 'x' ) * 8; 3749 tabStopWidth = defFormat->width( 'x' ) * 8;
3740 pseudoDocument()->commandHistory = new QTextCommandHistory( 100 ); 3750 pseudoDocument()->commandHistory = new QTextCommandHistory( 100 );
3741 } 3751 }
3742#if defined(PARSER_DEBUG)
3743 qDebug( debug_indent + "new QTextParag" );
3744#endif
3745 fullWidth = TRUE;
3746 3752
3747 if ( p ) 3753 if ( p )
3748 p->n = this; 3754 p->n = this;
3749 if ( n ) 3755 if ( n )
3750 n->p = this; 3756 n->p = this;
3751 3757
3752 3758
3753 if ( !p && hasdoc ) 3759 if ( !p && hasdoc )
3754 document()->setFirstParag( this ); 3760 document()->setFirstParagraph( this );
3755 if ( !n && hasdoc ) 3761 if ( !n && hasdoc )
3756 document()->setLastParag( this ); 3762 document()->setLastParagraph( this );
3757 3763
3758 changed = FALSE;
3759 firstFormat = TRUE;
3760 state = -1; 3764 state = -1;
3761 needPreProcess = FALSE;
3762 3765
3763 if ( p ) 3766 if ( p )
3764 id = p->id + 1; 3767 id = p->id + 1;
3765 else 3768 else
3766 id = 0; 3769 id = 0;
3767 if ( n && updateIds ) { 3770 if ( n && updateIds ) {
3768 QTextParag *s = n; 3771 QTextParagraph *s = n;
3769 while ( s ) { 3772 while ( s ) {
3770 s->id = s->p->id + 1; 3773 s->id = s->p->id + 1;
3771 s->numSubParag = -1; 3774 s->invalidateStyleCache();
3772 s->lm = s->rm = s->tm = s->bm = -1, s->flm = -1;
3773 s = s->n; 3775 s = s->n;
3774 } 3776 }
3775 } 3777 }
3776 firstPProcess = TRUE;
3777 3778
3778 str = new QTextString(); 3779 str = new QTextString();
3779 str->insert( 0, " ", formatCollection()->defaultFormat() ); 3780 str->insert( 0, " ", formatCollection()->defaultFormat() );
3780} 3781}
3781 3782
3782QTextParag::~QTextParag() 3783QTextParagraph::~QTextParagraph()
3783{ 3784{
3784 delete str; 3785 delete str;
3785 if ( hasdoc ) { 3786 if ( hasdoc ) {
3786 register QTextDocument *doc = document(); 3787 register QTextDocument *doc = document();
3787 if ( this == doc->minwParag ) { 3788 if ( this == doc->minwParag ) {
3788 doc->minwParag = 0; 3789 doc->minwParag = 0;
@@ -3793,73 +3794,83 @@ QTextParag::~QTextParag()
3793 } else { 3794 } else {
3794 delete pseudoDocument(); 3795 delete pseudoDocument();
3795 } 3796 }
3796 if ( tArray ) 3797 if ( tArray )
3797 delete [] tArray; 3798 delete [] tArray;
3798 delete eData; 3799 delete eData;
3799 QMap<int, QTextParagLineStart*>::Iterator it = lineStarts.begin(); 3800 QMap<int, QTextLineStart*>::Iterator it = lineStarts.begin();
3800 for ( ; it != lineStarts.end(); ++it ) 3801 for ( ; it != lineStarts.end(); ++it )
3801 delete *it; 3802 delete *it;
3802 if ( mSelections ) 3803 if ( mSelections )
3803 delete mSelections; 3804 delete mSelections;
3804 if ( mFloatingItems ) 3805 if ( mFloatingItems )
3805 delete mFloatingItems; 3806 delete mFloatingItems;
3806 if ( mStyleSheetItemsVec )
3807 delete mStyleSheetItemsVec;
3808 if ( p ) 3807 if ( p )
3809 p->setNext( n ); 3808 p->setNext( n );
3810 if ( n ) 3809 if ( n )
3811 n->setPrev( p ); 3810 n->setPrev( p );
3812} 3811}
3813 3812
3814void QTextParag::setNext( QTextParag *s ) 3813void QTextParagraph::setNext( QTextParagraph *s )
3815{ 3814{
3816 n = s; 3815 n = s;
3817 if ( !n && hasdoc ) 3816 if ( !n && hasdoc )
3818 document()->setLastParag( this ); 3817 document()->setLastParagraph( this );
3819} 3818}
3820 3819
3821void QTextParag::setPrev( QTextParag *s ) 3820void QTextParagraph::setPrev( QTextParagraph *s )
3822{ 3821{
3823 p = s; 3822 p = s;
3824 if ( !p && hasdoc ) 3823 if ( !p && hasdoc )
3825 document()->setFirstParag( this ); 3824 document()->setFirstParagraph( this );
3826} 3825}
3827 3826
3828void QTextParag::invalidate( int chr ) 3827void QTextParagraph::invalidate( int chr )
3829{ 3828{
3830 if ( invalid < 0 ) 3829 if ( invalid < 0 )
3831 invalid = chr; 3830 invalid = chr;
3832 else 3831 else
3833 invalid = QMIN( invalid, chr ); 3832 invalid = QMIN( invalid, chr );
3834 if ( mFloatingItems ) { 3833 if ( mFloatingItems ) {
3835 for ( QTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() ) 3834 for ( QTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() )
3836 i->ypos = -1; 3835 i->ypos = -1;
3837 } 3836 }
3838 lm = rm = bm = tm = flm = -1; 3837 invalidateStyleCache();
3839} 3838}
3840 3839
3841void QTextParag::insert( int index, const QString &s ) 3840void QTextParagraph::invalidateStyleCache()
3841{
3842 if ( list_val < 0 )
3843 list_val = -1;
3844}
3845
3846
3847void QTextParagraph::insert( int index, const QString &s )
3848{
3849 insert( index, s.unicode(), s.length() );
3850}
3851
3852void QTextParagraph::insert( int index, const QChar *unicode, int len )
3842{ 3853{
3843 if ( hasdoc && !document()->useFormatCollection() && document()->preProcessor() ) 3854 if ( hasdoc && !document()->useFormatCollection() && document()->preProcessor() )
3844 str->insert( index, s, 3855 str->insert( index, unicode, len,
3845 document()->preProcessor()->format( QTextPreProcessor::Standard ) ); 3856 document()->preProcessor()->format( QTextPreProcessor::Standard ) );
3846 else 3857 else
3847 str->insert( index, s, formatCollection()->defaultFormat() ); 3858 str->insert( index, unicode, len, formatCollection()->defaultFormat() );
3848 invalidate( index ); 3859 invalidate( index );
3849 needPreProcess = TRUE; 3860 needPreProcess = TRUE;
3850} 3861}
3851 3862
3852void QTextParag::truncate( int index ) 3863void QTextParagraph::truncate( int index )
3853{ 3864{
3854 str->truncate( index ); 3865 str->truncate( index );
3855 insert( length(), " " ); 3866 insert( length(), " " );
3856 needPreProcess = TRUE; 3867 needPreProcess = TRUE;
3857} 3868}
3858 3869
3859void QTextParag::remove( int index, int len ) 3870void QTextParagraph::remove( int index, int len )
3860{ 3871{
3861 if ( index + len - str->length() > 0 ) 3872 if ( index + len - str->length() > 0 )
3862 return; 3873 return;
3863 for ( int i = index; i < index + len; ++i ) { 3874 for ( int i = index; i < index + len; ++i ) {
3864 QTextStringChar *c = at( i ); 3875 QTextStringChar *c = at( i );
3865 if ( hasdoc && c->isCustom() ) { 3876 if ( hasdoc && c->isCustom() ) {
@@ -3868,20 +3879,20 @@ void QTextParag::remove( int index, int len )
3868 } 3879 }
3869 str->remove( index, len ); 3880 str->remove( index, len );
3870 invalidate( 0 ); 3881 invalidate( 0 );
3871 needPreProcess = TRUE; 3882 needPreProcess = TRUE;
3872} 3883}
3873 3884
3874void QTextParag::join( QTextParag *s ) 3885void QTextParagraph::join( QTextParagraph *s )
3875{ 3886{
3876 int oh = r.height() + s->r.height(); 3887 int oh = r.height() + s->r.height();
3877 n = s->n; 3888 n = s->n;
3878 if ( n ) 3889 if ( n )
3879 n->p = this; 3890 n->p = this;
3880 else if ( hasdoc ) 3891 else if ( hasdoc )
3881 document()->setLastParag( this ); 3892 document()->setLastParagraph( this );
3882 3893
3883 int start = str->length(); 3894 int start = str->length();
3884 if ( length() > 0 && at( length() - 1 )->c == ' ' ) { 3895 if ( length() > 0 && at( length() - 1 )->c == ' ' ) {
3885 remove( length() - 1, 1 ); 3896 remove( length() - 1, 1 );
3886 --start; 3897 --start;
3887 } 3898 }
@@ -3893,12 +3904,16 @@ void QTextParag::join( QTextParag *s )
3893 str->setFormat( i + start, s->str->at( i ).format(), TRUE ); 3904 str->setFormat( i + start, s->str->at( i ).format(), TRUE );
3894 } 3905 }
3895 if ( s->str->at( i ).isCustom() ) { 3906 if ( s->str->at( i ).isCustom() ) {
3896 QTextCustomItem * item = s->str->at( i ).customItem(); 3907 QTextCustomItem * item = s->str->at( i ).customItem();
3897 str->at( i + start ).setCustomItem( item ); 3908 str->at( i + start ).setCustomItem( item );
3898 s->str->at( i ).loseCustomItem(); 3909 s->str->at( i ).loseCustomItem();
3910 if ( hasdoc ) {
3911 document()->unregisterCustomItem( item, s );
3912 document()->registerCustomItem( item, this );
3913 }
3899 } 3914 }
3900 if ( s->str->at( i ).isAnchor() ) { 3915 if ( s->str->at( i ).isAnchor() ) {
3901 str->at( i + start ).setAnchor( s->str->at( i ).anchorName(), 3916 str->at( i + start ).setAnchor( s->str->at( i ).anchorName(),
3902 s->str->at( i ).anchorHref() ); 3917 s->str->at( i ).anchorHref() );
3903 } 3918 }
3904 } 3919 }
@@ -3911,26 +3926,28 @@ void QTextParag::join( QTextParag *s )
3911 } 3926 }
3912 delete s; 3927 delete s;
3913 invalidate( 0 ); 3928 invalidate( 0 );
3914 r.setHeight( oh ); 3929 r.setHeight( oh );
3915 needPreProcess = TRUE; 3930 needPreProcess = TRUE;
3916 if ( n ) { 3931 if ( n ) {
3917 QTextParag *s = n; 3932 QTextParagraph *s = n;
3933 s->invalidate( 0 );
3918 while ( s ) { 3934 while ( s ) {
3919 s->id = s->p->id + 1; 3935 s->id = s->p->id + 1;
3920 s->state = -1; 3936 s->state = -1;
3921 s->needPreProcess = TRUE; 3937 s->needPreProcess = TRUE;
3922 s->changed = TRUE; 3938 s->changed = TRUE;
3939 s->invalidateStyleCache();
3923 s = s->n; 3940 s = s->n;
3924 } 3941 }
3925 } 3942 }
3926 format(); 3943 format();
3927 state = -1; 3944 state = -1;
3928} 3945}
3929 3946
3930void QTextParag::move( int &dy ) 3947void QTextParagraph::move( int &dy )
3931{ 3948{
3932 if ( dy == 0 ) 3949 if ( dy == 0 )
3933 return; 3950 return;
3934 changed = TRUE; 3951 changed = TRUE;
3935 r.moveBy( 0, dy ); 3952 r.moveBy( 0, dy );
3936 if ( mFloatingItems ) { 3953 if ( mFloatingItems ) {
@@ -3948,13 +3965,13 @@ void QTextParag::move( int &dy )
3948 p->setChanged( TRUE ); 3965 p->setChanged( TRUE );
3949 dy += shift; 3966 dy += shift;
3950 } 3967 }
3951 } 3968 }
3952} 3969}
3953 3970
3954void QTextParag::format( int start, bool doMove ) 3971void QTextParagraph::format( int start, bool doMove )
3955{ 3972{
3956 if ( !str || str->length() == 0 || !formatter() ) 3973 if ( !str || str->length() == 0 || !formatter() )
3957 return; 3974 return;
3958 3975
3959 if ( hasdoc && 3976 if ( hasdoc &&
3960 document()->preProcessor() && 3977 document()->preProcessor() &&
@@ -3963,58 +3980,58 @@ void QTextParag::format( int start, bool doMove )
3963 needPreProcess = FALSE; 3980 needPreProcess = FALSE;
3964 3981
3965 if ( invalid == -1 ) 3982 if ( invalid == -1 )
3966 return; 3983 return;
3967 3984
3968 r.moveTopLeft( QPoint( documentX(), p ? p->r.y() + p->r.height() : documentY() ) ); 3985 r.moveTopLeft( QPoint( documentX(), p ? p->r.y() + p->r.height() : documentY() ) );
3969 r.setWidth( documentWidth() );
3970 if ( p ) 3986 if ( p )
3971 p->lastInFrame = FALSE; 3987 p->lastInFrame = FALSE;
3972 3988
3973 movedDown = FALSE; 3989 movedDown = FALSE;
3974 bool formattedAgain = FALSE; 3990 bool formattedAgain = FALSE;
3975 3991
3976 formatAgain: 3992 formatAgain:
3977 3993
3994 r.setWidth( documentWidth() );
3978 if ( hasdoc && mFloatingItems ) { 3995 if ( hasdoc && mFloatingItems ) {
3979 for ( QTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() ) { 3996 for ( QTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() ) {
3980 i->ypos = r.y(); 3997 i->ypos = r.y();
3981 if ( i->placement() == QTextCustomItem::PlaceRight ) { 3998 if ( i->placement() == QTextCustomItem::PlaceRight ) {
3982 i->xpos = r.x() + r.width() - i->width; 3999 i->xpos = r.x() + r.width() - i->width;
3983 } 4000 }
3984 } 4001 }
3985 } 4002 }
3986 QMap<int, QTextParagLineStart*> oldLineStarts = lineStarts; 4003 QMap<int, QTextLineStart*> oldLineStarts = lineStarts;
3987 lineStarts.clear(); 4004 lineStarts.clear();
3988 int y = formatter()->format( document(), this, start, oldLineStarts ); 4005 int y = formatter()->format( document(), this, start, oldLineStarts );
3989 4006
3990 4007
3991 r.setWidth( QMAX( r.width(), formatter()->minimumWidth() ) ); 4008 r.setWidth( QMAX( r.width(), formatter()->minimumWidth() ) );
3992 4009
3993 4010
3994 QMap<int, QTextParagLineStart*>::Iterator it = oldLineStarts.begin(); 4011 QMap<int, QTextLineStart*>::Iterator it = oldLineStarts.begin();
3995 4012
3996 for ( ; it != oldLineStarts.end(); ++it ) 4013 for ( ; it != oldLineStarts.end(); ++it )
3997 delete *it; 4014 delete *it;
3998 4015
3999 QTextStringChar *c = 0; 4016 QTextStringChar *c = 0;
4000 // do not do this on mac, as the paragraph 4017 // do not do this on mac, as the paragraph
4001 // with has to be the full document width on mac as the selections 4018 // with has to be the full document width on mac as the selections
4002 // always extend completely to the right. This is a bit unefficient, 4019 // always extend completely to the right. This is a bit unefficient,
4003 // as this results in a bigger double buffer than needed but ok for 4020 // as this results in a bigger double buffer than needed but ok for
4004 // now. 4021 // now.
4005 if ( lineStarts.count() == 1 ) { //&& ( !doc || document()->flow()->isEmpty() ) ) { 4022 if ( lineStarts.count() == 1 ) {
4006 if ( !string()->isBidi() ) { 4023 if ( !string()->isBidi() ) {
4007 c = &str->at( str->length() - 1 ); 4024 c = &str->at( str->length() - 1 );
4008 r.setWidth( c->x + str->width( str->length() - 1 ) ); 4025 r.setWidth( c->x + str->width( str->length() - 1 ) );
4009 } else { 4026 } else {
4010 r.setWidth( lineStarts[0]->w ); 4027 r.setWidth( lineStarts[0]->w );
4011 } 4028 }
4012 } 4029 }
4013 4030
4014 if ( newLinesAllowed ) { 4031 if ( !hasdoc ) { // qt_format_text bounding rect handling
4015 it = lineStarts.begin(); 4032 it = lineStarts.begin();
4016 int usedw = 0; 4033 int usedw = 0;
4017 for ( ; it != lineStarts.end(); ++it ) 4034 for ( ; it != lineStarts.end(); ++it )
4018 usedw = QMAX( usedw, (*it)->w ); 4035 usedw = QMAX( usedw, (*it)->w );
4019 if ( r.width() <= 0 ) { 4036 if ( r.width() <= 0 ) {
4020 // if the user specifies an invalid rect, this means that the 4037 // if the user specifies an invalid rect, this means that the
@@ -4051,13 +4068,13 @@ void QTextParag::format( int start, bool doMove )
4051 goto formatAgain; 4068 goto formatAgain;
4052 } 4069 }
4053 } 4070 }
4054 4071
4055 if ( n && doMove && n->invalid == -1 && r.y() + r.height() != n->r.y() ) { 4072 if ( n && doMove && n->invalid == -1 && r.y() + r.height() != n->r.y() ) {
4056 int dy = ( r.y() + r.height() ) - n->r.y(); 4073 int dy = ( r.y() + r.height() ) - n->r.y();
4057 QTextParag *s = n; 4074 QTextParagraph *s = n;
4058 bool makeInvalid = p && p->lastInFrame; 4075 bool makeInvalid = p && p->lastInFrame;
4059 while ( s && dy ) { 4076 while ( s && dy ) {
4060 if ( !s->isFullWidth() ) 4077 if ( !s->isFullWidth() )
4061 makeInvalid = TRUE; 4078 makeInvalid = TRUE;
4062 if ( makeInvalid ) 4079 if ( makeInvalid )
4063 s->invalidate( 0 ); 4080 s->invalidate( 0 );
@@ -4071,18 +4088,18 @@ void QTextParag::format( int start, bool doMove )
4071 firstFormat = FALSE; 4088 firstFormat = FALSE;
4072 changed = TRUE; 4089 changed = TRUE;
4073 invalid = -1; 4090 invalid = -1;
4074 //##### string()->setTextChanged( FALSE ); 4091 //##### string()->setTextChanged( FALSE );
4075} 4092}
4076 4093
4077int QTextParag::lineHeightOfChar( int i, int *bl, int *y ) const 4094int QTextParagraph::lineHeightOfChar( int i, int *bl, int *y ) const
4078{ 4095{
4079 if ( !isValid() ) 4096 if ( !isValid() )
4080 ( (QTextParag*)this )->format(); 4097 ( (QTextParagraph*)this )->format();
4081 4098
4082 QMap<int, QTextParagLineStart*>::ConstIterator it = lineStarts.end(); 4099 QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.end();
4083 --it; 4100 --it;
4084 for ( ;; ) { 4101 for ( ;; ) {
4085 if ( i >= it.key() ) { 4102 if ( i >= it.key() ) {
4086 if ( bl ) 4103 if ( bl )
4087 *bl = ( *it )->baseLine; 4104 *bl = ( *it )->baseLine;
4088 if ( y ) 4105 if ( y )
@@ -4091,23 +4108,23 @@ int QTextParag::lineHeightOfChar( int i, int *bl, int *y ) const
4091 } 4108 }
4092 if ( it == lineStarts.begin() ) 4109 if ( it == lineStarts.begin() )
4093 break; 4110 break;
4094 --it; 4111 --it;
4095 } 4112 }
4096 4113
4097 qWarning( "QTextParag::lineHeightOfChar: couldn't find lh for %d", i ); 4114 qWarning( "QTextParagraph::lineHeightOfChar: couldn't find lh for %d", i );
4098 return 15; 4115 return 15;
4099} 4116}
4100 4117
4101QTextStringChar *QTextParag::lineStartOfChar( int i, int *index, int *line ) const 4118QTextStringChar *QTextParagraph::lineStartOfChar( int i, int *index, int *line ) const
4102{ 4119{
4103 if ( !isValid() ) 4120 if ( !isValid() )
4104 ( (QTextParag*)this )->format(); 4121 ( (QTextParagraph*)this )->format();
4105 4122
4106 int l = (int)lineStarts.count() - 1; 4123 int l = (int)lineStarts.count() - 1;
4107 QMap<int, QTextParagLineStart*>::ConstIterator it = lineStarts.end(); 4124 QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.end();
4108 --it; 4125 --it;
4109 for ( ;; ) { 4126 for ( ;; ) {
4110 if ( i >= it.key() ) { 4127 if ( i >= it.key() ) {
4111 if ( index ) 4128 if ( index )
4112 *index = it.key(); 4129 *index = it.key();
4113 if ( line ) 4130 if ( line )
@@ -4117,67 +4134,67 @@ QTextStringChar *QTextParag::lineStartOfChar( int i, int *index, int *line ) con
4117 if ( it == lineStarts.begin() ) 4134 if ( it == lineStarts.begin() )
4118 break; 4135 break;
4119 --it; 4136 --it;
4120 --l; 4137 --l;
4121 } 4138 }
4122 4139
4123 qWarning( "QTextParag::lineStartOfChar: couldn't find %d", i ); 4140 qWarning( "QTextParagraph::lineStartOfChar: couldn't find %d", i );
4124 return 0; 4141 return 0;
4125} 4142}
4126 4143
4127int QTextParag::lines() const 4144int QTextParagraph::lines() const
4128{ 4145{
4129 if ( !isValid() ) 4146 if ( !isValid() )
4130 ( (QTextParag*)this )->format(); 4147 ( (QTextParagraph*)this )->format();
4131 4148
4132 return (int)lineStarts.count(); 4149 return (int)lineStarts.count();
4133} 4150}
4134 4151
4135QTextStringChar *QTextParag::lineStartOfLine( int line, int *index ) const 4152QTextStringChar *QTextParagraph::lineStartOfLine( int line, int *index ) const
4136{ 4153{
4137 if ( !isValid() ) 4154 if ( !isValid() )
4138 ( (QTextParag*)this )->format(); 4155 ( (QTextParagraph*)this )->format();
4139 4156
4140 if ( line >= 0 && line < (int)lineStarts.count() ) { 4157 if ( line >= 0 && line < (int)lineStarts.count() ) {
4141 QMap<int, QTextParagLineStart*>::ConstIterator it = lineStarts.begin(); 4158 QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.begin();
4142 while ( line-- > 0 ) 4159 while ( line-- > 0 )
4143 ++it; 4160 ++it;
4144 int i = it.key(); 4161 int i = it.key();
4145 if ( index ) 4162 if ( index )
4146 *index = i; 4163 *index = i;
4147 return &str->at( i ); 4164 return &str->at( i );
4148 } 4165 }
4149 4166
4150 qWarning( "QTextParag::lineStartOfLine: couldn't find %d", line ); 4167 qWarning( "QTextParagraph::lineStartOfLine: couldn't find %d", line );
4151 return 0; 4168 return 0;
4152} 4169}
4153 4170
4154int QTextParag::leftGap() const 4171int QTextParagraph::leftGap() const
4155{ 4172{
4156 if ( !isValid() ) 4173 if ( !isValid() )
4157 ( (QTextParag*)this )->format(); 4174 ( (QTextParagraph*)this )->format();
4158 4175
4159 int line = 0; 4176 int line = 0;
4160 int x = str->at(0).x; /* set x to x of first char */ 4177 int x = str->at(0).x; /* set x to x of first char */
4161 if ( str->isBidi() ) { 4178 if ( str->isBidi() ) {
4162 for ( int i = 1; i < str->length(); ++i ) 4179 for ( int i = 1; i < str->length()-1; ++i )
4163 x = QMIN(x, str->at(i).x); 4180 x = QMIN(x, str->at(i).x);
4164 return x; 4181 return x;
4165 } 4182 }
4166 4183
4167 QMap<int, QTextParagLineStart*>::ConstIterator it = lineStarts.begin(); 4184 QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.begin();
4168 while (line < (int)lineStarts.count()) { 4185 while (line < (int)lineStarts.count()) {
4169 int i = it.key(); /* char index */ 4186 int i = it.key(); /* char index */
4170 x = QMIN(x, str->at(i).x); 4187 x = QMIN(x, str->at(i).x);
4171 ++it; 4188 ++it;
4172 ++line; 4189 ++line;
4173 } 4190 }
4174 return x; 4191 return x;
4175} 4192}
4176 4193
4177void QTextParag::setFormat( int index, int len, QTextFormat *f, bool useCollection, int flags ) 4194void QTextParagraph::setFormat( int index, int len, QTextFormat *f, bool useCollection, int flags )
4178{ 4195{
4179 if ( !f ) 4196 if ( !f )
4180 return; 4197 return;
4181 if ( index < 0 ) 4198 if ( index < 0 )
4182 index = 0; 4199 index = 0;
4183 if ( index > str->length() - 1 ) 4200 if ( index > str->length() - 1 )
@@ -4209,274 +4226,201 @@ void QTextParag::setFormat( int index, int len, QTextFormat *f, bool useCollecti
4209 QTextFormat *fm = fc->format( of, f, flags ); 4226 QTextFormat *fm = fc->format( of, f, flags );
4210 str->setFormat( i + index, fm, useCollection ); 4227 str->setFormat( i + index, fm, useCollection );
4211 } 4228 }
4212 } 4229 }
4213} 4230}
4214 4231
4215void QTextParag::indent( int *oldIndent, int *newIndent ) 4232void QTextParagraph::indent( int *oldIndent, int *newIndent )
4216{ 4233{
4217 if ( !hasdoc || !document()->indent() || style() && style()->displayMode() != QStyleSheetItem::DisplayBlock ) { 4234 if ( !hasdoc || !document()->indent() || isListItem() ) {
4218 if ( oldIndent ) 4235 if ( oldIndent )
4219 *oldIndent = 0; 4236 *oldIndent = 0;
4220 if ( newIndent ) 4237 if ( newIndent )
4221 *newIndent = 0; 4238 *newIndent = 0;
4222 if ( oldIndent && newIndent ) 4239 if ( oldIndent && newIndent )
4223 *newIndent = *oldIndent; 4240 *newIndent = *oldIndent;
4224 return; 4241 return;
4225 } 4242 }
4226 document()->indent()->indent( document(), this, oldIndent, newIndent ); 4243 document()->indent()->indent( document(), this, oldIndent, newIndent );
4227} 4244}
4228 4245
4229void QTextParag::paint( QPainter &painter, const QColorGroup &cg, QTextCursor *cursor, bool drawSelections, 4246void QTextParagraph::paint( QPainter &painter, const QColorGroup &cg, QTextCursor *cursor, bool drawSelections,
4230 int clipx, int clipy, int clipw, int cliph ) 4247 int clipx, int clipy, int clipw, int cliph )
4231{ 4248{
4232 if ( !visible ) 4249 if ( !visible )
4233 return; 4250 return;
4234 QTextStringChar *chr = at( 0 ); 4251 QTextStringChar *chr = 0;
4235 int i = 0; 4252 int i, y, h, baseLine, xstart, xend;
4236 int h = 0; 4253 i = y =h = baseLine = 0;
4237 int baseLine = 0, lastBaseLine = 0; 4254 QRect cursorRect;
4238 QTextStringChar *formatChar = 0; 4255 drawSelections &= ( mSelections != 0 );
4239 int lastY = -1; 4256 // macintosh full-width selection style
4240 int startX = 0; 4257 bool fullWidthStyle = FALSE;
4241 int bw = 0; 4258 int fullSelectionWidth = 0;
4242 int cy = 0; 4259 if ( drawSelections && fullWidthStyle )
4243 int curx = -1, cury = 0, curh = 0; 4260 fullSelectionWidth = (hasdoc ? document()->width() : r.width());
4244 bool lastDirection = chr->rightToLeft; 4261
4245 const int full_sel_width = (hasdoc ? document()->width() : r.width());
4246#if 0 // seems we don't need that anymore
4247 int tw = 0;
4248#endif
4249
4250 QString qstr = str->toString(); 4262 QString qstr = str->toString();
4251 // ### workaround so that \n are not drawn, actually this should be 4263 // ### workaround so that \n are not drawn, actually this should
4252 // fixed in QFont somewhere (under Windows you get ugly boxes 4264 // be fixed in QFont somewhere (under Windows you get ugly boxes
4253 // otherwise) 4265 // otherwise)
4254 QChar* uc = (QChar*) qstr.unicode(); 4266 QChar* uc = (QChar*) qstr.unicode();
4255 for ( uint ii = 0; ii < qstr.length(); ii++ ) { 4267 for ( uint ii = 0; ii < qstr.length(); ii++ )
4256 if ( uc[(int)ii]== '\n' ) 4268 if ( uc[(int)ii]== '\n' || uc[(int)ii] == QChar_linesep || uc[(int)ii] == '\t' )
4257 uc[(int)ii] = 0x20; 4269 uc[(int)ii] = 0x20;
4258 }
4259
4260
4261 const int nSels = hasdoc ? document()->numSelections() : 1;
4262 QMemArray<int> selectionStarts( nSels );
4263 QMemArray<int> selectionEnds( nSels );
4264 if ( drawSelections ) {
4265 bool hasASelection = FALSE;
4266 for ( i = 0; i < nSels; ++i ) {
4267 if ( !hasSelection( i ) ) {
4268 selectionStarts[ i ] = -1;
4269 selectionEnds[ i ] = -1;
4270 } else {
4271 hasASelection = TRUE;
4272 selectionStarts[ i ] = selectionStart( i );
4273 int end = selectionEnd( i );
4274 if ( end == length() - 1 && n && n->hasSelection( i ) )
4275 end++;
4276 selectionEnds[ i ] = end;
4277 }
4278 }
4279 if ( !hasASelection )
4280 drawSelections = FALSE;
4281 }
4282 4270
4283 int line = -1; 4271 int line = -1;
4284 int cw;
4285 bool didListLabel = FALSE;
4286 int paintStart = 0; 4272 int paintStart = 0;
4287 int paintEnd = -1; 4273 int selection = -1;
4288 int lasth = 0;
4289 for ( i = 0; i < length(); i++ ) { 4274 for ( i = 0; i < length(); i++ ) {
4290 chr = at( i ); 4275 chr = at( i );
4291#if 0 // seems we don't need that anymore 4276
4292 if ( !str->isBidi() && is_printer( &painter ) ) { // ### fix our broken ps-printer 4277 // we flush at end of document
4293 if ( !chr->lineStart ) 4278 bool flush = i== length()-1;
4294 chr->x = QMAX( chr->x, tw ); 4279 bool selectionStateChanged = FALSE;
4295 else 4280 if ( !flush ) {
4296 tw = 0; 4281 QTextStringChar *nextchr = at( i+1 );
4282 // we flush at end of line
4283 flush |= nextchr->lineStart;
4284 // we flush on format changes
4285 flush |= ( nextchr->format() != chr->format() );
4286 // we flush on anchor changes
4287 flush |= ( nextchr->isAnchor() != chr->isAnchor() );
4288 // we flush on start of run
4289 flush |= nextchr->startOfRun;
4290 // we flush on bidi changes
4291 flush |= ( nextchr->rightToLeft != chr->rightToLeft );
4292 // we flush on tab
4293 flush |= ( chr->c == '\t' );
4294 // we flush on soft hypens
4295 flush |= ( chr->c.unicode() == 0xad );
4296 // we flush on custom items
4297 flush |= chr->isCustom();
4298 // we flush before custom items
4299 flush |= nextchr->isCustom();
4300 // when painting justified, we flush on spaces
4301 if ((alignment() & Qt3::AlignJustify) == Qt3::AlignJustify )
4302 flush |= QTextFormatter::isBreakable( str, i );
4303 // we flush when the string is getting too long
4304 flush |= ( i - paintStart >= 256 );
4305 // we flush when the selection state changes
4306 if ( drawSelections ) {
4307 for ( QMap<int, QTextParagraphSelection>::ConstIterator it = mSelections->begin();
4308 it != mSelections->end(); ++it )
4309 selectionStateChanged |=( (*it).start == i || (*it).start == i+1 || (*it).end == i+1 );
4310 flush |= selectionStateChanged;
4311 }
4297 } 4312 }
4298#endif
4299 cw = string()->width( i );
4300 if ( chr->c == '\t' && i < length() - 1 )
4301 cw = at( i + 1 )->x - chr->x + 1;
4302 if ( chr->c.unicode() == 0xad && i < length() - 1 )
4303 cw = 0;
4304 4313
4305 // init a new line 4314 // init a new line
4306 if ( chr->lineStart ) { 4315 if ( chr->lineStart ) {
4307#if 0 // seems we don't need that anymore 4316 if (fullWidthStyle && drawSelections && selection >= 0)
4308 tw = 0; 4317 painter.fillRect( xend, y, fullSelectionWidth - xend, h,
4309#endif 4318 (selection == QTextDocument::Standard || !hasdoc) ?
4319 cg.color( QColorGroup::Highlight ) :
4320 document()->selectionColor( selection ) );
4310 ++line; 4321 ++line;
4311 lineInfo( line, cy, h, baseLine ); 4322 paintStart = i;
4312 lasth = h; 4323 lineInfo( line, y, h, baseLine );
4313 if ( clipy != -1 && cy > clipy - r.y() + cliph ) // outside clip area, leave 4324 if ( clipy != -1 && cliph != 0 && y + r.y() - h > clipy + cliph ) { // outside clip area, leave
4314 break; 4325 break;
4315 if ( lastBaseLine == 0 ) 4326 }
4316 lastBaseLine = baseLine;
4317 }
4318 4327
4319 // draw bullet list items 4328 // if this is the first line and we are a list item, draw the the bullet label
4320 if ( !didListLabel && line == 0 && style() && style()->displayMode() == QStyleSheetItem::DisplayListItem ) { 4329 if ( line == 0 && isListItem() )
4321 didListLabel = TRUE; 4330 drawLabel( &painter, chr->x, y, 0, 0, baseLine, cg );
4322 drawLabel( &painter, chr->x, cy, 0, 0, baseLine, cg );
4323 } 4331 }
4324 4332
4325 // check for cursor mark 4333 // check for cursor mark
4326 if ( cursor && this == cursor->parag() && i == cursor->index() ) { 4334 if ( cursor && this == cursor->paragraph() && i == cursor->index() ) {
4327 curx = cursor->x(); 4335 QTextStringChar *c = i == 0 ? chr : chr - 1;
4328 QTextStringChar *c = chr; 4336 cursorRect.setRect( cursor->x() , y + baseLine - c->format()->ascent(),
4329 if ( i > 0 ) 4337 1, c->format()->height() );
4330 --c;
4331 curh = c->format()->height();
4332 cury = cy + baseLine - c->format()->ascent();
4333 }
4334
4335 // first time - start again...
4336 if ( !formatChar || lastY == -1 ) {
4337 formatChar = chr;
4338 lastY = cy;
4339 startX = chr->x;
4340 if ( !chr->isCustom() && chr->c != '\n' )
4341 paintEnd = i;
4342 bw = cw;
4343 if ( !chr->isCustom() )
4344 continue;
4345 } 4338 }
4346 4339
4347 // check if selection state changed 4340 // check if we are in a selection and store which one it is
4348 bool selectionChange = FALSE; 4341 selection = -1;
4349 if ( drawSelections ) { 4342 if ( drawSelections ) {
4350 for ( int j = 0; j < nSels; ++j ) { 4343 for ( QMap<int, QTextParagraphSelection>::ConstIterator it = mSelections->begin();
4351 selectionChange = selectionStarts[ j ] == i || selectionEnds[ j ] == i; 4344 it != mSelections->end(); ++it )
4352 if ( selectionChange ) 4345 if ( (*it).start <= i && i < (*it).end + ( (*it).end == length()-1 && n && n->hasSelection(it.key()) ) ? 1:0
4346 // exclude the standard selection from printing
4347 && (it.key() != QTextDocument::Standard || !is_printer( &painter) ) ) {
4348 selection = it.key();
4353 break; 4349 break;
4354 } 4350 }
4355 } 4351 }
4356 4352
4357 //if something (format, etc.) changed, draw what we have so far 4353 if ( flush ) { // something changed, draw what we have so far
4358 if ( ( ( ( alignment() & Qt3::AlignJustify ) == Qt3::AlignJustify && at(paintEnd)->c.isSpace() ) || 4354 if ( chr->rightToLeft ) {
4359 lastDirection != (bool)chr->rightToLeft || 4355 xstart = chr->x;
4360 chr->startOfRun || 4356 xend = at( paintStart )->x + str->width( paintStart );
4361 lastY != cy || chr->format() != formatChar->format() || chr->isAnchor() != formatChar->isAnchor() ||
4362 ( paintEnd != -1 && at( paintEnd )->c =='\t' ) || chr->c == '\t' ||
4363 ( paintEnd != -1 && at( paintEnd )->c.unicode() == 0xad ) || chr->c.unicode() == 0xad ||
4364 selectionChange || chr->isCustom() ) ) {
4365 if ( paintStart <= paintEnd ) {
4366 // ### temporary hack until I get the new placement/shaping stuff working
4367 int x = startX;
4368 if ( ( alignment() & Qt3::AlignJustify ) == Qt3::AlignJustify && paintEnd != -1 &&
4369 paintEnd > 1 && at( paintEnd )->c.isSpace() ) {
4370 int add = str->at(paintEnd).x - str->at(paintEnd-1).x - str->width(paintEnd-1);
4371 bw += ( lastDirection ? 0 : add );
4372 }
4373 drawParagString( painter, qstr, paintStart, paintEnd - paintStart + 1, x, lastY,
4374 lastBaseLine, bw, lasth, drawSelections,
4375 formatChar, i, selectionStarts, selectionEnds, cg, lastDirection );
4376 }
4377#if 0 // seems we don't need that anymore
4378 if ( !str->isBidi() && is_printer( &painter ) ) { // ### fix our broken ps-printer
4379 if ( !chr->lineStart ) {
4380 // ### the next line doesn't look 100% correct for arabic
4381 tw = startX + painter.fontMetrics().width( qstr.mid(paintStart, paintEnd - paintStart +1) );
4382 chr->x = QMAX( chr->x, tw );
4383 } else {
4384 tw = 0;
4385 }
4386 }
4387#endif
4388 if ( !chr->isCustom() ) {
4389 if ( chr->c != '\n' ) {
4390 paintStart = i;
4391 paintEnd = i;
4392 } else {
4393 paintStart = i+1;
4394 paintEnd = -1;
4395 }
4396 formatChar = chr;
4397 lastY = cy;
4398 startX = chr->x;
4399 bw = cw;
4400 } else { 4357 } else {
4401 if ( chr->customItem()->placement() == QTextCustomItem::PlaceInline ) { 4358 xstart = at( paintStart )->x;
4402 chr->customItem()->draw( &painter, chr->x, cy, clipx - r.x(), clipy - r.y(), clipw, cliph, cg, 4359 if ( !selectionStateChanged && i < length() - 1 && !str->at( i + 1 ).lineStart )
4403 nSels && selectionStarts[ 0 ] <= i && selectionEnds[ 0 ] >= i ); 4360 xend = str->at( i + 1 ).x;
4404 paintStart = i+1; 4361 else
4405 paintEnd = -1; 4362 xend = chr->x + str->width( i );
4406 formatChar = chr;
4407 lastY = cy;
4408 startX = chr->x + string()->width( i );
4409 bw = 0;
4410 } else {
4411 chr->customItem()->resize( chr->customItem()->width );
4412 paintStart = i+1;
4413 paintEnd = -1;
4414 formatChar = chr;
4415 lastY = cy;
4416 startX = chr->x + string()->width( i );
4417 bw = 0;
4418 }
4419 } 4363 }
4420 } else { 4364
4421 if ( chr->c != '\n' ) { 4365 if ( (clipx == -1 || clipw == -1) || (xend >= clipx && xstart <= clipx + clipw) ) {
4422 if( chr->rightToLeft ) { 4366 if ( !chr->isCustom() )
4423 startX = chr->x; 4367 drawString( painter, qstr, paintStart, i - paintStart + 1, xstart, y,
4424 } 4368 baseLine, xend-xstart, h, selection,
4425 paintEnd = i; 4369 chr, cg, chr->rightToLeft );
4370 else if ( chr->customItem()->placement() == QTextCustomItem::PlaceInline )
4371 chr->customItem()->draw( &painter, chr->x, y,
4372 clipx == -1 ? clipx : (clipx - r.x()),
4373 clipy == -1 ? clipy : (clipy - r.y()),
4374 clipw, cliph, cg, selection >= 0 );
4426 } 4375 }
4427 bw += cw; 4376 paintStart = i+1;
4428 } 4377 }
4429 lastBaseLine = baseLine; 4378
4430 lasth = h;
4431 lastDirection = chr->rightToLeft;
4432 } 4379 }
4433 4380
4434 // if we are through the parag, but still have some stuff left to draw, draw it now 4381 if (fullWidthStyle && drawSelections && selection >= 0 && next() && next()->mSelections)
4435 if ( paintStart <= paintEnd ) { 4382 for ( QMap<int, QTextParagraphSelection>::ConstIterator it = next()->mSelections->begin();
4436 bool selectionChange = FALSE; 4383 it != next()->mSelections->end(); ++it )
4437 if ( drawSelections ) { 4384 if (((*it).start) == 0) {
4438 for ( int j = 0; j < nSels; ++j ) { 4385 painter.fillRect( xend, y, fullSelectionWidth - xend, h,
4439 selectionChange = selectionStarts[ j ] == i || selectionEnds[ j ] == i; 4386 (selection == QTextDocument::Standard || !hasdoc) ?
4440 if ( selectionChange ) 4387 cg.color( QColorGroup::Highlight ) :
4441 break; 4388 document()->selectionColor( selection ) );
4389 break;
4442 } 4390 }
4443 }
4444 int x = startX;
4445 drawParagString( painter, qstr, paintStart, paintEnd-paintStart+1, x, lastY,
4446 lastBaseLine, bw, h, drawSelections,
4447 formatChar, i, selectionStarts, selectionEnds, cg, lastDirection );
4448 }
4449 4391
4450 // if we should draw a cursor, draw it now 4392 // time to draw the cursor
4451 if ( curx != -1 && cursor ) { 4393 const int cursor_extent = 4;
4452 painter.fillRect( QRect( curx, cury, 1, curh - lineSpacing() ), cg.color( QColorGroup::Text ) ); 4394 if ( !cursorRect.isNull() && cursor &&
4395 ((clipx == -1 || clipw == -1) || (cursorRect.right()+cursor_extent >= clipx && cursorRect.left()-cursor_extent <= clipx + clipw)) ) {
4396 painter.fillRect( cursorRect, cg.color( QColorGroup::Text ) );
4453 painter.save(); 4397 painter.save();
4454 if ( string()->isBidi() ) { 4398 if ( string()->isBidi() ) {
4455 const int d = 4;
4456 if ( at( cursor->index() )->rightToLeft ) { 4399 if ( at( cursor->index() )->rightToLeft ) {
4457 painter.setPen( Qt::black ); 4400 painter.setPen( Qt::black );
4458 painter.drawLine( curx, cury, curx - d / 2, cury + d / 2 ); 4401 painter.drawLine( cursorRect.x(), cursorRect.y(), cursorRect.x() - cursor_extent / 2, cursorRect.y() + cursor_extent / 2 );
4459 painter.drawLine( curx, cury + d, curx - d / 2, cury + d / 2 ); 4402 painter.drawLine( cursorRect.x(), cursorRect.y() + cursor_extent, cursorRect.x() - cursor_extent / 2, cursorRect.y() + cursor_extent / 2 );
4460 } else { 4403 } else {
4461 painter.setPen( Qt::black ); 4404 painter.setPen( Qt::black );
4462 painter.drawLine( curx, cury, curx + d / 2, cury + d / 2 ); 4405 painter.drawLine( cursorRect.x(), cursorRect.y(), cursorRect.x() + cursor_extent / 2, cursorRect.y() + cursor_extent / 2 );
4463 painter.drawLine( curx, cury + d, curx + d / 2, cury + d / 2 ); 4406 painter.drawLine( cursorRect.x(), cursorRect.y() + cursor_extent, cursorRect.x() + cursor_extent / 2, cursorRect.y() + cursor_extent / 2 );
4464 } 4407 }
4465 } 4408 }
4466 painter.restore(); 4409 painter.restore();
4467 } 4410 }
4468} 4411}
4469 4412
4470//#define BIDI_DEBUG 4413//#define BIDI_DEBUG
4471 4414
4472void QTextParag::drawParagString( QPainter &painter, const QString &s, int start, int len, int startX, 4415void QTextParagraph::drawString( QPainter &painter, const QString &s, int start, int len, int xstart,
4473 int lastY, int baseLine, int bw, int h, bool drawSelections, 4416 int y, int baseLine, int w, int h, int selection,
4474 QTextStringChar *formatChar, int i, const QMemArray<int> &selectionStarts, 4417 QTextStringChar *formatChar, const QColorGroup& cg,
4475 const QMemArray<int> &selectionEnds, const QColorGroup &cg, bool rightToLeft ) 4418 bool rightToLeft )
4476{ 4419{
4420 int i = start + len - 1;
4477 bool plainText = hasdoc ? document()->textFormat() == Qt::PlainText : FALSE; 4421 bool plainText = hasdoc ? document()->textFormat() == Qt::PlainText : FALSE;
4478 QTextFormat* format = formatChar->format(); 4422 QTextFormat* format = formatChar->format();
4479 QString str( s ); 4423 QString str( s );
4480 if ( str[ (int)str.length() - 1 ].unicode() == 0xad ) 4424 if ( str[ (int)str.length() - 1 ].unicode() == 0xad )
4481 str.remove( str.length() - 1, 1 ); 4425 str.remove( str.length() - 1, 1 );
4482 if ( !plainText || hasdoc && format->color() != document()->formatCollection()->defaultFormat()->color() ) 4426 if ( !plainText || hasdoc && format->color() != document()->formatCollection()->defaultFormat()->color() )
@@ -4496,116 +4440,114 @@ void QTextParag::drawParagString( QPainter &painter, const QString &s, int start
4496 QFont fn = format->font(); 4440 QFont fn = format->font();
4497 fn.setUnderline( TRUE ); 4441 fn.setUnderline( TRUE );
4498 painter.setFont( fn ); 4442 painter.setFont( fn );
4499 } 4443 }
4500 } 4444 }
4501 4445
4502 if ( drawSelections ) { 4446 if ( selection >= 0 ) {
4503 const int nSels = hasdoc ? document()->numSelections() : 1; 4447 if ( !hasdoc || document()->invertSelectionText( selection ) )
4504 const int startSel = is_printer( 0 ) ? 1 : 0; 4448 painter.setPen( cg.color( QColorGroup::HighlightedText ) );
4505 for ( int j = startSel; j < nSels; ++j ) { 4449 painter.fillRect( xstart, y, w, h,
4506 if ( i > selectionStarts[ j ] && i <= selectionEnds[ j ] ) { 4450 (selection == QTextDocument::Standard || !hasdoc) ?
4507 if ( !hasdoc || document()->invertSelectionText( j ) ) 4451 cg.color( QColorGroup::Highlight ) : document()->selectionColor( selection ) );
4508 painter.setPen( QPen( cg.color( QColorGroup::HighlightedText ) ) );
4509 if ( j == QTextDocument::Standard )
4510 painter.fillRect( startX, lastY, bw, h, cg.color( QColorGroup::Highlight ) );
4511 else
4512 painter.fillRect( startX, lastY, bw, h, hasdoc ? document()->selectionColor( j ) : cg.color( QColorGroup::Highlight ) );
4513 }
4514 }
4515 } 4452 }
4516 4453
4517 if ( str[ start ] != '\t' && str[ start ].unicode() != 0xad ) { 4454 if ( str[ start ] != '\t' && str[ start ].unicode() != 0xad ) {
4518 if ( format->vAlign() == QTextFormat::AlignNormal ) { 4455 if ( format->vAlign() == QTextFormat::AlignNormal ) {
4519 painter.drawText( startX, lastY + baseLine, str.mid( start ), len ); 4456 painter.drawText( xstart, y + baseLine, str.mid( start ), len );
4520#ifdef BIDI_DEBUG 4457#ifdef BIDI_DEBUG
4521 painter.save(); 4458 painter.save();
4522 painter.setPen ( Qt::red ); 4459 painter.setPen ( Qt::red );
4523 painter.drawLine( startX, lastY, startX, lastY + baseLine ); 4460 painter.drawLine( xstart, y, xstart, y + baseLine );
4524 painter.drawLine( startX, lastY + baseLine/2, startX + 10, lastY + baseLine/2 ); 4461 painter.drawLine( xstart, y + baseLine/2, xstart + 10, y + baseLine/2 );
4525 int w = 0; 4462 int w = 0;
4526 int i = 0; 4463 int i = 0;
4527 while( i < len ) 4464 while( i < len )
4528 w += painter.fontMetrics().charWidth( str, start + i++ ); 4465 w += painter.fontMetrics().charWidth( str, start + i++ );
4529 painter.setPen ( Qt::blue ); 4466 painter.setPen ( Qt::blue );
4530 painter.drawLine( startX + w - 1, lastY, startX + w - 1, lastY + baseLine ); 4467 painter.drawLine( xstart + w - 1, y, xstart + w - 1, y + baseLine );
4531 painter.drawLine( startX + w - 1, lastY + baseLine/2, startX + w - 1 - 10, lastY + baseLine/2 ); 4468 painter.drawLine( xstart + w - 1, y + baseLine/2, xstart + w - 1 - 10, y + baseLine/2 );
4532 painter.restore(); 4469 painter.restore();
4533#endif 4470#endif
4534 } else if ( format->vAlign() == QTextFormat::AlignSuperScript ) { 4471 } else if ( format->vAlign() == QTextFormat::AlignSuperScript ) {
4535 QFont f( painter.font() ); 4472 QFont f( painter.font() );
4536 if ( format->fontSizesInPixels() ) 4473 if ( format->fontSizesInPixels() )
4537 f.setPixelSize( ( f.pixelSize() * 2 ) / 3 ); 4474 f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
4538 else 4475 else
4539 f.setPointSize( ( f.pointSize() * 2 ) / 3 ); 4476 f.setPointSize( ( f.pointSize() * 2 ) / 3 );
4540 painter.setFont( f ); 4477 painter.setFont( f );
4541 painter.drawText( startX, lastY + baseLine - ( painter.fontMetrics().height() / 2 ), 4478 painter.drawText( xstart, y + baseLine - ( painter.fontMetrics().height() / 2 ),
4542 str.mid( start ), len ); 4479 str.mid( start ), len );
4543 } else if ( format->vAlign() == QTextFormat::AlignSubScript ) { 4480 } else if ( format->vAlign() == QTextFormat::AlignSubScript ) {
4544 QFont f( painter.font() ); 4481 QFont f( painter.font() );
4545 if ( format->fontSizesInPixels() ) 4482 if ( format->fontSizesInPixels() )
4546 f.setPixelSize( ( f.pixelSize() * 2 ) / 3 ); 4483 f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
4547 else 4484 else
4548 f.setPointSize( ( f.pointSize() * 2 ) / 3 ); 4485 f.setPointSize( ( f.pointSize() * 2 ) / 3 );
4549 painter.setFont( f ); 4486 painter.setFont( f );
4550 painter.drawText( startX, lastY + baseLine + painter.fontMetrics().height() / 6, str.mid( start ), len ); 4487 painter.drawText( xstart, y + baseLine + painter.fontMetrics().height() / 6, str.mid( start ), len );
4551 } 4488 }
4552 } 4489 }
4553 if ( i + 1 < length() && at( i + 1 )->lineStart && at( i )->c.unicode() == 0xad ) { 4490 if ( i + 1 < length() && at( i + 1 )->lineStart && at( i )->c.unicode() == 0xad ) {
4554 painter.drawText( startX + bw, lastY + baseLine, "\xad" ); 4491 painter.drawText( xstart + w, y + baseLine, "\xad" );
4555 } 4492 }
4556 if ( format->isMisspelled() ) { 4493 if ( format->isMisspelled() ) {
4557 painter.save(); 4494 painter.save();
4558 painter.setPen( QPen( Qt::red, 1, Qt::DotLine ) ); 4495 painter.setPen( QPen( Qt::red, 1, Qt::DotLine ) );
4559 painter.drawLine( startX, lastY + baseLine + 1, startX + bw, lastY + baseLine + 1 ); 4496 painter.drawLine( xstart, y + baseLine + 1, xstart + w, y + baseLine + 1 );
4560 painter.restore(); 4497 painter.restore();
4561 } 4498 }
4562 4499
4563 i -= len; 4500 i -= len;
4564 4501
4565 if ( hasdoc && formatChar->isAnchor() && !formatChar->anchorHref().isEmpty() && 4502 if ( hasdoc && formatChar->isAnchor() && !formatChar->anchorHref().isEmpty() &&
4566 document()->focusIndicator.parag == this && 4503 document()->focusIndicator.parag == this &&
4567 ( document()->focusIndicator.start >= i && 4504 ( document()->focusIndicator.start >= i &&
4568 document()->focusIndicator.start + document()->focusIndicator.len <= i + len || 4505 document()->focusIndicator.start + document()->focusIndicator.len <= i + len ||
4569 document()->focusIndicator.start <= i && 4506 document()->focusIndicator.start <= i &&
4570 document()->focusIndicator.start + document()->focusIndicator.len >= i + len ) ) { 4507 document()->focusIndicator.start + document()->focusIndicator.len >= i + len ) ) {
4571 painter.drawWinFocusRect( QRect( startX, lastY, bw, h ) ); 4508 painter.drawWinFocusRect( QRect( xstart, y, w, h ) );
4572 } 4509 }
4573 4510
4574} 4511}
4575 4512
4576void QTextParag::drawLabel( QPainter* p, int x, int y, int w, int h, int base, const QColorGroup& cg ) 4513void QTextParagraph::drawLabel( QPainter* p, int x, int y, int w, int h, int base, const QColorGroup& cg )
4577{ 4514{
4578 if ( !style() )
4579 return;
4580 QRect r ( x, y, w, h ); 4515 QRect r ( x, y, w, h );
4581 QStyleSheetItem::ListStyle s = listStyle(); 4516 QStyleSheetItem::ListStyle s = listStyle();
4582 4517
4583 p->save(); 4518 p->save();
4584 p->setPen( defFormat->color() ); 4519 QTextFormat *format = at( 0 )->format();
4585 4520 if ( format ) {
4586 QFont font2( defFormat->font() ); 4521 p->setPen( format->color() );
4587 if ( length() > 0 ) { 4522 p->setFont( format->font() );
4588 QTextFormat *format = at( 0 )->format();
4589 if ( format ) {
4590 if ( format->fontSizesInPixels() )
4591 font2.setPixelSize( at( 0 )->format()->font().pixelSize() );
4592 else
4593 font2.setPointSize( at( 0 )->format()->font().pointSize() );
4594 }
4595 } 4523 }
4596 p->setFont( font2 );
4597 QFontMetrics fm( p->fontMetrics() ); 4524 QFontMetrics fm( p->fontMetrics() );
4598 int size = fm.lineSpacing() / 3; 4525 int size = fm.lineSpacing() / 3;
4599 4526
4600 switch ( s ) { 4527 switch ( s ) {
4601 case QStyleSheetItem::ListDecimal: 4528 case QStyleSheetItem::ListDecimal:
4602 case QStyleSheetItem::ListLowerAlpha: 4529 case QStyleSheetItem::ListLowerAlpha:
4603 case QStyleSheetItem::ListUpperAlpha: 4530 case QStyleSheetItem::ListUpperAlpha:
4604 { 4531 {
4605 int n = numberOfSubParagraph(); 4532 if ( list_val == -1 ) { // uninitialised list value, calcluate the right one
4533 int depth = listDepth();
4534 list_val--;
4535 // ### evil, square and expensive. This needs to be done when formatting, not when painting
4536 QTextParagraph* s = prev();
4537 int depth_s;
4538 while ( s && (depth_s = s->listDepth()) >= depth ) {
4539 if ( depth_s == depth && s->isListItem() )
4540 list_val--;
4541 s = s->prev();
4542 }
4543 }
4544
4545 int n = list_val;
4546 if ( n < -1 )
4547 n = -n - 1;
4606 QString l; 4548 QString l;
4607 switch ( s ) { 4549 switch ( s ) {
4608 case QStyleSheetItem::ListLowerAlpha: 4550 case QStyleSheetItem::ListLowerAlpha:
4609 if ( n < 27 ) { 4551 if ( n < 27 ) {
4610 l = QChar( ('a' + (char) (n-1))); 4552 l = QChar( ('a' + (char) (n-1)));
4611 break; 4553 break;
@@ -4624,171 +4566,77 @@ void QTextParag::drawLabel( QPainter* p, int x, int y, int w, int h, int base, c
4624 p->drawText( r.right() - fm.width( l ), r.top() + base, l ); 4566 p->drawText( r.right() - fm.width( l ), r.top() + base, l );
4625 } 4567 }
4626 break; 4568 break;
4627 case QStyleSheetItem::ListSquare: 4569 case QStyleSheetItem::ListSquare:
4628 { 4570 {
4629 QRect er( r.right() - size * 2, r.top() + fm.height() / 2 - size / 2, size, size ); 4571 QRect er( r.right() - size * 2, r.top() + fm.height() / 2 - size / 2, size, size );
4630 p->fillRect( er , cg.brush( QColorGroup::Foreground ) ); 4572 p->fillRect( er , cg.brush( QColorGroup::Text ) );
4631 } 4573 }
4632 break; 4574 break;
4633 case QStyleSheetItem::ListCircle: 4575 case QStyleSheetItem::ListCircle:
4634 { 4576 {
4635 QRect er( r.right()-size*2, r.top() + fm.height() / 2 - size / 2, size, size); 4577 QRect er( r.right()-size*2, r.top() + fm.height() / 2 - size / 2, size, size);
4636 p->drawEllipse( er ); 4578 p->drawEllipse( er );
4637 } 4579 }
4638 break; 4580 break;
4639 case QStyleSheetItem::ListDisc: 4581 case QStyleSheetItem::ListDisc:
4640 default: 4582 default:
4641 { 4583 {
4642 p->setBrush( cg.brush( QColorGroup::Foreground )); 4584 p->setBrush( cg.brush( QColorGroup::Text ));
4643 QRect er( r.right()-size*2, r.top() + fm.height() / 2 - size / 2, size, size); 4585 QRect er( r.right()-size*2, r.top() + fm.height() / 2 - size / 2, size, size);
4644 p->drawEllipse( er ); 4586 p->drawEllipse( er );
4645 p->setBrush( Qt::NoBrush ); 4587 p->setBrush( Qt::NoBrush );
4646 } 4588 }
4647 break; 4589 break;
4648 } 4590 }
4649 4591
4650 p->restore(); 4592 p->restore();
4651} 4593}
4652 4594
4653void QTextParag::setStyleSheetItems( const QPtrVector<QStyleSheetItem> &vec ) 4595void QTextParagraph::readStyleInformation( QDataStream& stream )
4654{
4655 styleSheetItemsVec() = vec;
4656 invalidate( 0 );
4657 lm = rm = tm = bm = flm = -1;
4658 numSubParag = -1;
4659}
4660
4661void QTextParag::setList( bool b, int listStyle )
4662{ 4596{
4663 if ( !hasdoc ) 4597 int int_align, int_lstyle;
4664 return; 4598 uchar uchar_litem, uchar_rtext, uchar_dir;
4665 4599 stream >> int_align >> int_lstyle >> utm >> ubm >> ulm >> urm >> uflm
4666 if ( !style() ) { 4600 >> ulinespacing >> ldepth >> uchar_litem >> uchar_rtext >> uchar_dir;
4667 styleSheetItemsVec().resize( 2 ); 4601 align = int_align; lstyle = (QStyleSheetItem::ListStyle) int_lstyle;
4668 mStyleSheetItemsVec->insert( 0, document()->styleSheet()->item( "html" ) ); 4602 litem = uchar_litem; rtext = uchar_rtext; str->setDirection( (QChar::Direction)uchar_dir );
4669 mStyleSheetItemsVec->insert( 1, document()->styleSheet()->item( "p" ) ); 4603 QTextParagraph* s = prev() ? prev() : this;
4670 } 4604 while ( s ) {
4671 4605 s->invalidate( 0 );
4672 if ( b ) { 4606 s = s->next();
4673 if ( style()->displayMode() != QStyleSheetItem::DisplayListItem || this->listStyle() != listStyle ) {
4674 styleSheetItemsVec().remove( styleSheetItemsVec().size() - 1 );
4675 QStyleSheetItem *item = (*mStyleSheetItemsVec)[ mStyleSheetItemsVec->size() - 1 ];
4676 if ( item )
4677 mStyleSheetItemsVec->remove( mStyleSheetItemsVec->size() - 1 );
4678 mStyleSheetItemsVec->insert( mStyleSheetItemsVec->size() - 1,
4679 listStyle == QStyleSheetItem::ListDisc || listStyle == QStyleSheetItem::ListCircle
4680 || listStyle == QStyleSheetItem::ListSquare ?
4681 document()->styleSheet()->item( "ul" ) : document()->styleSheet()->item( "ol" ) );
4682 mStyleSheetItemsVec->insert( mStyleSheetItemsVec->size() - 1, document()->styleSheet()->item( "li" ) );
4683 setListStyle( (QStyleSheetItem::ListStyle)listStyle );
4684 } else {
4685 return;
4686 }
4687 } else {
4688 if ( style()->displayMode() != QStyleSheetItem::DisplayBlock ) {
4689 styleSheetItemsVec().remove( styleSheetItemsVec().size() - 1 );
4690 if ( mStyleSheetItemsVec->size() >= 2 ) {
4691 mStyleSheetItemsVec->remove( mStyleSheetItemsVec->size() - 2 );
4692 mStyleSheetItemsVec->resize( mStyleSheetItemsVec->size() - 2 );
4693 } else {
4694 mStyleSheetItemsVec->resize( mStyleSheetItemsVec->size() - 1 );
4695 }
4696 } else {
4697 return;
4698 }
4699 }
4700 invalidate( 0 );
4701 lm = rm = tm = bm = flm = -1;
4702 numSubParag = -1;
4703 if ( next() ) {
4704 QTextParag *s = next();
4705 while ( s ) {
4706 s->numSubParag = -1;
4707 s->lm = s->rm = s->tm = s->bm = flm = -1;
4708 s->numSubParag = -1;
4709 s->invalidate( 0 );
4710 s = s->next();
4711 }
4712 } 4607 }
4713} 4608}
4714 4609
4715void QTextParag::incDepth() 4610void QTextParagraph::writeStyleInformation( QDataStream& stream ) const
4716{ 4611{
4717 if ( !style() || !hasdoc ) 4612 stream << (int) align << (int) lstyle << utm << ubm << ulm << urm << uflm << ulinespacing << ldepth << (uchar)litem << (uchar)rtext << (uchar)str->direction();
4718 return;
4719 if ( style()->displayMode() != QStyleSheetItem::DisplayListItem )
4720 return;
4721 styleSheetItemsVec().resize( styleSheetItemsVec().size() + 1 );
4722 mStyleSheetItemsVec->insert( mStyleSheetItemsVec->size() - 1, (*mStyleSheetItemsVec)[ mStyleSheetItemsVec->size() - 2 ] );
4723 mStyleSheetItemsVec->insert( mStyleSheetItemsVec->size() - 2,
4724 listStyle() == QStyleSheetItem::ListDisc || listStyle() == QStyleSheetItem::ListCircle ||
4725 listStyle() == QStyleSheetItem::ListSquare ?
4726 document()->styleSheet()->item( "ul" ) : document()->styleSheet()->item( "ol" ) );
4727 invalidate( 0 );
4728 lm = -1;
4729 flm = -1;
4730} 4613}
4731 4614
4732void QTextParag::decDepth()
4733{
4734 if ( !style() || !hasdoc )
4735 return;
4736 if ( style()->displayMode() != QStyleSheetItem::DisplayListItem )
4737 return;
4738 int numLists = 0;
4739 QStyleSheetItem *lastList = 0;
4740 int lastIndex = 0;
4741 int i;
4742 if ( mStyleSheetItemsVec ) {
4743 for ( i = 0; i < (int)mStyleSheetItemsVec->size(); ++i ) {
4744 QStyleSheetItem *item = (*mStyleSheetItemsVec)[ i ];
4745 if ( item->name() == "ol" || item->name() == "ul" ) {
4746 lastList = item;
4747 lastIndex = i;
4748 numLists++;
4749 }
4750 }
4751 }
4752 4615
4753 if ( !lastList )
4754 return;
4755 styleSheetItemsVec().remove( lastIndex );
4756 for ( i = lastIndex; i < (int)mStyleSheetItemsVec->size() - 1; ++i )
4757 mStyleSheetItemsVec->insert( i, (*mStyleSheetItemsVec)[ i + 1 ] );
4758 mStyleSheetItemsVec->resize( mStyleSheetItemsVec->size() - 1 );
4759 if ( numLists == 1 )
4760 setList( FALSE, -1 );
4761 invalidate( 0 );
4762 lm = -1;
4763 flm = -1;
4764}
4765 4616
4766int QTextParag::listDepth() const 4617void QTextParagraph::setListDepth( int depth ) {
4767{ 4618 if ( !hasdoc || depth == ldepth )
4768 int numLists = 0; 4619 return;
4769 int i; 4620 ldepth = depth;
4770 if ( mStyleSheetItemsVec ) { 4621 QTextParagraph* s = prev() ? prev() : this;
4771 for ( i = 0; i < (int)mStyleSheetItemsVec->size(); ++i ) { 4622 while ( s ) {
4772 QStyleSheetItem *item = (*mStyleSheetItemsVec)[ i ]; 4623 s->invalidate( 0 );
4773 if ( item->name() == "ol" || item->name() == "ul" ) 4624 s = s->next();
4774 numLists++;
4775 }
4776 } 4625 }
4777 return numLists - 1;
4778} 4626}
4779 4627
4780int *QTextParag::tabArray() const 4628int *QTextParagraph::tabArray() const
4781{ 4629{
4782 int *ta = tArray; 4630 int *ta = tArray;
4783 if ( !ta && hasdoc ) 4631 if ( !ta && hasdoc )
4784 ta = document()->tabArray(); 4632 ta = document()->tabArray();
4785 return ta; 4633 return ta;
4786} 4634}
4787 4635
4788int QTextParag::nextTab( int, int x ) 4636int QTextParagraph::nextTab( int, int x )
4789{ 4637{
4790 int *ta = tArray; 4638 int *ta = tArray;
4791 if ( hasdoc ) { 4639 if ( hasdoc ) {
4792 if ( !ta ) 4640 if ( !ta )
4793 ta = document()->tabArray(); 4641 ta = document()->tabArray();
4794 tabStopWidth = document()->tabStopWidth(); 4642 tabStopWidth = document()->tabStopWidth();
@@ -4808,336 +4656,208 @@ int QTextParag::nextTab( int, int x )
4808 else 4656 else
4809 return x; 4657 return x;
4810 return tabStopWidth * ( d + 1 ); 4658 return tabStopWidth * ( d + 1 );
4811 } 4659 }
4812} 4660}
4813 4661
4814void QTextParag::adjustToPainter( QPainter *p ) 4662void QTextParagraph::adjustToPainter( QPainter *p )
4815{ 4663{
4816 for ( int i = 0; i < length(); ++i ) { 4664 for ( int i = 0; i < length(); ++i ) {
4817 if ( at( i )->isCustom() ) 4665 if ( at( i )->isCustom() )
4818 at( i )->customItem()->adjustToPainter( p ); 4666 at( i )->customItem()->adjustToPainter( p );
4819 } 4667 }
4820} 4668}
4821 4669
4822QTextFormatCollection *QTextParag::formatCollection() const 4670QTextFormatCollection *QTextParagraph::formatCollection() const
4823{ 4671{
4824 if ( hasdoc ) 4672 if ( hasdoc )
4825 return document()->formatCollection(); 4673 return document()->formatCollection();
4826 if ( !qFormatCollection ) { 4674 if ( !qFormatCollection ) {
4827 qFormatCollection = new QTextFormatCollection; 4675 qFormatCollection = new QTextFormatCollection;
4828 static QSingleCleanupHandler<QTextFormatCollection> qtfCleanup; 4676 static QSingleCleanupHandler<QTextFormatCollection> qtfCleanup;
4829 qtfCleanup.set( &qFormatCollection ); 4677 qtfCleanup.set( &qFormatCollection );
4830 } 4678 }
4831 return qFormatCollection; 4679 return qFormatCollection;
4832} 4680}
4833 4681
4834QString QTextParag::richText() const 4682QString QTextParagraph::richText() const
4835{ 4683{
4836 QString s; 4684 QString s;
4837 QTextStringChar *formatChar = 0; 4685 QTextStringChar *formatChar = 0;
4838 QString spaces; 4686 QString spaces;
4839 bool lastCharWasSpace = FALSE; 4687 bool doStart = richTextExportStart && richTextExportStart->paragraph() == this;
4840 int firstcol = 0; 4688 bool doEnd = richTextExportEnd && richTextExportEnd->paragraph() == this;
4841 for ( int i = 0; i < length()-1; ++i ) { 4689 int i;
4690 for ( i = 0; i < length()-1; ++i ) {
4691 if ( doStart && i && richTextExportStart->index() == i )
4692 s += "<selstart/>";
4693 if ( doEnd && richTextExportEnd->index() == i )
4694 s += "<selend/>";
4842 QTextStringChar *c = &str->at( i ); 4695 QTextStringChar *c = &str->at( i );
4843 if ( c->isAnchor() && !c->anchorName().isEmpty() ) { 4696 if ( c->isAnchor() && !c->anchorName().isEmpty() ) {
4844 if ( c->anchorName().contains( '#' ) ) { 4697 if ( c->anchorName().contains( '#' ) ) {
4845 QStringList l = QStringList::split( '#', c->anchorName() ); 4698 QStringList l = QStringList::split( '#', c->anchorName() );
4846 for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it ) 4699 for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it )
4847 s += "<a name=\"" + *it + "\"></a>"; 4700 s += "<a name=\"" + *it + "\"></a>";
4848 } else { 4701 } else {
4849 s += "<a name=\"" + c->anchorName() + "\"></a>"; 4702 s += "<a name=\"" + c->anchorName() + "\"></a>";
4850 } 4703 }
4851 } 4704 }
4852 if ( !formatChar ) { 4705 if ( !formatChar ) {
4853 s += c->format()->makeFormatChangeTags( 0, QString::null, c->anchorHref() ); 4706 s += c->format()->makeFormatChangeTags( formatCollection()->defaultFormat(),
4707 0, QString::null, c->anchorHref() );
4854 formatChar = c; 4708 formatChar = c;
4855 } else if ( ( formatChar->format()->key() != c->format()->key() ) || 4709 } else if ( ( formatChar->format()->key() != c->format()->key() ) ||
4856 (formatChar->isAnchor() != c->isAnchor() && 4710 (c->anchorHref() != formatChar->anchorHref() ) ) {
4857 (!c->anchorHref().isEmpty() || !formatChar->anchorHref().isEmpty() ) ) ) {// lisp was here 4711 s += c->format()->makeFormatChangeTags( formatCollection()->defaultFormat(),
4858 4712 formatChar->format() , formatChar->anchorHref(), c->anchorHref() );
4859 if ( !spaces.isEmpty() ) {
4860 if ( spaces[0] == '\t' || lastCharWasSpace )
4861 s += "<wsp>" + spaces + "</wsp>";
4862 else if ( spaces.length() > 1 )
4863 s += "<wsp>" + spaces.mid(1) + "</wsp> ";
4864 else
4865 s += spaces;
4866 lastCharWasSpace = TRUE;
4867 spaces = QString::null;
4868 }
4869 s += c->format()->makeFormatChangeTags( formatChar->format() , formatChar->anchorHref(), c->anchorHref() );
4870 formatChar = c; 4713 formatChar = c;
4871 } 4714 }
4872 4715 if ( c->c == '<' )
4873 if ( c->c == ' ' || c->c == '\t' ) {
4874 spaces += c->c;
4875 continue;
4876 } else if ( !spaces.isEmpty() ) {
4877 if ( spaces[0] == '\t' || lastCharWasSpace )
4878 s += "<wsp>" + spaces + "</wsp>";
4879 else if ( spaces.length() > 1 )
4880 s += "<wsp>" + spaces.mid(1) + "</wsp> ";
4881 else
4882 s += spaces;
4883 spaces = QString::null;
4884 if ( s.length() - firstcol > 60 ) {
4885 s += '\n';
4886 firstcol = s.length();
4887 }
4888 }
4889
4890 lastCharWasSpace = FALSE;
4891 if ( c->c == '<' ) {
4892 s += "&lt;"; 4716 s += "&lt;";
4893 } else if ( c->c == '>' ) { 4717 else if ( c->c == '>' )
4894 s += "&gt;"; 4718 s += "&gt;";
4895 } else if ( c->isCustom() ) { 4719 else if ( c->isCustom() )
4896 s += c->customItem()->richText(); 4720 s += c->customItem()->richText();
4897 } else { 4721 else if ( c->c == '\n' || c->c == QChar_linesep )
4898 s += c->c; 4722 s += "<br />"; // space on purpose for compatibility with Netscape, Lynx & Co.
4899 }
4900 }
4901 if ( !spaces.isEmpty() ) {
4902 if ( spaces.length() > 1 || spaces[0] == '\t' || lastCharWasSpace )
4903 s += "<wsp>" + spaces + "</wsp>";
4904 else 4723 else
4905 s += spaces; 4724 s += c->c;
4906 } 4725 }
4907 4726 if ( doEnd && richTextExportEnd->index() == i )
4727 s += "<selend/>";
4908 if ( formatChar ) 4728 if ( formatChar )
4909 s += formatChar->format()->makeFormatEndTags( formatChar->anchorHref() ); 4729 s += formatChar->format()->makeFormatEndTags( formatCollection()->defaultFormat(), formatChar->anchorHref() );
4910 return s; 4730 return s;
4911} 4731}
4912 4732
4913void QTextParag::addCommand( QTextCommand *cmd ) 4733void QTextParagraph::addCommand( QTextCommand *cmd )
4914{ 4734{
4915 if ( !hasdoc ) 4735 if ( !hasdoc )
4916 pseudoDocument()->commandHistory->addCommand( cmd ); 4736 pseudoDocument()->commandHistory->addCommand( cmd );
4917 else 4737 else
4918 document()->commands()->addCommand( cmd ); 4738 document()->commands()->addCommand( cmd );
4919} 4739}
4920 4740
4921QTextCursor *QTextParag::undo( QTextCursor *c ) 4741QTextCursor *QTextParagraph::undo( QTextCursor *c )
4922{ 4742{
4923 if ( !hasdoc ) 4743 if ( !hasdoc )
4924 return pseudoDocument()->commandHistory->undo( c ); 4744 return pseudoDocument()->commandHistory->undo( c );
4925 return document()->commands()->undo( c ); 4745 return document()->commands()->undo( c );
4926} 4746}
4927 4747
4928QTextCursor *QTextParag::redo( QTextCursor *c ) 4748QTextCursor *QTextParagraph::redo( QTextCursor *c )
4929{ 4749{
4930 if ( !hasdoc ) 4750 if ( !hasdoc )
4931 return pseudoDocument()->commandHistory->redo( c ); 4751 return pseudoDocument()->commandHistory->redo( c );
4932 return document()->commands()->redo( c ); 4752 return document()->commands()->redo( c );
4933} 4753}
4934 4754
4935int QTextParag::topMargin() const 4755int QTextParagraph::topMargin() const
4936{ 4756{
4937 if ( !p && ( !hasdoc || !document()->addMargins() ) )
4938 return 0;
4939 if ( tm != -1 )
4940 return tm;
4941 QStyleSheetItem *item = style();
4942 if ( !item ) {
4943 ( (QTextParag*)this )->tm = 0;
4944 return 0;
4945 }
4946
4947 int m = 0; 4757 int m = 0;
4948 if ( item->margin( QStyleSheetItem::MarginTop ) != QStyleSheetItem::Undefined ) 4758 if ( rtext ) {
4949 m = item->margin( QStyleSheetItem::MarginTop ); 4759 m = isListItem() ? (document()->li_tm/QMAX(1,listDepth())) : document()->par_tm;
4950 if ( mStyleSheetItemsVec ) { 4760 if ( listDepth() == 1 &&( !prev() || prev()->listDepth() < listDepth() ) )
4951 QStyleSheetItem *it = 0; 4761 m = QMAX( m, document()->list_tm );
4952 QStyleSheetItem *p = prev() ? prev()->style() : 0;
4953 for ( int i = (int)mStyleSheetItemsVec->size() - 2 ; i >= 0; --i ) {
4954 it = (*mStyleSheetItemsVec)[ i ];
4955 if ( it != p )
4956 break;
4957 int mar = it->margin( QStyleSheetItem::MarginTop );
4958 m += (mar != QStyleSheetItem::Undefined) ? mar : 0;
4959 if ( it->displayMode() != QStyleSheetItem::DisplayInline )
4960 break;
4961 }
4962 } 4762 }
4963 m = scale( m, QTextFormat::painter() ); 4763 m += utm;
4964 4764 return scale( m, QTextFormat::painter() );
4965 ( (QTextParag*)this )->tm = m;
4966 return tm;
4967} 4765}
4968 4766
4969int QTextParag::bottomMargin() const 4767int QTextParagraph::bottomMargin() const
4970{ 4768{
4971 if ( bm != -1 )
4972 return bm;
4973 QStyleSheetItem *item = style();
4974 if ( !item || !next() ) {
4975 ( (QTextParag*)this )->bm = 0;
4976 return 0;
4977 }
4978
4979 int m = 0; 4769 int m = 0;
4980 if ( item->margin( QStyleSheetItem::MarginBottom ) != QStyleSheetItem::Undefined ) 4770 if ( rtext ) {
4981 m = item->margin( QStyleSheetItem::MarginBottom ); 4771 m = isListItem() ? (document()->li_bm/QMAX(1,listDepth())) : document()->par_bm;
4982 if ( mStyleSheetItemsVec ) { 4772 if ( listDepth() == 1 &&( !next() || next()->listDepth() < listDepth() ) )
4983 QStyleSheetItem *it = 0; 4773 m = QMAX( m, document()->list_bm );
4984 QStyleSheetItem *n = next() ? next()->style() : 0;
4985 for ( int i =(int)mStyleSheetItemsVec->size() - 2 ; i >= 0; --i ) {
4986 it = (*mStyleSheetItemsVec)[ i ];
4987 if ( it != n )
4988 break;
4989 int mar = it->margin( QStyleSheetItem::MarginBottom );
4990 m += mar != QStyleSheetItem::Undefined ? mar : 0;
4991 if ( it->displayMode() != QStyleSheetItem::DisplayInline )
4992 break;
4993 }
4994 } 4774 }
4995 m = scale ( m, QTextFormat::painter() ); 4775 m += ubm;
4996 4776 return scale( m, QTextFormat::painter() );
4997 ( (QTextParag*)this )->bm = m;
4998 return bm;
4999} 4777}
5000 4778
5001int QTextParag::leftMargin() const 4779int QTextParagraph::leftMargin() const
5002{ 4780{
5003 if ( lm != -1 ) 4781 int m = ulm;
5004 return lm; 4782 if ( listDepth() )
5005 QStyleSheetItem *item = style(); 4783 m += listDepth() * document()->list_lm;
5006 if ( !item ) { 4784 return scale( m, QTextFormat::painter() );
5007 ( (QTextParag*)this )->lm = 0;
5008 return 0;
5009 }
5010 int m = 0;
5011 if ( mStyleSheetItemsVec ) {
5012 for ( int i = 0; i < (int)mStyleSheetItemsVec->size(); ++i ) {
5013 item = (*mStyleSheetItemsVec)[ i ];
5014 int mar = item->margin( QStyleSheetItem::MarginLeft );
5015 m += mar != QStyleSheetItem::Undefined ? mar : 0;
5016 if ( item->name() == "ol" || item->name() == "ul" ) {
5017 QPainter* oldPainter = QTextFormat::painter();
5018 QTextFormat::setPainter( 0 );
5019 m += defFormat->width( '1' ) +
5020 defFormat->width( '2' ) +
5021 defFormat->width( '3' ) +
5022 defFormat->width( '.' );
5023 QTextFormat::setPainter( oldPainter );
5024 }
5025 }
5026 }
5027
5028 m = scale ( m, QTextFormat::painter() );
5029
5030 ( (QTextParag*)this )->lm = m;
5031 return lm;
5032} 4785}
5033 4786
5034int QTextParag::firstLineMargin() const 4787int QTextParagraph::firstLineMargin() const
5035{ 4788{
5036 if ( flm != -1 ) 4789 int m = uflm;
5037 return lm; 4790 return scale( m, QTextFormat::painter() );
5038 QStyleSheetItem *item = style();
5039 if ( !item ) {
5040 ( (QTextParag*)this )->flm = 0;
5041 return 0;
5042 }
5043 int m = 0;
5044 if ( mStyleSheetItemsVec ) {
5045 for ( int i = 0; i < (int)mStyleSheetItemsVec->size(); ++i ) {
5046 item = (*mStyleSheetItemsVec)[ i ];
5047 int mar = item->margin( QStyleSheetItem::MarginFirstLine );
5048 m += mar != QStyleSheetItem::Undefined ? mar : 0;
5049 }
5050 }
5051
5052 m = scale( m, QTextFormat::painter() );
5053
5054 ( (QTextParag*)this )->flm = m;
5055 return flm;
5056} 4791}
5057 4792
5058int QTextParag::rightMargin() const 4793int QTextParagraph::rightMargin() const
5059{ 4794{
5060 if ( rm != -1 ) 4795 int m = urm;
5061 return rm; 4796 return scale( m, QTextFormat::painter() );
5062 QStyleSheetItem *item = style();
5063 if ( !item ) {
5064 ( (QTextParag*)this )->rm = 0;
5065 return 0;
5066 }
5067 int m = 0;
5068 if ( mStyleSheetItemsVec ) {
5069 for ( int i = 0; i < (int)mStyleSheetItemsVec->size(); ++i ) {
5070 item = (*mStyleSheetItemsVec)[ i ];
5071 int mar = item->margin( QStyleSheetItem::MarginRight );
5072 m += mar != QStyleSheetItem::Undefined ? mar : 0;
5073 }
5074 }
5075 m = scale( m, QTextFormat::painter() );
5076
5077 ( (QTextParag*)this )->rm = m;
5078 return rm;
5079} 4797}
5080 4798
5081int QTextParag::lineSpacing() const 4799int QTextParagraph::lineSpacing() const
5082{ 4800{
5083 QStyleSheetItem *item = style(); 4801 int l = ulinespacing;
5084 if ( !item ) 4802 l = scale( l, QTextFormat::painter() );
5085 return 0; 4803 return l;
5086
5087 int ls = item->lineSpacing();
5088 if ( ls == QStyleSheetItem::Undefined )
5089 return 0;
5090 ls = scale( ls, QTextFormat::painter() );
5091
5092 return ls;
5093} 4804}
5094 4805
5095void QTextParag::copyParagData( QTextParag *parag ) 4806void QTextParagraph::copyParagData( QTextParagraph *parag )
5096{ 4807{
5097 setStyleSheetItems( parag->styleSheetItems() ); 4808 rtext = parag->rtext;
5098 setListStyle( parag->listStyle() ); 4809 lstyle = parag->lstyle;
5099 setAlignment( parag->alignment() ); 4810 ldepth = parag->ldepth;
4811 litem = parag->litem;
4812 align = parag->align;
4813 utm = parag->utm;
4814 ubm = parag->ubm;
4815 urm = parag->urm;
4816 ulm = parag->ulm;
4817 uflm = parag->uflm;
4818 ulinespacing = parag->ulinespacing;
5100 QColor *c = parag->backgroundColor(); 4819 QColor *c = parag->backgroundColor();
5101 if ( c ) 4820 if ( c )
5102 setBackgroundColor( *c ); 4821 setBackgroundColor( *c );
4822 str->setDirection( parag->str->direction() );
5103} 4823}
5104 4824
5105void QTextParag::show() 4825void QTextParagraph::show()
5106{ 4826{
5107 if ( visible || !hasdoc ) 4827 if ( visible || !hasdoc )
5108 return; 4828 return;
5109 visible = TRUE; 4829 visible = TRUE;
5110} 4830}
5111 4831
5112void QTextParag::hide() 4832void QTextParagraph::hide()
5113{ 4833{
5114 if ( !visible || !hasdoc ) 4834 if ( !visible || !hasdoc )
5115 return; 4835 return;
5116 visible = FALSE; 4836 visible = FALSE;
5117} 4837}
5118 4838
5119void QTextParag::setDirection( QChar::Direction d ) 4839void QTextParagraph::setDirection( QChar::Direction d )
5120{ 4840{
5121 if ( str && str->direction() != d ) { 4841 if ( str && str->direction() != d ) {
5122 str->setDirection( d ); 4842 str->setDirection( d );
5123 invalidate( 0 ); 4843 invalidate( 0 );
5124 } 4844 }
5125} 4845}
5126 4846
5127QChar::Direction QTextParag::direction() const 4847QChar::Direction QTextParagraph::direction() const
5128{ 4848{
5129 return (str ? str->direction() : QChar::DirON ); 4849 return (str ? str->direction() : QChar::DirON );
5130} 4850}
5131 4851
5132void QTextParag::setChanged( bool b, bool recursive ) 4852void QTextParagraph::setChanged( bool b, bool recursive )
5133{ 4853{
5134 changed = b; 4854 changed = b;
5135 if ( recursive ) { 4855 if ( recursive ) {
5136 if ( document() && document()->parentParag() ) 4856 if ( document() && document()->parentParagraph() )
5137 document()->parentParag()->setChanged( b, recursive ); 4857 document()->parentParagraph()->setChanged( b, recursive );
5138 } 4858 }
5139} 4859}
5140 4860
5141// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4861// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5142 4862
5143 4863
@@ -5149,33 +4869,36 @@ QTextPreProcessor::QTextPreProcessor()
5149 4869
5150QTextFormatter::QTextFormatter() 4870QTextFormatter::QTextFormatter()
5151 : thisminw(0), thiswused(0), wrapEnabled( TRUE ), wrapColumn( -1 ), biw( FALSE ) 4871 : thisminw(0), thiswused(0), wrapEnabled( TRUE ), wrapColumn( -1 ), biw( FALSE )
5152{ 4872{
5153} 4873}
5154 4874
5155/* only used for bidi or complex text reordering 4875QTextLineStart *QTextFormatter::formatLine( QTextParagraph *parag, QTextString *string, QTextLineStart *line,
5156 */
5157QTextParagLineStart *QTextFormatter::formatLine( QTextParag *parag, QTextString *string, QTextParagLineStart *line,
5158 QTextStringChar *startChar, QTextStringChar *lastChar, int align, int space ) 4876 QTextStringChar *startChar, QTextStringChar *lastChar, int align, int space )
5159{ 4877{
5160#ifndef QT_NO_COMPLEXTEXT 4878#ifndef QT_NO_COMPLEXTEXT
5161 if( string->isBidi() ) 4879 if( string->isBidi() )
5162 return bidiReorderLine( parag, string, line, startChar, lastChar, align, space ); 4880 return bidiReorderLine( parag, string, line, startChar, lastChar, align, space );
5163#endif 4881#endif
5164 space = QMAX( space, 0 ); // #### with nested tables this gets negative because of a bug I didn't find yet, so workaround for now. This also means non-left aligned nested tables do not work at the moment
5165 int start = (startChar - &string->at(0)); 4882 int start = (startChar - &string->at(0));
5166 int last = (lastChar - &string->at(0) ); 4883 int last = (lastChar - &string->at(0) );
5167 // do alignment Auto == Left in this case 4884 // do alignment Auto == Left in this case
5168 if ( align & Qt::AlignHCenter || align & Qt::AlignRight ) { 4885 if ( align & Qt::AlignHCenter || align & Qt::AlignRight ) {
5169 if ( align & Qt::AlignHCenter ) 4886 if ( align & Qt::AlignHCenter )
5170 space /= 2; 4887 space /= 2;
5171 for ( int j = start; j <= last; ++j ) 4888 for ( int j = start; j <= last; ++j )
5172 string->at( j ).x += space; 4889 string->at( j ).x += space;
5173 } else if ( align & Qt3::AlignJustify ) { 4890 } else if ( align & Qt3::AlignJustify ) {
5174 int numSpaces = 0; 4891 int numSpaces = 0;
5175 for ( int j = start; j < last; ++j ) { 4892 // End at "last-1", the last space ends up with a width of 0
4893 for ( int j = last-1; j >= start; --j ) {
4894 // Start at last tab, if any.
4895 if ( string->at( j ).c == '\t' ) {
4896 start = j+1;
4897 break;
4898 }
5176 if( isBreakable( string, j ) ) { 4899 if( isBreakable( string, j ) ) {
5177 numSpaces++; 4900 numSpaces++;
5178 } 4901 }
5179 } 4902 }
5180 int toAdd = 0; 4903 int toAdd = 0;
5181 for ( int k = start + 1; k <= last; ++k ) { 4904 for ( int k = start + 1; k <= last; ++k ) {
@@ -5191,28 +4914,27 @@ QTextParagLineStart *QTextFormatter::formatLine( QTextParag *parag, QTextString
5191 4914
5192 if ( last >= 0 && last < string->length() ) 4915 if ( last >= 0 && last < string->length() )
5193 line->w = string->at( last ).x + string->width( last ); 4916 line->w = string->at( last ).x + string->width( last );
5194 else 4917 else
5195 line->w = 0; 4918 line->w = 0;
5196 4919
5197 return new QTextParagLineStart(); 4920 return new QTextLineStart();
5198} 4921}
5199 4922
5200#ifndef QT_NO_COMPLEXTEXT 4923#ifndef QT_NO_COMPLEXTEXT
5201 4924
5202#ifdef BIDI_DEBUG 4925#ifdef BIDI_DEBUG
5203#include <iostream> 4926#include <iostream>
5204#endif 4927#endif
5205 4928
5206// collects one line of the paragraph and transforms it to visual order 4929// collects one line of the paragraph and transforms it to visual order
5207QTextParagLineStart *QTextFormatter::bidiReorderLine( QTextParag * /*parag*/, QTextString *text, QTextParagLineStart *line, 4930QTextLineStart *QTextFormatter::bidiReorderLine( QTextParagraph * /*parag*/, QTextString *text, QTextLineStart *line,
5208 QTextStringChar *startChar, QTextStringChar *lastChar, int align, int space ) 4931 QTextStringChar *startChar, QTextStringChar *lastChar, int align, int space )
5209{ 4932{
5210 int start = (startChar - &text->at(0)); 4933 int start = (startChar - &text->at(0));
5211 int last = (lastChar - &text->at(0) ); 4934 int last = (lastChar - &text->at(0) );
5212 //qDebug("doing BiDi reordering from %d to %d!", start, last);
5213 4935
5214 QBidiControl *control = new QBidiControl( line->context(), line->status ); 4936 QBidiControl *control = new QBidiControl( line->context(), line->status );
5215 QString str; 4937 QString str;
5216 str.setUnicode( 0, last - start + 1 ); 4938 str.setUnicode( 0, last - start + 1 );
5217 // fill string with logically ordered chars. 4939 // fill string with logically ordered chars.
5218 QTextStringChar *ch = startChar; 4940 QTextStringChar *ch = startChar;
@@ -5240,13 +4962,19 @@ QTextParagLineStart *QTextFormatter::bidiReorderLine( QTextParag * /*parag*/, QT
5240 4962
5241 if ( align & Qt::AlignHCenter ) 4963 if ( align & Qt::AlignHCenter )
5242 x += space/2; 4964 x += space/2;
5243 else if ( align & Qt::AlignRight ) 4965 else if ( align & Qt::AlignRight )
5244 x += space; 4966 x += space;
5245 else if ( align & Qt3::AlignJustify ) { 4967 else if ( align & Qt3::AlignJustify ) {
5246 for ( int j = start; j < last; ++j ) { 4968 // End at "last-1", the last space ends up with a width of 0
4969 for ( int j = last-1; j >= start; --j ) {
4970 // Start at last tab, if any.
4971 if ( text->at( j ).c == '\t' ) {
4972 start = j+1;
4973 break;
4974 }
5247 if( isBreakable( text, j ) ) { 4975 if( isBreakable( text, j ) ) {
5248 numSpaces++; 4976 numSpaces++;
5249 } 4977 }
5250 } 4978 }
5251 } 4979 }
5252 int toAdd = 0; 4980 int toAdd = 0;
@@ -5302,34 +5030,35 @@ QTextParagLineStart *QTextFormatter::bidiReorderLine( QTextParag * /*parag*/, QT
5302 int ww = 0; 5030 int ww = 0;
5303 if ( c->c.unicode() >= 32 || c->c == '\t' || c->isCustom() ) { 5031 if ( c->c.unicode() >= 32 || c->c == '\t' || c->isCustom() ) {
5304 ww = text->width( pos ); 5032 ww = text->width( pos );
5305 } else { 5033 } else {
5306 ww = c->format()->width( ' ' ); 5034 ww = c->format()->width( ' ' );
5307 } 5035 }
5308 //qDebug("setting char %d at pos %d", pos, x);
5309 if ( xmax < x + toAdd + ww ) xmax = x + toAdd + ww; 5036 if ( xmax < x + toAdd + ww ) xmax = x + toAdd + ww;
5310 x += ww; 5037 x += ww;
5311 pos++; 5038 pos++;
5312 } 5039 }
5313 } 5040 }
5314 text->at( r->start + start ).startOfRun = TRUE; 5041 text->at( r->start + start ).startOfRun = TRUE;
5315 r = runs->next(); 5042 r = runs->next();
5316 } 5043 }
5317 5044
5318 line->w = xmax + 10; 5045 line->w = xmax + 10;
5319 QTextParagLineStart *ls = new QTextParagLineStart( control->context, control->status ); 5046 QTextLineStart *ls = new QTextLineStart( control->context, control->status );
5320 delete control; 5047 delete control;
5321 delete runs; 5048 delete runs;
5322 return ls; 5049 return ls;
5323} 5050}
5324#endif 5051#endif
5325 5052
5326bool QTextFormatter::isBreakable( QTextString *string, int pos ) const 5053bool QTextFormatter::isBreakable( QTextString *string, int pos )
5327{ 5054{
5328 const QChar &c = string->at( pos ).c; 5055 const QChar &c = string->at( pos ).c;
5329 char ch = c.latin1(); 5056 char ch = c.latin1();
5057 if ( c == QChar_linesep )
5058 return TRUE;
5330 if ( c.isSpace() && ch != '\n' && c.unicode() != 0x00a0U ) 5059 if ( c.isSpace() && ch != '\n' && c.unicode() != 0x00a0U )
5331 return TRUE; 5060 return TRUE;
5332 if ( c.unicode() == 0xad ) // soft hyphen 5061 if ( c.unicode() == 0xad ) // soft hyphen
5333 return TRUE; 5062 return TRUE;
5334 if ( !ch ) { 5063 if ( !ch ) {
5335 // not latin1, need to do more sophisticated checks for other scripts 5064 // not latin1, need to do more sophisticated checks for other scripts
@@ -5371,19 +5100,19 @@ bool QTextFormatter::isBreakable( QTextString *string, int pos ) const
5371 // in front of a punctuation character. 5100 // in front of a punctuation character.
5372 return TRUE; 5101 return TRUE;
5373 } 5102 }
5374 return FALSE; 5103 return FALSE;
5375} 5104}
5376 5105
5377void QTextFormatter::insertLineStart( QTextParag *parag, int index, QTextParagLineStart *ls ) 5106void QTextFormatter::insertLineStart( QTextParagraph *parag, int index, QTextLineStart *ls )
5378{ 5107{
5379 if ( index > 0 ) { // we can assume that only first line starts are insrted multiple times 5108 if ( index > 0 ) { // we can assume that only first line starts are insrted multiple times
5380 parag->lineStartList().insert( index, ls ); 5109 parag->lineStartList().insert( index, ls );
5381 return; 5110 return;
5382 } 5111 }
5383 QMap<int, QTextParagLineStart*>::Iterator it; 5112 QMap<int, QTextLineStart*>::Iterator it;
5384 if ( ( it = parag->lineStartList().find( index ) ) == parag->lineStartList().end() ) { 5113 if ( ( it = parag->lineStartList().find( index ) ) == parag->lineStartList().end() ) {
5385 parag->lineStartList().insert( index, ls ); 5114 parag->lineStartList().insert( index, ls );
5386 } else { 5115 } else {
5387 delete *it; 5116 delete *it;
5388 parag->lineStartList().remove( it ); 5117 parag->lineStartList().remove( it );
5389 parag->lineStartList().insert( index, ls ); 5118 parag->lineStartList().insert( index, ls );
@@ -5391,20 +5120,20 @@ void QTextFormatter::insertLineStart( QTextParag *parag, int index, QTextParagLi
5391} 5120}
5392 5121
5393 5122
5394/* Standard pagebreak algorithm using QTextFlow::adjustFlow. Returns 5123/* Standard pagebreak algorithm using QTextFlow::adjustFlow. Returns
5395 the shift of the paragraphs bottom line. 5124 the shift of the paragraphs bottom line.
5396 */ 5125 */
5397int QTextFormatter::formatVertically( QTextDocument* doc, QTextParag* parag ) 5126int QTextFormatter::formatVertically( QTextDocument* doc, QTextParagraph* parag )
5398{ 5127{
5399 int oldHeight = parag->rect().height(); 5128 int oldHeight = parag->rect().height();
5400 QMap<int, QTextParagLineStart*>& lineStarts = parag->lineStartList(); 5129 QMap<int, QTextLineStart*>& lineStarts = parag->lineStartList();
5401 QMap<int, QTextParagLineStart*>::Iterator it = lineStarts.begin(); 5130 QMap<int, QTextLineStart*>::Iterator it = lineStarts.begin();
5402 int h = doc->addMargins() ? parag->topMargin() : 0; 5131 int h = parag->prev() ? QMAX(parag->prev()->bottomMargin(),parag->topMargin() ) / 2: 0;
5403 for ( ; it != lineStarts.end() ; ++it ) { 5132 for ( ; it != lineStarts.end() ; ++it ) {
5404 QTextParagLineStart * ls = it.data(); 5133 QTextLineStart * ls = it.data();
5405 ls->y = h; 5134 ls->y = h;
5406 QTextStringChar *c = &parag->string()->at(it.key()); 5135 QTextStringChar *c = &parag->string()->at(it.key());
5407 if ( c && c->customItem() && c->customItem()->ownLine() ) { 5136 if ( c && c->customItem() && c->customItem()->ownLine() ) {
5408 int h = c->customItem()->height; 5137 int h = c->customItem()->height;
5409 c->customItem()->pageBreak( parag->rect().y() + ls->y + ls->baseLine - h, doc->flow() ); 5138 c->customItem()->pageBreak( parag->rect().y() + ls->y + ls->baseLine - h, doc->flow() );
5410 int delta = c->customItem()->height - h; 5139 int delta = c->customItem()->height - h;
@@ -5417,36 +5146,38 @@ int QTextFormatter::formatVertically( QTextDocument* doc, QTextParag* parag )
5417 if ( shift ) 5146 if ( shift )
5418 parag->setMovedDown( TRUE ); 5147 parag->setMovedDown( TRUE );
5419 } 5148 }
5420 h = ls->y + ls->h; 5149 h = ls->y + ls->h;
5421 } 5150 }
5422 int m = parag->bottomMargin(); 5151 int m = parag->bottomMargin();
5423 if ( parag->next() && doc && !doc->addMargins() ) 5152 if ( !parag->next() )
5424 m = QMAX( m, parag->next()->topMargin() );
5425 if ( parag->next() && parag->next()->isLineBreak() )
5426 m = 0; 5153 m = 0;
5154 else
5155 m = QMAX(m, parag->next()->topMargin() ) / 2;
5427 h += m; 5156 h += m;
5428 parag->setHeight( h ); 5157 parag->setHeight( h );
5429 return h - oldHeight; 5158 return h - oldHeight;
5430} 5159}
5431 5160
5432// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5161// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5433 5162
5434QTextFormatterBreakInWords::QTextFormatterBreakInWords() 5163QTextFormatterBreakInWords::QTextFormatterBreakInWords()
5435{ 5164{
5436} 5165}
5437 5166
5438int QTextFormatterBreakInWords::format( QTextDocument *doc,QTextParag *parag, 5167#define SPACE(s) doc?(s>0?s:0):s
5439 int start, const QMap<int, QTextParagLineStart*> & ) 5168
5169int QTextFormatterBreakInWords::format( QTextDocument *doc,QTextParagraph *parag,
5170 int start, const QMap<int, QTextLineStart*> & )
5440{ 5171{
5441 QTextStringChar *c = 0; 5172 QTextStringChar *c = 0;
5442 QTextStringChar *firstChar = 0; 5173 QTextStringChar *firstChar = 0;
5443 int left = doc ? parag->leftMargin() + doc->leftMargin() : 4; 5174 int left = doc ? parag->leftMargin() + doc->leftMargin() : 0;
5444 int x = left + ( doc ? parag->firstLineMargin() : 0 ); 5175 int x = left + ( doc ? parag->firstLineMargin() : 0 );
5445 int dw = parag->documentVisibleWidth() - ( doc ? doc->rightMargin() : 0 ); 5176 int dw = parag->documentVisibleWidth() - ( doc ? doc->rightMargin() : 0 );
5446 int y = doc && doc->addMargins() ? parag->topMargin() : 0; 5177 int y = parag->prev() ? QMAX(parag->prev()->bottomMargin(),parag->topMargin()) / 2: 0;
5447 int h = y; 5178 int h = y;
5448 int len = parag->length(); 5179 int len = parag->length();
5449 if ( doc ) 5180 if ( doc )
5450 x = doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), x, 4 ); 5181 x = doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), x, 4 );
5451 int rm = parag->rightMargin(); 5182 int rm = parag->rightMargin();
5452 int w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 ); 5183 int w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
@@ -5457,13 +5188,13 @@ int QTextFormatterBreakInWords::format( QTextDocument *doc,QTextParag *parag,
5457 5188
5458 start = 0; //######### what is the point with start?! (Matthias) 5189 start = 0; //######### what is the point with start?! (Matthias)
5459 if ( start == 0 ) 5190 if ( start == 0 )
5460 c = &parag->string()->at( 0 ); 5191 c = &parag->string()->at( 0 );
5461 5192
5462 int i = start; 5193 int i = start;
5463 QTextParagLineStart *lineStart = new QTextParagLineStart( y, y, 0 ); 5194 QTextLineStart *lineStart = new QTextLineStart( y, y, 0 );
5464 insertLineStart( parag, 0, lineStart ); 5195 insertLineStart( parag, 0, lineStart );
5465 5196
5466 QPainter *painter = QTextFormat::painter(); 5197 QPainter *painter = QTextFormat::painter();
5467 5198
5468 int col = 0; 5199 int col = 0;
5469 int ww = 0; 5200 int ww = 0;
@@ -5498,29 +5229,28 @@ int QTextFormatterBreakInWords::format( QTextDocument *doc,QTextParag *parag,
5498 x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left; 5229 x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
5499 w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 ); 5230 w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
5500 c->customItem()->resize( w - x ); 5231 c->customItem()->resize( w - x );
5501 w = dw; 5232 w = dw;
5502 y += h; 5233 y += h;
5503 h = c->height(); 5234 h = c->height();
5504 lineStart = new QTextParagLineStart( y, h, h ); 5235 lineStart = new QTextLineStart( y, h, h );
5505 insertLineStart( parag, i, lineStart ); 5236 insertLineStart( parag, i, lineStart );
5506 c->lineStart = 1; 5237 c->lineStart = 1;
5507 firstChar = c; 5238 firstChar = c;
5508 x = 0xffffff; 5239 x = 0xffffff;
5509 continue; 5240 continue;
5510 } 5241 }
5511 5242
5512 if ( wrapEnabled && 5243 if ( wrapEnabled &&
5513 ( wrapAtColumn() == -1 && x + ww > w || 5244 ( wrapAtColumn() == -1 && x + ww > w ||
5514 wrapAtColumn() != -1 && col >= wrapAtColumn() ) || 5245 wrapAtColumn() != -1 && col >= wrapAtColumn() ) ) {
5515 parag->isNewLinesAllowed() && lastChr == '\n' ) {
5516 x = doc ? parag->document()->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left; 5246 x = doc ? parag->document()->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
5517 w = dw; 5247 w = dw;
5518 y += h; 5248 y += h;
5519 h = c->height(); 5249 h = c->height();
5520 lineStart = formatLine( parag, parag->string(), lineStart, firstChar, c-1 ); 5250 lineStart = formatLine( parag, parag->string(), lineStart, firstChar, SPACE(c-1) );
5521 lineStart->y = y; 5251 lineStart->y = y;
5522 insertLineStart( parag, i, lineStart ); 5252 insertLineStart( parag, i, lineStart );
5523 lineStart->baseLine = c->ascent(); 5253 lineStart->baseLine = c->ascent();
5524 lineStart->h = c->height(); 5254 lineStart->h = c->height();
5525 c->lineStart = 1; 5255 c->lineStart = 1;
5526 firstChar = c; 5256 firstChar = c;
@@ -5536,18 +5266,20 @@ int QTextFormatterBreakInWords::format( QTextDocument *doc,QTextParag *parag,
5536 c->x = x; 5266 c->x = x;
5537 x += ww; 5267 x += ww;
5538 wused = QMAX( wused, x ); 5268 wused = QMAX( wused, x );
5539 } 5269 }
5540 5270
5541 int m = parag->bottomMargin(); 5271 int m = parag->bottomMargin();
5542 if ( parag->next() && doc && !doc->addMargins() ) 5272 if ( !parag->next() )
5543 m = QMAX( m, parag->next()->topMargin() );
5544 parag->setFullWidth( fullWidth );
5545 if ( parag->next() && parag->next()->isLineBreak() )
5546 m = 0; 5273 m = 0;
5274 else
5275 m = QMAX(m, parag->next()->topMargin() ) / 2;
5276 parag->setFullWidth( fullWidth );
5547 y += h + m; 5277 y += h + m;
5278 if ( doc )
5279 minw += doc->rightMargin();
5548 if ( !wrapEnabled ) 5280 if ( !wrapEnabled )
5549 minw = QMAX(minw, wused); 5281 minw = QMAX(minw, wused);
5550 5282
5551 thisminw = minw; 5283 thisminw = minw;
5552 thiswused = wused; 5284 thiswused = wused;
5553 return y; 5285 return y;
@@ -5563,21 +5295,21 @@ QTextFormatterBreakWords::QTextFormatterBreakWords()
5563 int yflow = lineStart->y + parag->rect().y();\ 5295 int yflow = lineStart->y + parag->rect().y();\
5564 int shift = doc->flow()->adjustFlow( yflow, dw, lineStart->h ); \ 5296 int shift = doc->flow()->adjustFlow( yflow, dw, lineStart->h ); \
5565 lineStart->y += shift;\ 5297 lineStart->y += shift;\
5566 y += shift;\ 5298 y += shift;\
5567 }}while(FALSE) 5299 }}while(FALSE)
5568 5300
5569int QTextFormatterBreakWords::format( QTextDocument *doc, QTextParag *parag, 5301int QTextFormatterBreakWords::format( QTextDocument *doc, QTextParagraph *parag,
5570 int start, const QMap<int, QTextParagLineStart*> & ) 5302 int start, const QMap<int, QTextLineStart*> & )
5571{ 5303{
5572 QTextStringChar *c = 0; 5304 QTextStringChar *c = 0;
5573 QTextStringChar *firstChar = 0; 5305 QTextStringChar *firstChar = 0;
5574 QTextString *string = parag->string(); 5306 QTextString *string = parag->string();
5575 int left = doc ? parag->leftMargin() + doc->leftMargin() : 0; 5307 int left = doc ? parag->leftMargin() + doc->leftMargin() : 0;
5576 int x = left + ( doc ? parag->firstLineMargin() : 0 ); 5308 int x = left + ( doc ? parag->firstLineMargin() : 0 );
5577 int y = doc && doc->addMargins() ? parag->topMargin() : 0; 5309 int y = parag->prev() ? QMAX(parag->prev()->bottomMargin(),parag->topMargin()) / 2: 0;
5578 int h = y; 5310 int h = y;
5579 int len = parag->length(); 5311 int len = parag->length();
5580 if ( doc ) 5312 if ( doc )
5581 x = doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), x, 0 ); 5313 x = doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), x, 0 );
5582 int dw = parag->documentVisibleWidth() - ( doc ? ( left != x ? 0 : doc->rightMargin() ) : 0 ); 5314 int dw = parag->documentVisibleWidth() - ( doc ? ( left != x ? 0 : doc->rightMargin() ) : 0 );
5583 5315
@@ -5587,21 +5319,21 @@ int QTextFormatterBreakWords::format( QTextDocument *doc, QTextParag *parag,
5587 int w = dw - rdiff; 5319 int w = dw - rdiff;
5588 bool fullWidth = TRUE; 5320 bool fullWidth = TRUE;
5589 int marg = left + rdiff; 5321 int marg = left + rdiff;
5590 int minw = 0; 5322 int minw = 0;
5591 int wused = 0; 5323 int wused = 0;
5592 int tminw = marg; 5324 int tminw = marg;
5593 int linespace = doc ? parag->lineSpacing() : 0; 5325 int linespacing = doc ? parag->lineSpacing() : 0;
5594 bool wrapEnabled = isWrapEnabled( parag ); 5326 bool wrapEnabled = isWrapEnabled( parag );
5595 5327
5596 start = 0; 5328 start = 0;
5597 if ( start == 0 ) 5329 if ( start == 0 )
5598 c = &parag->string()->at( 0 ); 5330 c = &parag->string()->at( 0 );
5599 5331
5600 int i = start; 5332 int i = start;
5601 QTextParagLineStart *lineStart = new QTextParagLineStart( y, y, 0 ); 5333 QTextLineStart *lineStart = new QTextLineStart( y, y, 0 );
5602 insertLineStart( parag, 0, lineStart ); 5334 insertLineStart( parag, 0, lineStart );
5603 int lastBreak = -1; 5335 int lastBreak = -1;
5604 int tmpBaseLine = 0, tmph = 0; 5336 int tmpBaseLine = 0, tmph = 0;
5605 bool lastWasNonInlineCustom = FALSE; 5337 bool lastWasNonInlineCustom = FALSE;
5606 5338
5607 int align = parag->alignment(); 5339 int align = parag->alignment();
@@ -5651,111 +5383,126 @@ int QTextFormatterBreakWords::format( QTextDocument *doc, QTextParag *parag,
5651 ww = 0; 5383 ww = 0;
5652 5384
5653 QTextCustomItem* ci = c->customItem(); 5385 QTextCustomItem* ci = c->customItem();
5654 if ( c->isCustom() && ci->ownLine() ) { 5386 if ( c->isCustom() && ci->ownLine() ) {
5655 x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left; 5387 x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
5656 w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 ); 5388 w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
5657 QTextParagLineStart *lineStart2 = formatLine( parag, string, lineStart, firstChar, c-1, align, w - x ); 5389 QTextLineStart *lineStart2 = formatLine( parag, string, lineStart, firstChar, c-1, align, SPACE(w - x) );
5658 ci->resize( w - x); 5390 ci->resize( w - x);
5659 if ( ci->width < w - x ) { 5391 if ( ci->width < w - x ) {
5660 if ( align & Qt::AlignHCenter ) 5392 if ( align & Qt::AlignHCenter )
5661 x = ( w - ci->width ) / 2; 5393 x = ( w - ci->width ) / 2;
5662 else if ( align & Qt::AlignRight ) { 5394 else if ( align & Qt::AlignRight ) {
5663 x = w - ci->width; 5395 x = w - ci->width;
5664 } 5396 }
5665 } 5397 }
5666 c->x = x; 5398 c->x = x;
5667 curLeft = x; 5399 curLeft = x;
5668 if ( i == 0 || !isBreakable( string, i - 1 ) || string->at( i - 1 ).lineStart == 0 ) { 5400 if ( i == 0 || !isBreakable( string, i - 1 ) || string->at( i - 1 ).lineStart == 0 ) {
5669 y += QMAX( h, tmph ); 5401 y += QMAX( h, QMAX( tmph, linespacing ) );
5670 tmph = c->height() + linespace; 5402 tmph = c->height();
5671 h = tmph; 5403 h = tmph;
5672 lineStart = lineStart2; 5404 lineStart = lineStart2;
5673 lineStart->y = y; 5405 lineStart->y = y;
5674 insertLineStart( parag, i, lineStart ); 5406 insertLineStart( parag, i, lineStart );
5675 c->lineStart = 1; 5407 c->lineStart = 1;
5676 firstChar = c; 5408 firstChar = c;
5677 } else { 5409 } else {
5678 tmph = c->height() + linespace; 5410 tmph = c->height();
5679 h = tmph; 5411 h = tmph;
5680 delete lineStart2; 5412 delete lineStart2;
5681 } 5413 }
5682 lineStart->h = h; 5414 lineStart->h = h;
5683 lineStart->baseLine = h; 5415 lineStart->baseLine = h;
5684 tmpBaseLine = lineStart->baseLine; 5416 tmpBaseLine = lineStart->baseLine;
5685 lastBreak = -2; 5417 lastBreak = -2;
5686 x = 0xffffff; 5418 x = 0xffffff;
5687 minw = QMAX( minw, tminw ); 5419 minw = QMAX( minw, tminw );
5688 5420
5689 int tw = ci->minimumWidth(); 5421 int tw = ci->minimumWidth() + ( doc ? doc->leftMargin() : 0 );
5690 if ( tw < QWIDGETSIZE_MAX ) 5422 if ( tw < QWIDGETSIZE_MAX )
5691 tminw = tw; 5423 tminw = tw;
5692 else 5424 else
5693 tminw = marg; 5425 tminw = marg;
5694 wused = QMAX( wused, ci->width ); 5426 wused = QMAX( wused, ci->width );
5695 continue; 5427 continue;
5696 } else if ( c->isCustom() && ci->placement() != QTextCustomItem::PlaceInline ) { 5428 } else if ( c->isCustom() && ci->placement() != QTextCustomItem::PlaceInline ) {
5697 int tw = ci->minimumWidth(); 5429 int tw = ci->minimumWidth();
5698 if ( tw < QWIDGETSIZE_MAX ) 5430 if ( tw < QWIDGETSIZE_MAX )
5699 minw = QMAX( minw, tw ); 5431 minw = QMAX( minw, tw );
5700 } 5432 }
5701 5433
5702 if ( wrapEnabled && ( !c->c.isSpace() || lastBreak == -2 ) 5434 bool lastWasOwnLineCustomItem = lastBreak == -2;
5703 && ( lastBreak != -1 || allowBreakInWords() ) && 5435 bool hadBreakableChar = lastBreak != -1;
5704 ( wrapAtColumn() == -1 && x + ww > w && lastBreak != -1 || 5436 bool lastWasHardBreak = lastChr == QChar_linesep;
5705 wrapAtColumn() == -1 && x + ww > w - 4 && lastBreak == -1 && allowBreakInWords() || 5437
5706 wrapAtColumn() != -1 && col >= wrapAtColumn() ) || 5438 // we break if
5707 parag->isNewLinesAllowed() && lastChr == '\n' && firstChar < c ) { 5439 // 1. the last character was a hard break (QChar_linesep) or
5440 // 2. the last charater was a own-line custom item (eg. table or ruler) or
5441 // 3. wrapping was enabled, it was not a space and following
5442 // condition is true: We either had a breakable character
5443 // previously or we ar allowed to break in words and - either
5444 // we break at w pixels and the current char would exceed that
5445 // or - we break at a column and the current character would
5446 // exceed that.
5447 if ( lastWasHardBreak || lastWasOwnLineCustomItem ||
5448 ( wrapEnabled &&
5449 ( (!c->c.isSpace() && (hadBreakableChar || allowBreakInWords()) &&
5450 ( (wrapAtColumn() == -1 && x + ww > w) ||
5451 (wrapAtColumn() != -1 && col >= wrapAtColumn()) ) ) )
5452 )
5453 ) {
5708 if ( wrapAtColumn() != -1 ) 5454 if ( wrapAtColumn() != -1 )
5709 minw = QMAX( minw, x + ww ); 5455 minw = QMAX( minw, x + ww );
5710 if ( lastBreak < 0 ) { 5456 // if a break was forced (no breakable char, hard break or own line custom item), break immediately....
5457 if ( !hadBreakableChar || lastWasHardBreak || lastWasOwnLineCustomItem ) {
5711 if ( lineStart ) { 5458 if ( lineStart ) {
5712 lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine ); 5459 lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
5713 h = QMAX( h, tmph ); 5460 h = QMAX( h, tmph );
5714 lineStart->h = h; 5461 lineStart->h = h;
5715 DO_FLOW( lineStart ); 5462 DO_FLOW( lineStart );
5716 } 5463 }
5717 lineStart = formatLine( parag, string, lineStart, firstChar, c-1, align, w - x ); 5464 lineStart = formatLine( parag, string, lineStart, firstChar, c-1, align, SPACE(w - x) );
5718 x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left; 5465 x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
5719 w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 ); 5466 w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
5720 if ( parag->isNewLinesAllowed() && c->c == '\t' ) { 5467 if ( !doc && c->c == '\t' ) { // qt_format_text tab handling
5721 int nx = parag->nextTab( i, x - left ) + left; 5468 int nx = parag->nextTab( i, x - left ) + left;
5722 if ( nx < x ) 5469 if ( nx < x )
5723 ww = w - x; 5470 ww = w - x;
5724 else 5471 else
5725 ww = nx - x; 5472 ww = nx - x;
5726 } 5473 }
5727 curLeft = x; 5474 curLeft = x;
5728 y += h; 5475 y += QMAX( h, linespacing );
5729 tmph = c->height() + linespace; 5476 tmph = c->height();
5730 h = 0; 5477 h = 0;
5731 lineStart->y = y; 5478 lineStart->y = y;
5732 insertLineStart( parag, i, lineStart ); 5479 insertLineStart( parag, i, lineStart );
5733 lineStart->baseLine = c->ascent(); 5480 lineStart->baseLine = c->ascent();
5734 lineStart->h = c->height(); 5481 lineStart->h = c->height();
5735 c->lineStart = 1; 5482 c->lineStart = 1;
5736 firstChar = c; 5483 firstChar = c;
5737 tmpBaseLine = lineStart->baseLine; 5484 tmpBaseLine = lineStart->baseLine;
5738 lastBreak = -1; 5485 lastBreak = -1;
5739 col = 0; 5486 col = 0;
5740 } else { 5487 } else { // ... otherwise if we had a breakable char, break there
5741 DO_FLOW( lineStart ); 5488 DO_FLOW( lineStart );
5742 i = lastBreak; 5489 i = lastBreak;
5743 lineStart = formatLine( parag, string, lineStart, firstChar, parag->at( lastBreak ), align, w - string->at( i ).x ); 5490 lineStart = formatLine( parag, string, lineStart, firstChar, parag->at( lastBreak ),align, SPACE(w - string->at( i ).x) );
5744 x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left; 5491 x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
5745 w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 ); 5492 w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
5746 if ( parag->isNewLinesAllowed() && c->c == '\t' ) { 5493 if ( !doc && c->c == '\t' ) { // qt_format_text tab handling
5747 int nx = parag->nextTab( i, x - left ) + left; 5494 int nx = parag->nextTab( i, x - left ) + left;
5748 if ( nx < x ) 5495 if ( nx < x )
5749 ww = w - x; 5496 ww = w - x;
5750 else 5497 else
5751 ww = nx - x; 5498 ww = nx - x;
5752 } 5499 }
5753 curLeft = x; 5500 curLeft = x;
5754 y += h; 5501 y += QMAX( h, linespacing );
5755 tmph = c->height() + linespace; 5502 tmph = c->height();
5756 h = tmph; 5503 h = tmph;
5757 lineStart->y = y; 5504 lineStart->y = y;
5758 insertLineStart( parag, i + 1, lineStart ); 5505 insertLineStart( parag, i + 1, lineStart );
5759 lineStart->baseLine = c->ascent(); 5506 lineStart->baseLine = c->ascent();
5760 lineStart->h = c->height(); 5507 lineStart->h = c->height();
5761 c->lineStart = 1; 5508 c->lineStart = 1;
@@ -5763,69 +5510,81 @@ int QTextFormatterBreakWords::format( QTextDocument *doc, QTextParag *parag,
5763 tmpBaseLine = lineStart->baseLine; 5510 tmpBaseLine = lineStart->baseLine;
5764 lastBreak = -1; 5511 lastBreak = -1;
5765 col = 0; 5512 col = 0;
5766 tminw = marg; 5513 tminw = marg;
5767 continue; 5514 continue;
5768 } 5515 }
5769 } else if ( lineStart && ( isBreakable( string, i ) || parag->isNewLinesAllowed() && c->c == '\n' ) ) { 5516 } else if ( lineStart && isBreakable( string, i ) ) {
5770 if ( len <= 2 || i < len - 1 ) { 5517 if ( len <= 2 || i < len - 1 ) {
5771 tmpBaseLine = QMAX( tmpBaseLine, c->ascent() ); 5518 tmpBaseLine = QMAX( tmpBaseLine, c->ascent() );
5772 tmph = QMAX( tmph, c->height() + linespace ); 5519 tmph = QMAX( tmph, c->height() );
5773 } 5520 }
5774 minw = QMAX( minw, tminw ); 5521 minw = QMAX( minw, tminw );
5775 tminw = marg + ww; 5522 tminw = marg + ww;
5776 lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine ); 5523 lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
5777 h = QMAX( h, tmph ); 5524 h = QMAX( h, tmph );
5778 lineStart->h = h; 5525 lineStart->h = h;
5779 if ( i < len - 2 || c->c != ' ' ) 5526 if ( i < len - 2 || c->c != ' ' )
5780 lastBreak = i; 5527 lastBreak = i;
5781 } else { 5528 } else {
5782 tminw += ww; 5529 tminw += ww;
5783 int belowBaseLine = QMAX( tmph - tmpBaseLine, c->height() + linespace - c->ascent() ); 5530 int belowBaseLine = QMAX( tmph - tmpBaseLine, c->height()- c->ascent() );
5784 tmpBaseLine = QMAX( tmpBaseLine, c->ascent() ); 5531 tmpBaseLine = QMAX( tmpBaseLine, c->ascent() );
5785 tmph = tmpBaseLine + belowBaseLine; 5532 tmph = tmpBaseLine + belowBaseLine;
5786 } 5533 }
5787 5534
5788 c->x = x; 5535 c->x = x;
5789 x += ww; 5536 x += ww;
5790 wused = QMAX( wused, x ); 5537 wused = QMAX( wused, x );
5791 } 5538 }
5792 5539
5793 // ### hack. The last char in the paragraph is always invisible, and somehow sometimes has a wrong format. It changes between 5540 // ### hack. The last char in the paragraph is always invisible,
5794 // layouting and printing. This corrects some layouting errors in BiDi mode due to this. 5541 // ### and somehow sometimes has a wrong format. It changes
5542 // ### between // layouting and printing. This corrects some
5543 // ### layouting errors in BiDi mode due to this.
5795 if ( len > 1 && !c->isAnchor() ) { 5544 if ( len > 1 && !c->isAnchor() ) {
5796 c->format()->removeRef(); 5545 c->format()->removeRef();
5797 c->setFormat( string->at( len - 2 ).format() ); 5546 c->setFormat( string->at( len - 2 ).format() );
5798 c->format()->addRef(); 5547 c->format()->addRef();
5799 } 5548 }
5800 5549
5801 if ( lineStart ) { 5550 if ( lineStart ) {
5802 lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine ); 5551 lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
5803 h = QMAX( h, tmph ); 5552 h = QMAX( h, tmph );
5804 lineStart->h = h; 5553 lineStart->h = h;
5805 // last line in a paragraph is not justified 5554 // last line in a paragraph is not justified
5806 if ( align == Qt3::AlignJustify ) 5555 if ( align == Qt3::AlignJustify || lastChr == QChar_linesep )
5807 align = Qt3::AlignAuto; 5556 align = Qt3::AlignAuto;
5808 DO_FLOW( lineStart ); 5557 DO_FLOW( lineStart );
5809 lineStart = formatLine( parag, string, lineStart, firstChar, c, align, w - x ); 5558 lineStart = formatLine( parag, string, lineStart, firstChar, c, align, SPACE(w - x) );
5810 delete lineStart; 5559 delete lineStart;
5811 } 5560 }
5812 5561
5813 minw = QMAX( minw, tminw ); 5562 minw = QMAX( minw, tminw );
5563 if ( doc )
5564 minw += doc->rightMargin();
5814 5565
5815 int m = parag->bottomMargin(); 5566 int m = parag->bottomMargin();
5816 if ( parag->next() && doc && !doc->addMargins() ) 5567 if ( !parag->next() )
5817 m = QMAX( m, parag->next()->topMargin() );
5818 parag->setFullWidth( fullWidth );
5819 if ( parag->next() && parag->next()->isLineBreak() )
5820 m = 0; 5568 m = 0;
5821 y += h + m; 5569 else
5570 m = QMAX(m, parag->next()->topMargin() ) / 2;
5571 parag->setFullWidth( fullWidth );
5572 y += QMAX( h, linespacing ) + m;
5822 5573
5823 wused += rm; 5574 wused += rm;
5824 if ( !wrapEnabled || wrapAtColumn() != -1 ) 5575 if ( !wrapEnabled || wrapAtColumn() != -1 )
5825 minw = QMAX(minw, wused); 5576 minw = QMAX(minw, wused);
5577
5578 // This is the case where we are breaking wherever we darn well please
5579 // in cases like that, the minw should not be the length of the entire
5580 // word, because we necessarily want to show the word on the whole line.
5581 // example: word wrap in iconview
5582 if ( allowBreakInWords() && minw > wused )
5583 minw = wused;
5584
5826 thisminw = minw; 5585 thisminw = minw;
5827 thiswused = wused; 5586 thiswused = wused;
5828 return y; 5587 return y;
5829} 5588}
5830 5589
5831// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5590// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -5834,13 +5593,13 @@ QTextIndent::QTextIndent()
5834{ 5593{
5835} 5594}
5836 5595
5837// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5596// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5838 5597
5839QTextFormatCollection::QTextFormatCollection() 5598QTextFormatCollection::QTextFormatCollection()
5840 : cKey( 307 ), sheet( 0 ) 5599 : cKey( 307 )
5841{ 5600{
5842 defFormat = new QTextFormat( QApplication::font(), 5601 defFormat = new QTextFormat( QApplication::font(),
5843 QApplication::palette().color( QPalette::Active, QColorGroup::Text ) ); 5602 QApplication::palette().color( QPalette::Active, QColorGroup::Text ) );
5844 lastFormat = cres = 0; 5603 lastFormat = cres = 0;
5845 cflags = -1; 5604 cflags = -1;
5846 cKey.setAutoDelete( TRUE ); 5605 cKey.setAutoDelete( TRUE );
@@ -5852,56 +5611,41 @@ QTextFormatCollection::~QTextFormatCollection()
5852 delete defFormat; 5611 delete defFormat;
5853} 5612}
5854 5613
5855QTextFormat *QTextFormatCollection::format( QTextFormat *f ) 5614QTextFormat *QTextFormatCollection::format( QTextFormat *f )
5856{ 5615{
5857 if ( f->parent() == this || f == defFormat ) { 5616 if ( f->parent() == this || f == defFormat ) {
5858#ifdef DEBUG_COLLECTION
5859 qDebug( "need '%s', best case!", f->key().latin1() );
5860#endif
5861 lastFormat = f; 5617 lastFormat = f;
5862 lastFormat->addRef(); 5618 lastFormat->addRef();
5863 return lastFormat; 5619 return lastFormat;
5864 } 5620 }
5865 5621
5866 if ( f == lastFormat || ( lastFormat && f->key() == lastFormat->key() ) ) { 5622 if ( f == lastFormat || ( lastFormat && f->key() == lastFormat->key() ) ) {
5867#ifdef DEBUG_COLLECTION
5868 qDebug( "need '%s', good case!", f->key().latin1() );
5869#endif
5870 lastFormat->addRef(); 5623 lastFormat->addRef();
5871 return lastFormat; 5624 return lastFormat;
5872 } 5625 }
5873 5626
5874 QTextFormat *fm = cKey.find( f->key() ); 5627 QTextFormat *fm = cKey.find( f->key() );
5875 if ( fm ) { 5628 if ( fm ) {
5876#ifdef DEBUG_COLLECTION
5877 qDebug( "need '%s', normal case!", f->key().latin1() );
5878#endif
5879 lastFormat = fm; 5629 lastFormat = fm;
5880 lastFormat->addRef(); 5630 lastFormat->addRef();
5881 return lastFormat; 5631 return lastFormat;
5882 } 5632 }
5883 5633
5884 if ( f->key() == defFormat->key() ) 5634 if ( f->key() == defFormat->key() )
5885 return defFormat; 5635 return defFormat;
5886 5636
5887#ifdef DEBUG_COLLECTION
5888 qDebug( "need '%s', worst case!", f->key().latin1() );
5889#endif
5890 lastFormat = createFormat( *f ); 5637 lastFormat = createFormat( *f );
5891 lastFormat->collection = this; 5638 lastFormat->collection = this;
5892 cKey.insert( lastFormat->key(), lastFormat ); 5639 cKey.insert( lastFormat->key(), lastFormat );
5893 return lastFormat; 5640 return lastFormat;
5894} 5641}
5895 5642
5896QTextFormat *QTextFormatCollection::format( QTextFormat *of, QTextFormat *nf, int flags ) 5643QTextFormat *QTextFormatCollection::format( QTextFormat *of, QTextFormat *nf, int flags )
5897{ 5644{
5898 if ( cres && kof == of->key() && knf == nf->key() && cflags == flags ) { 5645 if ( cres && kof == of->key() && knf == nf->key() && cflags == flags ) {
5899#ifdef DEBUG_COLLECTION
5900 qDebug( "mix of '%s' and '%s, best case!", of->key().latin1(), nf->key().latin1() );
5901#endif
5902 cres->addRef(); 5646 cres->addRef();
5903 return cres; 5647 return cres;
5904 } 5648 }
5905 5649
5906 cres = createFormat( *of ); 5650 cres = createFormat( *of );
5907 kof = of->key(); 5651 kof = of->key();
@@ -5910,12 +5654,14 @@ QTextFormat *QTextFormatCollection::format( QTextFormat *of, QTextFormat *nf, in
5910 if ( flags & QTextFormat::Bold ) 5654 if ( flags & QTextFormat::Bold )
5911 cres->fn.setBold( nf->fn.bold() ); 5655 cres->fn.setBold( nf->fn.bold() );
5912 if ( flags & QTextFormat::Italic ) 5656 if ( flags & QTextFormat::Italic )
5913 cres->fn.setItalic( nf->fn.italic() ); 5657 cres->fn.setItalic( nf->fn.italic() );
5914 if ( flags & QTextFormat::Underline ) 5658 if ( flags & QTextFormat::Underline )
5915 cres->fn.setUnderline( nf->fn.underline() ); 5659 cres->fn.setUnderline( nf->fn.underline() );
5660 if ( flags & QTextFormat::StrikeOut )
5661 cres->fn.setStrikeOut( nf->fn.strikeOut() );
5916 if ( flags & QTextFormat::Family ) 5662 if ( flags & QTextFormat::Family )
5917 cres->fn.setFamily( nf->fn.family() ); 5663 cres->fn.setFamily( nf->fn.family() );
5918 if ( flags & QTextFormat::Size ) { 5664 if ( flags & QTextFormat::Size ) {
5919 if ( of->usePixelSizes ) 5665 if ( of->usePixelSizes )
5920 cres->fn.setPixelSize( nf->fn.pixelSize() ); 5666 cres->fn.setPixelSize( nf->fn.pixelSize() );
5921 else 5667 else
@@ -5928,63 +5674,48 @@ QTextFormat *QTextFormatCollection::format( QTextFormat *of, QTextFormat *nf, in
5928 if ( flags & QTextFormat::VAlign ) 5674 if ( flags & QTextFormat::VAlign )
5929 cres->ha = nf->ha; 5675 cres->ha = nf->ha;
5930 cres->update(); 5676 cres->update();
5931 5677
5932 QTextFormat *fm = cKey.find( cres->key() ); 5678 QTextFormat *fm = cKey.find( cres->key() );
5933 if ( !fm ) { 5679 if ( !fm ) {
5934#ifdef DEBUG_COLLECTION
5935 qDebug( "mix of '%s' and '%s, worst case!", of->key().latin1(), nf->key().latin1() );
5936#endif
5937 cres->collection = this; 5680 cres->collection = this;
5938 cKey.insert( cres->key(), cres ); 5681 cKey.insert( cres->key(), cres );
5939 } else { 5682 } else {
5940#ifdef DEBUG_COLLECTION
5941 qDebug( "mix of '%s' and '%s, good case!", of->key().latin1(), nf->key().latin1() );
5942#endif
5943 delete cres; 5683 delete cres;
5944 cres = fm; 5684 cres = fm;
5945 cres->addRef(); 5685 cres->addRef();
5946 } 5686 }
5947 5687
5948 return cres; 5688 return cres;
5949} 5689}
5950 5690
5951QTextFormat *QTextFormatCollection::format( const QFont &f, const QColor &c ) 5691QTextFormat *QTextFormatCollection::format( const QFont &f, const QColor &c )
5952{ 5692{
5953 if ( cachedFormat && cfont == f && ccol == c ) { 5693 if ( cachedFormat && cfont == f && ccol == c ) {
5954#ifdef DEBUG_COLLECTION
5955 qDebug( "format of font and col '%s' - best case", cachedFormat->key().latin1() );
5956#endif
5957 cachedFormat->addRef(); 5694 cachedFormat->addRef();
5958 return cachedFormat; 5695 return cachedFormat;
5959 } 5696 }
5960 5697
5961 QString key = QTextFormat::getKey( f, c, FALSE, QTextFormat::AlignNormal ); 5698 QString key = QTextFormat::getKey( f, c, FALSE, QTextFormat::AlignNormal );
5962 cachedFormat = cKey.find( key ); 5699 cachedFormat = cKey.find( key );
5963 cfont = f; 5700 cfont = f;
5964 ccol = c; 5701 ccol = c;
5965 5702
5966 if ( cachedFormat ) { 5703 if ( cachedFormat ) {
5967#ifdef DEBUG_COLLECTION
5968 qDebug( "format of font and col '%s' - good case", cachedFormat->key().latin1() );
5969#endif
5970 cachedFormat->addRef(); 5704 cachedFormat->addRef();
5971 return cachedFormat; 5705 return cachedFormat;
5972 } 5706 }
5973 5707
5974 if ( key == defFormat->key() ) 5708 if ( key == defFormat->key() )
5975 return defFormat; 5709 return defFormat;
5976 5710
5977 cachedFormat = createFormat( f, c ); 5711 cachedFormat = createFormat( f, c );
5978 cachedFormat->collection = this; 5712 cachedFormat->collection = this;
5979 cKey.insert( cachedFormat->key(), cachedFormat ); 5713 cKey.insert( cachedFormat->key(), cachedFormat );
5980 if ( cachedFormat->key() != key ) 5714 if ( cachedFormat->key() != key )
5981 qWarning("ASSERT: keys for format not identical: '%s '%s'", cachedFormat->key().latin1(), key.latin1() ); 5715 qWarning("ASSERT: keys for format not identical: '%s '%s'", cachedFormat->key().latin1(), key.latin1() );
5982#ifdef DEBUG_COLLECTION
5983 qDebug( "format of font and col '%s' - worst case", cachedFormat->key().latin1() );
5984#endif
5985 return cachedFormat; 5716 return cachedFormat;
5986} 5717}
5987 5718
5988void QTextFormatCollection::remove( QTextFormat *f ) 5719void QTextFormatCollection::remove( QTextFormat *f )
5989{ 5720{
5990 if ( lastFormat == f ) 5721 if ( lastFormat == f )
@@ -5993,112 +5724,72 @@ void QTextFormatCollection::remove( QTextFormat *f )
5993 cres = 0; 5724 cres = 0;
5994 if ( cachedFormat == f ) 5725 if ( cachedFormat == f )
5995 cachedFormat = 0; 5726 cachedFormat = 0;
5996 cKey.remove( f->key() ); 5727 cKey.remove( f->key() );
5997} 5728}
5998 5729
5999void QTextFormatCollection::debug() 5730#define UPDATE( up, lo, rest ) \
6000{ 5731 if ( font.lo##rest() != defFormat->fn.lo##rest() && fm->fn.lo##rest() == defFormat->fn.lo##rest() ) \
6001#ifdef DEBUG_COLLECTION 5732 fm->fn.set##up##rest( font.lo##rest() )
6002 qDebug( "------------ QTextFormatCollection: debug --------------- BEGIN" );
6003 QDictIterator<QTextFormat> it( cKey );
6004 for ( ; it.current(); ++it ) {
6005 qDebug( "format '%s' (%p): refcount: %d", it.current()->key().latin1(),
6006 it.current(), it.current()->ref );
6007 }
6008 qDebug( "------------ QTextFormatCollection: debug --------------- END" );
6009#endif
6010}
6011
6012void QTextFormatCollection::updateStyles()
6013{
6014 QDictIterator<QTextFormat> it( cKey );
6015 QTextFormat *f;
6016 while ( ( f = it.current() ) ) {
6017 ++it;
6018 f->updateStyle();
6019 }
6020 updateKeys();
6021}
6022
6023void QTextFormatCollection::updateFontSizes( int base, bool usePixels )
6024{
6025 QDictIterator<QTextFormat> it( cKey );
6026 QTextFormat *f;
6027 while ( ( f = it.current() ) ) {
6028 ++it;
6029 f->stdSize = base;
6030 f->usePixelSizes = usePixels;
6031 if ( usePixels )
6032 f->fn.setPixelSize( f->stdSize );
6033 else
6034 f->fn.setPointSize( f->stdSize );
6035 styleSheet()->scaleFont( f->fn, f->logicalFontSize );
6036 f->update();
6037 }
6038 f = defFormat;
6039 f->stdSize = base;
6040 f->usePixelSizes = usePixels;
6041 if ( usePixels )
6042 f->fn.setPixelSize( f->stdSize );
6043 else
6044 f->fn.setPointSize( f->stdSize );
6045 styleSheet()->scaleFont( f->fn, f->logicalFontSize );
6046 f->update();
6047 updateKeys();
6048}
6049 5733
6050void QTextFormatCollection::updateFontAttributes( const QFont &f, const QFont &old ) 5734void QTextFormatCollection::updateDefaultFormat( const QFont &font, const QColor &color, QStyleSheet *sheet )
6051{ 5735{
6052 QDictIterator<QTextFormat> it( cKey ); 5736 QDictIterator<QTextFormat> it( cKey );
6053 QTextFormat *fm; 5737 QTextFormat *fm;
5738 bool usePixels = font.pointSize() == -1;
5739 bool changeSize = usePixels ? font.pixelSize() != defFormat->fn.pixelSize() :
5740 font.pointSize() != defFormat->fn.pointSize();
5741 int base = usePixels ? font.pixelSize() : font.pointSize();
6054 while ( ( fm = it.current() ) ) { 5742 while ( ( fm = it.current() ) ) {
6055 ++it; 5743 ++it;
6056 if ( fm->fn.family() == old.family() && 5744 UPDATE( F, f, amily );
6057 fm->fn.weight() == old.weight() && 5745 UPDATE( W, w, eight );
6058 fm->fn.italic() == old.italic() && 5746 UPDATE( B, b, old );
6059 fm->fn.underline() == old.underline() ) { 5747 UPDATE( I, i, talic );
6060 fm->fn.setFamily( f.family() ); 5748 UPDATE( U, u, nderline );
6061 fm->fn.setWeight( f.weight() ); 5749 if ( changeSize ) {
6062 fm->fn.setItalic( f.italic() ); 5750 fm->stdSize = base;
6063 fm->fn.setUnderline( f.underline() ); 5751 fm->usePixelSizes = usePixels;
6064 fm->update(); 5752 if ( usePixels )
6065 } 5753 fm->fn.setPixelSize( fm->stdSize );
6066 } 5754 else
6067 fm = defFormat; 5755 fm->fn.setPointSize( fm->stdSize );
6068 if ( fm->fn.family() == old.family() && 5756 sheet->scaleFont( fm->fn, fm->logicalFontSize );
6069 fm->fn.weight() == old.weight() && 5757 }
6070 fm->fn.italic() == old.italic() && 5758 if ( color.isValid() && color != defFormat->col && fm->col == defFormat->col )
6071 fm->fn.underline() == old.underline() ) { 5759 fm->col = color;
6072 fm->fn.setFamily( f.family() );
6073 fm->fn.setWeight( f.weight() );
6074 fm->fn.setItalic( f.italic() );
6075 fm->fn.setUnderline( f.underline() );
6076 fm->update(); 5760 fm->update();
6077 } 5761 }
5762
5763 defFormat->fn = font;
5764 defFormat->col = color;
5765 defFormat->update();
5766 defFormat->stdSize = base;
5767 defFormat->usePixelSizes = usePixels;
5768
6078 updateKeys(); 5769 updateKeys();
6079} 5770}
6080 5771
6081
6082// the keys in cKey have changed, rebuild the hashtable 5772// the keys in cKey have changed, rebuild the hashtable
6083void QTextFormatCollection::updateKeys() 5773void QTextFormatCollection::updateKeys()
6084{ 5774{
6085 if ( cKey.isEmpty() ) 5775 if ( cKey.isEmpty() )
6086 return; 5776 return;
6087 cKey.setAutoDelete( FALSE ); 5777 cKey.setAutoDelete( FALSE );
6088 QTextFormat** formats = new QTextFormat*[ cKey.count() + 1]; 5778 QTextFormat** formats = new QTextFormat*[ cKey.count() + 1 ];
6089 QTextFormat **f = formats; 5779 QTextFormat **f = formats;
6090 QDictIterator<QTextFormat> it( cKey ); 5780 QDictIterator<QTextFormat> it( cKey );
6091 while ( ( *f = it.current() ) ) { 5781 while ( ( *f = it.current() ) ) {
6092 ++it; 5782 ++it;
6093 ++f; 5783 ++f;
6094 } 5784 }
6095 cKey.clear(); 5785 cKey.clear();
6096 for ( f = formats; *f; f++ ) 5786 for ( f = formats; *f; f++ )
6097 cKey.insert( (*f)->key(), *f ); 5787 cKey.insert( (*f)->key(), *f );
6098 cKey.setAutoDelete( TRUE ); 5788 cKey.setAutoDelete( TRUE );
5789 delete [] formats;
6099} 5790}
6100 5791
6101 5792
6102 5793
6103// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5794// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6104 5795
@@ -6139,12 +5830,20 @@ void QTextFormat::setUnderline( bool b )
6139 if ( b == fn.underline() ) 5830 if ( b == fn.underline() )
6140 return; 5831 return;
6141 fn.setUnderline( b ); 5832 fn.setUnderline( b );
6142 update(); 5833 update();
6143} 5834}
6144 5835
5836void QTextFormat::setStrikeOut( bool b )
5837{
5838 if ( b == fn.strikeOut() )
5839 return;
5840 fn.setStrikeOut( b );
5841 update();
5842}
5843
6145void QTextFormat::setFamily( const QString &f ) 5844void QTextFormat::setFamily( const QString &f )
6146{ 5845{
6147 if ( f == fn.family() ) 5846 if ( f == fn.family() )
6148 return; 5847 return;
6149 fn.setFamily( f ); 5848 fn.setFamily( f );
6150 update(); 5849 update();
@@ -6172,198 +5871,189 @@ void QTextFormat::setColor( const QColor &c )
6172 if ( c == col ) 5871 if ( c == col )
6173 return; 5872 return;
6174 col = c; 5873 col = c;
6175 update(); 5874 update();
6176} 5875}
6177 5876
6178static int makeLogicFontSize( int s ) 5877QString QTextFormat::makeFormatChangeTags( QTextFormat* defaultFormat, QTextFormat *f,
6179{ 5878 const QString& oldAnchorHref, const QString& anchorHref ) const
6180 int defSize = QApplication::font().pointSize();
6181 if ( s < defSize - 4 )
6182 return 1;
6183 if ( s < defSize )
6184 return 2;
6185 if ( s < defSize + 4 )
6186 return 3;
6187 if ( s < defSize + 8 )
6188 return 4;
6189 if ( s < defSize + 12 )
6190 return 5;
6191 if (s < defSize + 16 )
6192 return 6;
6193 return 7;
6194}
6195
6196static QTextFormat *defaultFormat = 0;
6197
6198QString QTextFormat::makeFormatChangeTags( QTextFormat *f, const QString& oldAnchorHref, const QString& anchorHref ) const
6199{ 5879{
6200 if ( !defaultFormat ) // #### wrong, use the document's default format instead
6201 defaultFormat = new QTextFormat( QApplication::font(),
6202 QApplication::palette().color( QPalette::Active, QColorGroup::Text ) );
6203
6204 QString tag; 5880 QString tag;
6205 if ( f ) { 5881 if ( f )
6206 if ( f->font() != defaultFormat->font() ) { 5882 tag += f->makeFormatEndTags( defaultFormat, oldAnchorHref );
6207 if ( f->font().family() != defaultFormat->font().family()
6208 || f->font().pointSize() != defaultFormat->font().pointSize()
6209 || f->color().rgb() != defaultFormat->color().rgb() )
6210 tag += "</font>";
6211 if ( f->font().underline() && f->font().underline() != defaultFormat->font().underline() )
6212 tag += "</u>";
6213 if ( f->font().italic() && f->font().italic() != defaultFormat->font().italic() )
6214 tag += "</i>";
6215 if ( f->font().bold() && f->font().bold() != defaultFormat->font().bold() )
6216 tag += "</b>";
6217 }
6218 if ( !oldAnchorHref.isEmpty() )
6219 tag += "</a>";
6220 }
6221 5883
6222 if ( !anchorHref.isEmpty() ) 5884 if ( !anchorHref.isEmpty() )
6223 tag += "<a href=\"" + anchorHref + "\">"; 5885 tag += "<a href=\"" + anchorHref + "\">";
6224 5886
6225 if ( font() != defaultFormat->font() ) {
6226 if ( font().bold() && font().bold() != defaultFormat->font().bold() )
6227 tag += "<b>";
6228 if ( font().italic() && font().italic() != defaultFormat->font().italic() )
6229 tag += "<i>";
6230 if ( font().underline() && font().underline() != defaultFormat->font().underline() )
6231 tag += "<u>";
6232 }
6233 if ( font() != defaultFormat->font() 5887 if ( font() != defaultFormat->font()
5888 || vAlign() != defaultFormat->vAlign()
6234 || color().rgb() != defaultFormat->color().rgb() ) { 5889 || color().rgb() != defaultFormat->color().rgb() ) {
6235 QString f; 5890 QString s;
6236 if ( font().family() != defaultFormat->font().family() ) 5891 if ( font().family() != defaultFormat->font().family() )
6237 f +=" face=\"" + fn.family() + "\""; 5892 s += QString(!!s?";":"") + "font-family:" + fn.family();
6238 if ( font().pointSize() != defaultFormat->font().pointSize() ) { 5893 if ( font().italic() && font().italic() != defaultFormat->font().italic() )
6239 f +=" size=\"" + QString::number( makeLogicFontSize( fn.pointSize() ) ) + "\""; 5894 s += QString(!!s?";":"") + "font-style:" + (font().italic() ? "italic" : "normal");
6240 f +=" style=\"font-size:" + QString::number( fn.pointSize() ) + "pt\""; 5895 if ( font().pointSize() != defaultFormat->font().pointSize() )
5896 s += QString(!!s?";":"") + "font-size:" + QString::number( fn.pointSize() ) + "pt";
5897 if ( font().weight() != defaultFormat->font().weight() )
5898 s += QString(!!s?";":"") + "font-weight:" + QString::number( fn.weight() * 8 );
5899 if ( font().underline() != defaultFormat->font().underline() )
5900 s += QString(!!s?";":"") + "text-decoration:" + ( font().underline() ? "underline" : "none");
5901 if ( vAlign() != defaultFormat->vAlign() ) {
5902 s += QString(!!s?";":"") + "vertical-align:";
5903 if ( vAlign() == QTextFormat::AlignSuperScript )
5904 s += "super";
5905 else if ( vAlign() == QTextFormat::AlignSubScript )
5906 s += "sub";
5907 else
5908 s += "normal";
6241 } 5909 }
6242 if ( color().rgb() != defaultFormat->color().rgb() ) 5910 if ( color().rgb() != defaultFormat->color().rgb() )
6243 f +=" color=\"" + col.name() + "\""; 5911 s += QString(!!s?";":"") + "color:" + col.name();
6244 if ( !f.isEmpty() ) 5912 if ( !s.isEmpty() )
6245 tag += "<font" + f + ">"; 5913 tag += "<span style=\"" + s + "\">";
6246 } 5914 }
6247 5915
6248 return tag; 5916 return tag;
6249} 5917}
6250 5918
6251QString QTextFormat::makeFormatEndTags( const QString& anchorHref ) const 5919QString QTextFormat::makeFormatEndTags( QTextFormat* defaultFormat, const QString& anchorHref ) const
6252{ 5920{
6253 if ( !defaultFormat )
6254 defaultFormat = new QTextFormat( QApplication::font(),
6255 QApplication::palette().color( QPalette::Active, QColorGroup::Text ) );
6256
6257 QString tag; 5921 QString tag;
6258 if ( font() != defaultFormat->font() ) { 5922 if ( font().family() != defaultFormat->font().family()
6259 if ( font().family() != defaultFormat->font().family() 5923 || font().pointSize() != defaultFormat->font().pointSize()
6260 || font().pointSize() != defaultFormat->font().pointSize() 5924 || font().weight() != defaultFormat->font().weight()
6261 || color().rgb() != defaultFormat->color().rgb() ) 5925 || font().italic() != defaultFormat->font().italic()
6262 tag += "</font>"; 5926 || font().underline() != defaultFormat->font().underline()
6263 if ( font().underline() && font().underline() != defaultFormat->font().underline() ) 5927 || font().strikeOut() != defaultFormat->font().strikeOut()
6264 tag += "</u>"; 5928 || vAlign() != defaultFormat->vAlign()
6265 if ( font().italic() && font().italic() != defaultFormat->font().italic() ) 5929 || color().rgb() != defaultFormat->color().rgb() )
6266 tag += "</i>"; 5930 tag += "</span>";
6267 if ( font().bold() && font().bold() != defaultFormat->font().bold() )
6268 tag += "</b>";
6269 }
6270 if ( !anchorHref.isEmpty() ) 5931 if ( !anchorHref.isEmpty() )
6271 tag += "</a>"; 5932 tag += "</a>";
6272 return tag; 5933 return tag;
6273} 5934}
6274 5935
6275QTextFormat QTextFormat::makeTextFormat( const QStyleSheetItem *style, const QMap<QString,QString>& attr ) const 5936QTextFormat QTextFormat::makeTextFormat( const QStyleSheetItem *style, const QMap<QString,QString>& attr, double scaleFontsFactor ) const
6276{ 5937{
6277 QTextFormat format(*this); 5938 QTextFormat format(*this);
6278 if ( style ) { 5939 if (!style )
6279 format.style = style->name(); 5940 return format;
6280 if ( style->name() == "font") { 5941
6281 if ( attr.contains("color") ) { 5942 if ( !style->isAnchor() && style->color().isValid() ) {
6282 QString s = attr["color"]; 5943 // the style is not an anchor and defines a color.
6283 if ( !s.isEmpty() ) { 5944 // It might be used inside an anchor and it should
6284 format.col.setNamedColor( s ); 5945 // override the link color.
6285 format.linkColor = FALSE; 5946 format.linkColor = FALSE;
6286 } 5947 }
6287 } 5948 switch ( style->verticalAlignment() ) {
6288 if ( attr.contains("size") ) { 5949 case QStyleSheetItem::VAlignBaseline:
6289 QString a = attr["size"]; 5950 format.setVAlign( QTextFormat::AlignNormal );
6290 int n = a.toInt(); 5951 break;
6291 if ( a[0] == '+' || a[0] == '-' ) 5952 case QStyleSheetItem::VAlignSuper:
6292 n += format.logicalFontSize; 5953 format.setVAlign( QTextFormat::AlignSuperScript );
6293 format.logicalFontSize = n; 5954 break;
6294 if ( format.usePixelSizes ) 5955 case QStyleSheetItem::VAlignSub:
6295 format.fn.setPixelSize( format.stdSize ); 5956 format.setVAlign( QTextFormat::AlignSubScript );
6296 else 5957 break;
6297 format.fn.setPointSize( format.stdSize ); 5958 }
6298 style->styleSheet()->scaleFont( format.fn, format.logicalFontSize ); 5959
6299 } 5960 if ( style->fontWeight() != QStyleSheetItem::Undefined )
6300 if ( attr.contains("style" ) ) { 5961 format.fn.setWeight( style->fontWeight() );
6301 QString a = attr["style"]; 5962 if ( style->fontSize() != QStyleSheetItem::Undefined ) {
6302 if ( a.startsWith( "font-size:" ) ) { 5963 format.fn.setPointSize( style->fontSize() );
6303 QString s = a.mid( a.find( ':' ) + 1 ); 5964 } else if ( style->logicalFontSize() != QStyleSheetItem::Undefined ) {
6304 int n = s.left( s.length() - 2 ).toInt(); 5965 format.logicalFontSize = style->logicalFontSize();
6305 format.logicalFontSize = 0; 5966 if ( format.usePixelSizes )
6306 if ( format.usePixelSizes ) 5967 format.fn.setPixelSize( format.stdSize );
6307 format.fn.setPixelSize( n ); 5968 else
6308 else 5969 format.fn.setPointSize( format.stdSize );
6309 format.fn.setPointSize( n ); 5970 style->styleSheet()->scaleFont( format.fn, format.logicalFontSize );
6310 } 5971 } else if ( style->logicalFontSizeStep() ) {
6311 } 5972 format.logicalFontSize += style->logicalFontSizeStep();
6312 if ( attr.contains("face") ) { 5973 if ( format.usePixelSizes )
6313 QString a = attr["face"]; 5974 format.fn.setPixelSize( format.stdSize );
6314 if ( a.contains(',') ) 5975 else
6315 a = a.left( a.find(',') ); 5976 format.fn.setPointSize( format.stdSize );
6316 format.fn.setFamily( a ); 5977 style->styleSheet()->scaleFont( format.fn, format.logicalFontSize );
6317 } 5978 }
6318 } else { 5979 if ( !style->fontFamily().isEmpty() )
6319 if ( !style->isAnchor() && style->color().isValid() ) { 5980 format.fn.setFamily( style->fontFamily() );
6320 // the style is not an anchor and defines a color. 5981 if ( style->color().isValid() )
6321 // It might be used inside an anchor and it should 5982 format.col = style->color();
6322 // override the link color. 5983 if ( style->definesFontItalic() )
5984 format.fn.setItalic( style->fontItalic() );
5985 if ( style->definesFontUnderline() )
5986 format.fn.setUnderline( style->fontUnderline() );
5987 if ( style->definesFontStrikeOut() )
5988 format.fn.setStrikeOut( style->fontStrikeOut() );
5989
5990
5991 if ( style->name() == "font") {
5992 if ( attr.contains("color") ) {
5993 QString s = attr["color"];
5994 if ( !s.isEmpty() ) {
5995 format.col.setNamedColor( s );
6323 format.linkColor = FALSE; 5996 format.linkColor = FALSE;
6324 } 5997 }
6325 switch ( style->verticalAlignment() ) { 5998 }
6326 case QStyleSheetItem::VAlignBaseline: 5999 if ( attr.contains("face") ) {
6327 format.setVAlign( QTextFormat::AlignNormal ); 6000 QString a = attr["face"];
6328 break; 6001 QString family = QTextDocument::section( a, ",", 0, 0 );
6329 case QStyleSheetItem::VAlignSuper: 6002 if ( !!family )
6330 format.setVAlign( QTextFormat::AlignSuperScript ); 6003 format.fn.setFamily( family );
6331 break; 6004 }
6332 case QStyleSheetItem::VAlignSub: 6005 if ( attr.contains("size") ) {
6333 format.setVAlign( QTextFormat::AlignSubScript ); 6006 QString a = attr["size"];
6334 break; 6007 int n = a.toInt();
6335 } 6008 if ( a[0] == '+' || a[0] == '-' )
6336 6009 n += format.logicalFontSize;
6337 if ( style->fontWeight() != QStyleSheetItem::Undefined ) 6010 format.logicalFontSize = n;
6338 format.fn.setWeight( style->fontWeight() ); 6011 if ( format.usePixelSizes )
6339 if ( style->fontSize() != QStyleSheetItem::Undefined ) { 6012 format.fn.setPixelSize( format.stdSize );
6340 format.fn.setPointSize( style->fontSize() ); 6013 else
6341 } else if ( style->logicalFontSize() != QStyleSheetItem::Undefined ) { 6014 format.fn.setPointSize( format.stdSize );
6342 format.logicalFontSize = style->logicalFontSize(); 6015 style->styleSheet()->scaleFont( format.fn, format.logicalFontSize );
6343 if ( format.usePixelSizes ) 6016 }
6344 format.fn.setPixelSize( format.stdSize ); 6017 }
6345 else 6018 if ( attr.contains("style" ) ) {
6346 format.fn.setPointSize( format.stdSize ); 6019 QString a = attr["style"];
6347 style->styleSheet()->scaleFont( format.fn, format.logicalFontSize ); 6020 for ( int s = 0; s < a.contains(';')+1; s++ ) {
6348 } else if ( style->logicalFontSizeStep() ) { 6021 QString style = QTextDocument::section( a, ";", s, s );
6349 format.logicalFontSize += style->logicalFontSizeStep(); 6022 if ( style.startsWith("font-size:" ) && QTextDocument::endsWith(style, "pt") ) {
6350 if ( format.usePixelSizes ) 6023 format.logicalFontSize = 0;
6351 format.fn.setPixelSize( format.stdSize ); 6024 format.setPointSize( int( scaleFontsFactor * style.mid( 10, style.length() - 12 ).toInt() ) );
6025 } if ( style.startsWith("font-style:" ) ) {
6026 QString s = style.mid( 11 ).stripWhiteSpace();
6027 if ( s == "normal" )
6028 format.fn.setItalic( FALSE );
6029 else if ( s == "italic" || s == "oblique" )
6030 format.fn.setItalic( TRUE );
6031 } else if ( style.startsWith("font-weight:" ) ) {
6032 QString s = style.mid( 12 );
6033 bool ok = TRUE;
6034 int n = s.toInt( &ok );
6035 if ( ok )
6036 format.fn.setWeight( n/8 );
6037 } else if ( style.startsWith("font-family:" ) ) {
6038 format.fn.setFamily( QTextDocument::section(style.mid(12),",",0,0).stripWhiteSpace() );
6039 } else if ( style.startsWith("text-decoration:" ) ) {
6040 QString s = style.mid( 16 ).stripWhiteSpace();
6041 format.fn.setUnderline( s == "underline" );
6042 } else if ( style.startsWith("vertical-align:" ) ) {
6043 QString s = style.mid( 15 ).stripWhiteSpace();
6044 if ( s == "sub" )
6045 format.setVAlign( QTextFormat::AlignSubScript );
6046 else if ( s == "super" )
6047 format.setVAlign( QTextFormat::AlignSuperScript );
6352 else 6048 else
6353 format.fn.setPointSize( format.stdSize ); 6049 format.setVAlign( QTextFormat::AlignNormal );
6354 style->styleSheet()->scaleFont( format.fn, format.logicalFontSize ); 6050 } else if ( style.startsWith("color:" ) ) {
6051 format.col.setNamedColor( style.mid(6) );
6052 format.linkColor = FALSE;
6355 } 6053 }
6356 if ( !style->fontFamily().isEmpty() )
6357 format.fn.setFamily( style->fontFamily() );
6358 if ( style->color().isValid() )
6359 format.col = style->color();
6360 if ( style->definesFontItalic() )
6361 format.fn.setItalic( style->fontItalic() );
6362 if ( style->definesFontUnderline() )
6363 format.fn.setUnderline( style->fontUnderline() );
6364 } 6054 }
6365 } 6055 }
6366 6056
6367 format.update(); 6057 format.update();
6368 return format; 6058 return format;
6369} 6059}
@@ -6378,32 +6068,24 @@ struct QPixmapInt
6378static QMap<QString, QPixmapInt> *pixmap_map = 0; 6068static QMap<QString, QPixmapInt> *pixmap_map = 0;
6379 6069
6380QTextImage::QTextImage( QTextDocument *p, const QMap<QString, QString> &attr, const QString& context, 6070QTextImage::QTextImage( QTextDocument *p, const QMap<QString, QString> &attr, const QString& context,
6381 QMimeSourceFactory &factory ) 6071 QMimeSourceFactory &factory )
6382 : QTextCustomItem( p ) 6072 : QTextCustomItem( p )
6383{ 6073{
6384#if defined(PARSER_DEBUG)
6385 qDebug( debug_indent + "new QTextImage (pappi: %p)", p );
6386#endif
6387
6388 width = height = 0; 6074 width = height = 0;
6389 if ( attr.contains("width") ) 6075 if ( attr.contains("width") )
6390 width = attr["width"].toInt(); 6076 width = attr["width"].toInt();
6391 if ( attr.contains("height") ) 6077 if ( attr.contains("height") )
6392 height = attr["height"].toInt(); 6078 height = attr["height"].toInt();
6393 6079
6394 reg = 0; 6080 reg = 0;
6395 QString imageName = attr["src"]; 6081 QString imageName = attr["src"];
6396 6082
6397 if (!imageName) 6083 if (!imageName)
6398 imageName = attr["source"]; 6084 imageName = attr["source"];
6399 6085
6400#if defined(PARSER_DEBUG)
6401 qDebug( debug_indent + " .." + imageName );
6402#endif
6403
6404 if ( !imageName.isEmpty() ) { 6086 if ( !imageName.isEmpty() ) {
6405 imgId = QString( "%1,%2,%3,%4" ).arg( imageName ).arg( width ).arg( height ).arg( (ulong)&factory ); 6087 imgId = QString( "%1,%2,%3,%4" ).arg( imageName ).arg( width ).arg( height ).arg( (ulong)&factory );
6406 if ( !pixmap_map ) 6088 if ( !pixmap_map )
6407 pixmap_map = new QMap<QString, QPixmapInt>; 6089 pixmap_map = new QMap<QString, QPixmapInt>;
6408 if ( pixmap_map->contains( imgId ) ) { 6090 if ( pixmap_map->contains( imgId ) ) {
6409 QPixmapInt& pmi = pixmap_map->operator[](imgId); 6091 QPixmapInt& pmi = pixmap_map->operator[](imgId);
@@ -6484,12 +6166,13 @@ QTextImage::~QTextImage()
6484 if ( pixmap_map->isEmpty() ) { 6166 if ( pixmap_map->isEmpty() ) {
6485 delete pixmap_map; 6167 delete pixmap_map;
6486 pixmap_map = 0; 6168 pixmap_map = 0;
6487 } 6169 }
6488 } 6170 }
6489 } 6171 }
6172 delete reg;
6490} 6173}
6491 6174
6492QString QTextImage::richText() const 6175QString QTextImage::richText() const
6493{ 6176{
6494 QString s; 6177 QString s;
6495 s += "<img "; 6178 s += "<img ";
@@ -6642,13 +6325,13 @@ static bool qt_is_cell_in_use( QPtrList<QTextTableCell>& cells, int row, int col
6642 return TRUE; 6325 return TRUE;
6643 } 6326 }
6644 return FALSE; 6327 return FALSE;
6645} 6328}
6646 6329
6647QTextCustomItem* QTextDocument::parseTable( const QMap<QString, QString> &attr, const QTextFormat &fmt, 6330QTextCustomItem* QTextDocument::parseTable( const QMap<QString, QString> &attr, const QTextFormat &fmt,
6648 const QChar* doc, int length, int& pos, QTextParag *curpar ) 6331 const QChar* doc, int length, int& pos, QTextParagraph *curpar )
6649{ 6332{
6650 6333
6651 QTextTable* table = new QTextTable( this, attr ); 6334 QTextTable* table = new QTextTable( this, attr );
6652 int row = -1; 6335 int row = -1;
6653 int col = -1; 6336 int col = -1;
6654 6337
@@ -6662,15 +6345,12 @@ QTextCustomItem* QTextDocument::parseTable( const QMap<QString, QString> &attr,
6662 (void) eatSpace(doc, length, pos); 6345 (void) eatSpace(doc, length, pos);
6663 while ( pos < length) { 6346 while ( pos < length) {
6664 if (hasPrefix(doc, length, pos, QChar('<')) ){ 6347 if (hasPrefix(doc, length, pos, QChar('<')) ){
6665 if (hasPrefix(doc, length, pos+1, QChar('/'))) { 6348 if (hasPrefix(doc, length, pos+1, QChar('/'))) {
6666 tagname = parseCloseTag( doc, length, pos ); 6349 tagname = parseCloseTag( doc, length, pos );
6667 if ( tagname == "table" ) { 6350 if ( tagname == "table" ) {
6668#if defined(PARSER_DEBUG)
6669 debug_indent.remove( debug_indent.length() - 3, 2 );
6670#endif
6671 return table; 6351 return table;
6672 } 6352 }
6673 } else { 6353 } else {
6674 QMap<QString, QString> attr2; 6354 QMap<QString, QString> attr2;
6675 bool emptyTag = FALSE; 6355 bool emptyTag = FALSE;
6676 tagname = parseOpenTag( doc, length, pos, attr2, emptyTag ); 6356 tagname = parseOpenTag( doc, length, pos, attr2, emptyTag );
@@ -6721,31 +6401,28 @@ QTextCustomItem* QTextDocument::parseTable( const QMap<QString, QString> &attr,
6721 end++; 6401 end++;
6722 } 6402 }
6723 } 6403 }
6724 end++; 6404 end++;
6725 } 6405 }
6726 QTextTableCell* cell = new QTextTableCell( table, row, col, 6406 QTextTableCell* cell = new QTextTableCell( table, row, col,
6727 attr2, s, fmt.makeTextFormat( s, attr2 ), 6407 attr2, s, fmt.makeTextFormat( s, attr2, scaleFontsFactor ),
6728 contxt, *factory_, sheet_, 6408 contxt, *factory_, sheet_,
6729 QString( doc, length).mid( pos, end - pos ) ); 6409 QString( doc, length).mid( pos, end - pos ) );
6730 cell->richText()->parParag = curpar; 6410 cell->richText()->parentPar = curpar;
6731 if ( cell->colspan() > 1 || cell->rowspan() > 1 ) 6411 if ( cell->colspan() > 1 || cell->rowspan() > 1 )
6732 multicells.append( cell ); 6412 multicells.append( cell );
6733 col += cell->colspan()-1; 6413 col += cell->colspan()-1;
6734 pos = end; 6414 pos = end;
6735 } 6415 }
6736 } 6416 }
6737 } 6417 }
6738 6418
6739 } else { 6419 } else {
6740 ++pos; 6420 ++pos;
6741 } 6421 }
6742 } 6422 }
6743#if defined(PARSER_DEBUG)
6744 debug_indent.remove( debug_indent.length() - 3, 2 );
6745#endif
6746 return table; 6423 return table;
6747} 6424}
6748 6425
6749bool QTextDocument::eatSpace(const QChar* doc, int length, int& pos, bool includeNbsp ) 6426bool QTextDocument::eatSpace(const QChar* doc, int length, int& pos, bool includeNbsp )
6750{ 6427{
6751 int old_pos = pos; 6428 int old_pos = pos;
@@ -7128,25 +6805,16 @@ QChar QTextDocument::parseChar(const QChar* doc, int length, int& pos, QStyleShe
7128 6805
7129 if (c == '<' ) 6806 if (c == '<' )
7130 return QChar::null; 6807 return QChar::null;
7131 6808
7132 if ( c.isSpace() && c != QChar::nbsp ) { 6809 if ( c.isSpace() && c != QChar::nbsp ) {
7133 if ( wsm == QStyleSheetItem::WhiteSpacePre ) { 6810 if ( wsm == QStyleSheetItem::WhiteSpacePre ) {
7134 if ( c == ' ' )
7135 return QChar::nbsp;
7136 else
7137 return c;
7138 } else if ( wsm == QStyleSheetItem_WhiteSpaceNoCompression ) {
7139 return c;
7140 } else if ( wsm == QStyleSheetItem_WhiteSpaceNormalWithNewlines ) {
7141 if ( c == '\n' ) 6811 if ( c == '\n' )
6812 return QChar_linesep;
6813 else
7142 return c; 6814 return c;
7143 while ( pos< length &&
7144 doc[pos].isSpace() && doc[pos] != QChar::nbsp && doc[pos] != '\n' )
7145 pos++;
7146 return ' ';
7147 } else { // non-pre mode: collapse whitespace except nbsp 6815 } else { // non-pre mode: collapse whitespace except nbsp
7148 while ( pos< length && 6816 while ( pos< length &&
7149 doc[pos].isSpace() && doc[pos] != QChar::nbsp ) 6817 doc[pos].isSpace() && doc[pos] != QChar::nbsp )
7150 pos++; 6818 pos++;
7151 if ( wsm == QStyleSheetItem::WhiteSpaceNoWrap ) 6819 if ( wsm == QStyleSheetItem::WhiteSpaceNoWrap )
7152 return QChar::nbsp; 6820 return QChar::nbsp;
@@ -7352,17 +7020,12 @@ void QTextCustomItem::pageBreak( int /*y*/ , QTextFlow* /*flow*/ )
7352} 7020}
7353 7021
7354QTextTable::QTextTable( QTextDocument *p, const QMap<QString, QString> & attr ) 7022QTextTable::QTextTable( QTextDocument *p, const QMap<QString, QString> & attr )
7355 : QTextCustomItem( p ) 7023 : QTextCustomItem( p )
7356{ 7024{
7357 cells.setAutoDelete( FALSE ); 7025 cells.setAutoDelete( FALSE );
7358#if defined(PARSER_DEBUG)
7359 debug_indent += "\t";
7360 qDebug( debug_indent + "new QTextTable (%p)", this );
7361 debug_indent += "\t";
7362#endif
7363 cellspacing = 2; 7026 cellspacing = 2;
7364 if ( attr.contains("cellspacing") ) 7027 if ( attr.contains("cellspacing") )
7365 cellspacing = attr["cellspacing"].toInt(); 7028 cellspacing = attr["cellspacing"].toInt();
7366 cellpadding = 1; 7029 cellpadding = 1;
7367 if ( attr.contains("cellpadding") ) 7030 if ( attr.contains("cellpadding") )
7368 cellpadding = attr["cellpadding"].toInt(); 7031 cellpadding = attr["cellpadding"].toInt();
@@ -7437,16 +7100,16 @@ QString QTextTable::richText() const
7437 if ( lastRow != -1 ) 7100 if ( lastRow != -1 )
7438 s += "</tr>\n"; 7101 s += "</tr>\n";
7439 s += "<tr>"; 7102 s += "<tr>";
7440 lastRow = cell->row(); 7103 lastRow = cell->row();
7441 needEnd = TRUE; 7104 needEnd = TRUE;
7442 } 7105 }
7443 s += "<td "; 7106 s += "<td";
7444 it = cell->attributes.begin(); 7107 it = cell->attributes.begin();
7445 for ( ; it != cell->attributes.end(); ++it ) 7108 for ( ; it != cell->attributes.end(); ++it )
7446 s += it.key() + "=" + *it + " "; 7109 s += " " + it.key() + "=" + *it;
7447 s += ">"; 7110 s += ">";
7448 s += cell->richText()->richText(); 7111 s += cell->richText()->richText();
7449 s += "</td>"; 7112 s += "</td>";
7450 } 7113 }
7451 if ( needEnd ) 7114 if ( needEnd )
7452 s += "</tr>\n"; 7115 s += "</tr>\n";
@@ -7573,18 +7236,12 @@ void QTextTable::draw(QPainter* p, int x, int y, int cx, int cy, int cw, int ch,
7573 p->fillRect( r.left(), r.bottom()-s, r.width(), s, cg.button() ); 7236 p->fillRect( r.left(), r.bottom()-s, r.width(), s, cg.button() );
7574 } 7237 }
7575 qDrawShadePanel( p, r, cg, FALSE, border ); 7238 qDrawShadePanel( p, r, cg, FALSE, border );
7576 } 7239 }
7577 } 7240 }
7578 7241
7579#if defined(DEBUG_TABLE_RENDERING)
7580 p->save();
7581 p->setPen( Qt::red );
7582 p->drawRect( x, y, width, height );
7583 p->restore();
7584#endif
7585} 7242}
7586 7243
7587int QTextTable::minimumWidth() const 7244int QTextTable::minimumWidth() const
7588{ 7245{
7589 return (layout ? layout->minimumSize().width() : 0) + 2 * outerborder; 7246 return (layout ? layout->minimumSize().width() : 0) + 2 * outerborder;
7590} 7247}
@@ -7640,22 +7297,22 @@ void QTextTable::addCell( QTextTableCell* cell )
7640{ 7297{
7641 cells.append( cell ); 7298 cells.append( cell );
7642 layout->addMultiCell( cell, cell->row(), cell->row() + cell->rowspan()-1, 7299 layout->addMultiCell( cell, cell->row(), cell->row() + cell->rowspan()-1,
7643 cell->column(), cell->column() + cell->colspan()-1 ); 7300 cell->column(), cell->column() + cell->colspan()-1 );
7644} 7301}
7645 7302
7646bool QTextTable::enter( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy, bool atEnd ) 7303bool QTextTable::enter( QTextCursor *c, QTextDocument *&doc, QTextParagraph *&parag, int &idx, int &ox, int &oy, bool atEnd )
7647{ 7304{
7648 currCell.remove( c ); 7305 currCell.remove( c );
7649 if ( !atEnd ) 7306 if ( !atEnd )
7650 return next( c, doc, parag, idx, ox, oy ); 7307 return next( c, doc, parag, idx, ox, oy );
7651 currCell.insert( c, cells.count() ); 7308 currCell.insert( c, cells.count() );
7652 return prev( c, doc, parag, idx, ox, oy ); 7309 return prev( c, doc, parag, idx, ox, oy );
7653} 7310}
7654 7311
7655bool QTextTable::enterAt( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy, const QPoint &pos ) 7312bool QTextTable::enterAt( QTextCursor *c, QTextDocument *&doc, QTextParagraph *&parag, int &idx, int &ox, int &oy, const QPoint &pos )
7656{ 7313{
7657 currCell.remove( c ); 7314 currCell.remove( c );
7658 int lastCell = -1; 7315 int lastCell = -1;
7659 int lastY = -1; 7316 int lastY = -1;
7660 int i; 7317 int i;
7661 for ( i = 0; i < (int)cells.count(); ++i ) { 7318 for ( i = 0; i < (int)cells.count(); ++i ) {
@@ -7689,20 +7346,20 @@ bool QTextTable::enterAt( QTextCursor *c, QTextDocument *&doc, QTextParag *&para
7689 } 7346 }
7690 7347
7691 QTextTableCell *cell = cells.at( *currCell.find( c ) ); 7348 QTextTableCell *cell = cells.at( *currCell.find( c ) );
7692 if ( !cell ) 7349 if ( !cell )
7693 return FALSE; 7350 return FALSE;
7694 doc = cell->richText(); 7351 doc = cell->richText();
7695 parag = doc->firstParag(); 7352 parag = doc->firstParagraph();
7696 idx = 0; 7353 idx = 0;
7697 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x(); 7354 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
7698 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder; 7355 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
7699 return TRUE; 7356 return TRUE;
7700} 7357}
7701 7358
7702bool QTextTable::next( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy ) 7359bool QTextTable::next( QTextCursor *c, QTextDocument *&doc, QTextParagraph *&parag, int &idx, int &ox, int &oy )
7703{ 7360{
7704 int cc = -1; 7361 int cc = -1;
7705 if ( currCell.find( c ) != currCell.end() ) 7362 if ( currCell.find( c ) != currCell.end() )
7706 cc = *currCell.find( c ); 7363 cc = *currCell.find( c );
7707 if ( cc > (int)cells.count() - 1 || cc < 0 ) 7364 if ( cc > (int)cells.count() - 1 || cc < 0 )
7708 cc = -1; 7365 cc = -1;
@@ -7722,20 +7379,20 @@ bool QTextTable::next( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag,
7722 if ( currCell.find( c ) == currCell.end() ) 7379 if ( currCell.find( c ) == currCell.end() )
7723 return FALSE; 7380 return FALSE;
7724 QTextTableCell *cell = cells.at( *currCell.find( c ) ); 7381 QTextTableCell *cell = cells.at( *currCell.find( c ) );
7725 if ( !cell ) 7382 if ( !cell )
7726 return FALSE; 7383 return FALSE;
7727 doc = cell->richText(); 7384 doc = cell->richText();
7728 parag = doc->firstParag(); 7385 parag = doc->firstParagraph();
7729 idx = 0; 7386 idx = 0;
7730 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x(); 7387 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
7731 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder; 7388 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
7732 return TRUE; 7389 return TRUE;
7733} 7390}
7734 7391
7735bool QTextTable::prev( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy ) 7392bool QTextTable::prev( QTextCursor *c, QTextDocument *&doc, QTextParagraph *&parag, int &idx, int &ox, int &oy )
7736{ 7393{
7737 int cc = -1; 7394 int cc = -1;
7738 if ( currCell.find( c ) != currCell.end() ) 7395 if ( currCell.find( c ) != currCell.end() )
7739 cc = *currCell.find( c ); 7396 cc = *currCell.find( c );
7740 if ( cc > (int)cells.count() - 1 || cc < 0 ) 7397 if ( cc > (int)cells.count() - 1 || cc < 0 )
7741 cc = cells.count(); 7398 cc = cells.count();
@@ -7755,20 +7412,20 @@ bool QTextTable::prev( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag,
7755 if ( currCell.find( c ) == currCell.end() ) 7412 if ( currCell.find( c ) == currCell.end() )
7756 return FALSE; 7413 return FALSE;
7757 QTextTableCell *cell = cells.at( *currCell.find( c ) ); 7414 QTextTableCell *cell = cells.at( *currCell.find( c ) );
7758 if ( !cell ) 7415 if ( !cell )
7759 return FALSE; 7416 return FALSE;
7760 doc = cell->richText(); 7417 doc = cell->richText();
7761 parag = doc->firstParag(); 7418 parag = doc->lastParagraph();
7762 idx = parag->length() - 1; 7419 idx = parag->length() - 1;
7763 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x(); 7420 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
7764 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder; 7421 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
7765 return TRUE; 7422 return TRUE;
7766} 7423}
7767 7424
7768bool QTextTable::down( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy ) 7425bool QTextTable::down( QTextCursor *c, QTextDocument *&doc, QTextParagraph *&parag, int &idx, int &ox, int &oy )
7769{ 7426{
7770 if ( currCell.find( c ) == currCell.end() ) 7427 if ( currCell.find( c ) == currCell.end() )
7771 return FALSE; 7428 return FALSE;
7772 QTextTableCell *cell = cells.at( *currCell.find( c ) ); 7429 QTextTableCell *cell = cells.at( *currCell.find( c ) );
7773 if ( cell->row_ == layout->numRows() - 1 ) { 7430 if ( cell->row_ == layout->numRows() - 1 ) {
7774 currCell.insert( c, 0 ); 7431 currCell.insert( c, 0 );
@@ -7793,20 +7450,20 @@ bool QTextTable::down( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag,
7793 break; 7450 break;
7794 } 7451 }
7795 } 7452 }
7796 doc = cell->richText(); 7453 doc = cell->richText();
7797 if ( !cell ) 7454 if ( !cell )
7798 return FALSE; 7455 return FALSE;
7799 parag = doc->firstParag(); 7456 parag = doc->firstParagraph();
7800 idx = 0; 7457 idx = 0;
7801 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x(); 7458 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
7802 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder; 7459 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
7803 return TRUE; 7460 return TRUE;
7804} 7461}
7805 7462
7806bool QTextTable::up( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, int &idx, int &ox, int &oy ) 7463bool QTextTable::up( QTextCursor *c, QTextDocument *&doc, QTextParagraph *&parag, int &idx, int &ox, int &oy )
7807{ 7464{
7808 if ( currCell.find( c ) == currCell.end() ) 7465 if ( currCell.find( c ) == currCell.end() )
7809 return FALSE; 7466 return FALSE;
7810 QTextTableCell *cell = cells.at( *currCell.find( c ) ); 7467 QTextTableCell *cell = cells.at( *currCell.find( c ) );
7811 if ( cell->row_ == 0 ) { 7468 if ( cell->row_ == 0 ) {
7812 currCell.insert( c, 0 ); 7469 currCell.insert( c, 0 );
@@ -7831,13 +7488,13 @@ bool QTextTable::up( QTextCursor *c, QTextDocument *&doc, QTextParag *&parag, in
7831 break; 7488 break;
7832 } 7489 }
7833 } 7490 }
7834 doc = cell->richText(); 7491 doc = cell->richText();
7835 if ( !cell ) 7492 if ( !cell )
7836 return FALSE; 7493 return FALSE;
7837 parag = doc->lastParag(); 7494 parag = doc->lastParagraph();
7838 idx = parag->length() - 1; 7495 idx = parag->length() - 1;
7839 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x(); 7496 ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
7840 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder; 7497 oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
7841 return TRUE; 7498 return TRUE;
7842} 7499}
7843 7500
@@ -7846,16 +7503,12 @@ QTextTableCell::QTextTableCell( QTextTable* table,
7846 const QMap<QString, QString> &attr, 7503 const QMap<QString, QString> &attr,
7847 const QStyleSheetItem* /*style*/, // ### use them 7504 const QStyleSheetItem* /*style*/, // ### use them
7848 const QTextFormat& /*fmt*/, const QString& context, 7505 const QTextFormat& /*fmt*/, const QString& context,
7849 QMimeSourceFactory &factory, QStyleSheet *sheet, 7506 QMimeSourceFactory &factory, QStyleSheet *sheet,
7850 const QString& doc) 7507 const QString& doc)
7851{ 7508{
7852#if defined(PARSER_DEBUG)
7853 qDebug( debug_indent + "new QTextTableCell1 (pappi: %p)", table );
7854 qDebug( debug_indent + doc );
7855#endif
7856 cached_width = -1; 7509 cached_width = -1;
7857 cached_sizehint = -1; 7510 cached_sizehint = -1;
7858 7511
7859 maxw = QWIDGETSIZE_MAX; 7512 maxw = QWIDGETSIZE_MAX;
7860 minw = 0; 7513 minw = 0;
7861 7514
@@ -7885,13 +7538,14 @@ QTextTableCell::QTextTableCell( QTextTable* table,
7885 align |= Qt::AlignBottom; 7538 align |= Qt::AlignBottom;
7886 } 7539 }
7887 richtext->setFormatter( table->parent->formatter() ); 7540 richtext->setFormatter( table->parent->formatter() );
7888 richtext->setUseFormatCollection( table->parent->useFormatCollection() ); 7541 richtext->setUseFormatCollection( table->parent->useFormatCollection() );
7889 richtext->setMimeSourceFactory( &factory ); 7542 richtext->setMimeSourceFactory( &factory );
7890 richtext->setStyleSheet( sheet ); 7543 richtext->setStyleSheet( sheet );
7891 richtext->setDefaultFont( table->parent->formatCollection()->defaultFormat()->font() ); 7544 richtext->setDefaultFormat( table->parent->formatCollection()->defaultFormat()->font(),
7545 table->parent->formatCollection()->defaultFormat()->color() );
7892 richtext->setRichText( doc, context ); 7546 richtext->setRichText( doc, context );
7893 rowspan_ = 1; 7547 rowspan_ = 1;
7894 colspan_ = 1; 7548 colspan_ = 1;
7895 if ( attr.contains("colspan") ) 7549 if ( attr.contains("colspan") )
7896 colspan_ = attr["colspan"].toInt(); 7550 colspan_ = attr["colspan"].toInt();
7897 if ( attr.contains("rowspan") ) 7551 if ( attr.contains("rowspan") )
@@ -7921,40 +7575,12 @@ QTextTableCell::QTextTableCell( QTextTable* table,
7921 7575
7922 attributes = attr; 7576 attributes = attr;
7923 7577
7924 parent->addCell( this ); 7578 parent->addCell( this );
7925} 7579}
7926 7580
7927QTextTableCell::QTextTableCell( QTextTable* table, int row, int column )
7928{
7929#if defined(PARSER_DEBUG)
7930 qDebug( debug_indent + "new QTextTableCell2( pappi: %p", table );
7931#endif
7932 maxw = QWIDGETSIZE_MAX;
7933 minw = 0;
7934 cached_width = -1;
7935 cached_sizehint = -1;
7936
7937 parent = table;
7938 row_ = row;
7939 col_ = column;
7940 stretch_ = 0;
7941 richtext = new QTextDocument( table->parent );
7942 richtext->setTableCell( this );
7943 richtext->setFormatter( table->parent->formatter() );
7944 richtext->setUseFormatCollection( table->parent->useFormatCollection() );
7945 richtext->setDefaultFont( table->parent->formatCollection()->defaultFormat()->font() );
7946 richtext->setRichText( "<html></html>", QString::null );
7947 rowspan_ = 1;
7948 colspan_ = 1;
7949 background = 0;
7950 hasFixedWidth = FALSE;
7951 parent->addCell( this );
7952}
7953
7954
7955QTextTableCell::~QTextTableCell() 7581QTextTableCell::~QTextTableCell()
7956{ 7582{
7957 delete background; 7583 delete background;
7958 background = 0; 7584 background = 0;
7959 delete richtext; 7585 delete richtext;
7960 richtext = 0; 7586 richtext = 0;
@@ -8024,13 +7650,13 @@ int QTextTableCell::heightForWidth( int w ) const
8024 } 7650 }
8025 return richtext->height() + extra; 7651 return richtext->height() + extra;
8026} 7652}
8027 7653
8028void QTextTableCell::adjustToPainter( QPainter* p ) 7654void QTextTableCell::adjustToPainter( QPainter* p )
8029{ 7655{
8030 QTextParag *parag = richtext->firstParag(); 7656 QTextParagraph *parag = richtext->firstParagraph();
8031 while ( parag ) { 7657 while ( parag ) {
8032 parag->adjustToPainter( p ); 7658 parag->adjustToPainter( p );
8033 parag = parag->next(); 7659 parag = parag->next();
8034 } 7660 }
8035} 7661}
8036 7662
@@ -8068,18 +7694,151 @@ void QTextTableCell::draw( QPainter* p, int x, int y, int cx, int cy, int cw, in
8068 else if ( richtext->paper() ) 7694 else if ( richtext->paper() )
8069 p->fillRect( 0, 0, geom.width(), geom.height(), *richtext->paper() ); 7695 p->fillRect( 0, 0, geom.width(), geom.height(), *richtext->paper() );
8070 7696
8071 p->translate( horizontalAlignmentOffset(), verticalAlignmentOffset() ); 7697 p->translate( horizontalAlignmentOffset(), verticalAlignmentOffset() );
8072 7698
8073 QRegion r; 7699 QRegion r;
8074 QTextCursor *c = 0;
8075 if ( richtext->parent()->tmpCursor )
8076 c = richtext->parent()->tmpCursor;
8077 if ( cx >= 0 && cy >= 0 ) 7700 if ( cx >= 0 && cy >= 0 )
8078 richtext->draw( p, cx - ( x + horizontalAlignmentOffset() + geom.x() ), 7701 richtext->draw( p, cx - ( x + horizontalAlignmentOffset() + geom.x() ),
8079 cy - ( y + geom.y() + verticalAlignmentOffset() ), 7702 cy - ( y + geom.y() + verticalAlignmentOffset() ),
8080 cw, ch, g, FALSE, (c != 0), c ); 7703 cw, ch, g, FALSE, FALSE, 0 );
8081 else 7704 else
8082 richtext->draw( p, -1, -1, -1, -1, g, FALSE, (c != 0), c ); 7705 richtext->draw( p, -1, -1, -1, -1, g, FALSE, FALSE, 0 );
8083 7706
8084 p->restore(); 7707 p->restore();
8085} 7708}
7709
7710QString QTextDocument::section( QString str, const QString &sep, int start, int end )
7711{
7712 const QChar *uc = str.unicode();
7713 if ( !uc )
7714 return QString();
7715 QString _sep = sep;
7716 const QChar *uc_sep = _sep.unicode();
7717 if(!uc_sep)
7718 return QString();
7719 bool match = FALSE, last_match = TRUE;
7720
7721 //find start
7722 int n = str.length(), sep_len = _sep.length();
7723 const QChar *begin = start < 0 ? uc + n : uc;
7724 while(start) {
7725 match = FALSE;
7726 int c = 0;
7727 for(const QChar *tmp = start < 0 ? begin - sep_len : begin;
7728 c < sep_len && tmp < uc + n && tmp >= uc; tmp++, c++) {
7729 if( *tmp != *(uc_sep + c) )
7730 break;
7731 if(c == sep_len - 1) {
7732 match = TRUE;
7733 break;
7734 }
7735 }
7736 last_match = match;
7737
7738 if(start < 0) {
7739 if(match) {
7740 begin -= sep_len;
7741 if(!++start)
7742 break;
7743 } else {
7744 if(start == -1 && begin == uc)
7745 break;
7746 begin--;
7747 }
7748 } else {
7749 if(match) {
7750 if(!--start)
7751 break;
7752 begin += sep_len;
7753 } else {
7754 if(start == 1 && begin == uc + n)
7755 break;
7756 begin++;
7757 }
7758 }
7759 if(begin > uc + n || begin < uc)
7760 return QString();
7761 }
7762 if(match)
7763 begin+=sep_len;
7764 if(begin > uc + n || begin < uc)
7765 return QString();
7766
7767 //now find last
7768 match = FALSE;
7769 const QChar *last = end < 0 ? uc + n : uc;
7770 if(end == -1) {
7771 int c = 0;
7772 for(const QChar *tmp = end < 0 ? last - sep_len : last;
7773 c < sep_len && tmp < uc + n && tmp >= uc; tmp++, c++) {
7774 if( *tmp != *(uc_sep + c) )
7775 break;
7776 if(c == sep_len - 1) {
7777 match = TRUE;
7778 break;
7779 }
7780 }
7781 } else {
7782 end++;
7783 last_match = TRUE;
7784 while(end) {
7785 match = FALSE;
7786 int c = 0;
7787 for(const QChar *tmp = end < 0 ? last - sep_len : last;
7788 c < sep_len && tmp < uc + n && tmp >= uc; tmp++, c++) {
7789 if( *tmp != *(uc_sep + c) )
7790 break;
7791 if(c == sep_len - 1) {
7792 match = TRUE;
7793 break;
7794 }
7795 }
7796 last_match = match;
7797
7798 if(end < 0) {
7799 if(match) {
7800 if(!++end)
7801 break;
7802 last -= sep_len;
7803 } else {
7804 last--;
7805 }
7806 } else {
7807 if(match) {
7808 last += sep_len;
7809 if(!--end)
7810 break;
7811 } else {
7812 last++;
7813 }
7814 }
7815 if(last >= uc + n) {
7816 last = uc + n;
7817 break;
7818 } else if(last < uc) {
7819 return QString();
7820 }
7821 }
7822 }
7823 if(match)
7824 last -= sep_len;
7825 if(last < uc || last > uc + n || begin >= last)
7826 return QString();
7827
7828 //done
7829 return QString(begin, last - begin);
7830}
7831
7832bool QTextDocument::endsWith( QString str, const QString &s)
7833{
7834 if ( str.isNull() )
7835 return s.isNull();
7836 int pos = str.length() - s.length();
7837 if ( pos < 0 )
7838 return FALSE;
7839 for ( uint i = 0; i < s.length(); i++ ) {
7840 if ( str.unicode()[pos+i] != s[(int)i] )
7841 return FALSE;
7842 }
7843 return TRUE;
7844}