1 | /****************************************************************************
|
---|
2 | ** $Id: qrichtext.cpp 2 2005-11-16 15:49:26Z dmik $
|
---|
3 | **
|
---|
4 | ** Implementation of the internal Qt classes dealing with rich text
|
---|
5 | **
|
---|
6 | ** Created : 990101
|
---|
7 | **
|
---|
8 | ** Copyright (C) 1992-2003 Trolltech AS. All rights reserved.
|
---|
9 | **
|
---|
10 | ** This file is part of the kernel module of the Qt GUI Toolkit.
|
---|
11 | **
|
---|
12 | ** This file may be distributed under the terms of the Q Public License
|
---|
13 | ** as defined by Trolltech AS of Norway and appearing in the file
|
---|
14 | ** LICENSE.QPL included in the packaging of this file.
|
---|
15 | **
|
---|
16 | ** This file may be distributed and/or modified under the terms of the
|
---|
17 | ** GNU General Public License version 2 as published by the Free Software
|
---|
18 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
19 | ** packaging of this file.
|
---|
20 | **
|
---|
21 | ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
|
---|
22 | ** licenses may use this file in accordance with the Qt Commercial License
|
---|
23 | ** Agreement provided with the Software.
|
---|
24 | **
|
---|
25 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
---|
26 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
---|
27 | **
|
---|
28 | ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
|
---|
29 | ** information about Qt Commercial License Agreements.
|
---|
30 | ** See http://www.trolltech.com/qpl/ for QPL licensing information.
|
---|
31 | ** See http://www.trolltech.com/gpl/ for GPL licensing information.
|
---|
32 | **
|
---|
33 | ** Contact info@trolltech.com if any conditions of this licensing are
|
---|
34 | ** not clear to you.
|
---|
35 | **
|
---|
36 | **********************************************************************/
|
---|
37 |
|
---|
38 | #include "qrichtext_p.h"
|
---|
39 |
|
---|
40 | #ifndef QT_NO_RICHTEXT
|
---|
41 |
|
---|
42 |
|
---|
43 | #include "qstringlist.h"
|
---|
44 | #include "qfont.h"
|
---|
45 | #include "qtextstream.h"
|
---|
46 | #include "qfile.h"
|
---|
47 | #include "qapplication.h"
|
---|
48 | #include "qmap.h"
|
---|
49 | #include "qfileinfo.h"
|
---|
50 | #include "qstylesheet.h"
|
---|
51 | #include "qmime.h"
|
---|
52 | #include "qimage.h"
|
---|
53 | #include "qdragobject.h"
|
---|
54 | #include "qpaintdevicemetrics.h"
|
---|
55 | #include "qpainter.h"
|
---|
56 | #include "qdrawutil.h"
|
---|
57 | #include "qcursor.h"
|
---|
58 | #include "qptrstack.h"
|
---|
59 | #include "qptrdict.h"
|
---|
60 | #include "qstyle.h"
|
---|
61 | #include "qcleanuphandler.h"
|
---|
62 | #include "qtextengine_p.h"
|
---|
63 | #include <private/qunicodetables_p.h>
|
---|
64 |
|
---|
65 | #include <stdlib.h>
|
---|
66 |
|
---|
67 | static QTextCursor* richTextExportStart = 0;
|
---|
68 | static QTextCursor* richTextExportEnd = 0;
|
---|
69 |
|
---|
70 | class QTextFormatCollection;
|
---|
71 |
|
---|
72 | const int border_tolerance = 2;
|
---|
73 |
|
---|
74 | #ifdef Q_WS_WIN
|
---|
75 | #include "qt_windows.h"
|
---|
76 | #endif
|
---|
77 |
|
---|
78 | #define QChar_linesep QChar(0x2028U)
|
---|
79 |
|
---|
80 | static inline bool is_printer( QPainter *p )
|
---|
81 | {
|
---|
82 | if ( !p || !p->device() )
|
---|
83 | return FALSE;
|
---|
84 | return p->device()->devType() == QInternal::Printer;
|
---|
85 | }
|
---|
86 |
|
---|
87 | static inline int scale( int value, QPainter *painter )
|
---|
88 | {
|
---|
89 | if ( is_printer( painter ) ) {
|
---|
90 | QPaintDeviceMetrics metrics( painter->device() );
|
---|
91 | #if defined(Q_WS_X11)
|
---|
92 | value = value * metrics.logicalDpiY() /
|
---|
93 | QPaintDevice::x11AppDpiY( painter->device()->x11Screen() );
|
---|
94 | #elif defined (Q_WS_WIN)
|
---|
95 | HDC hdc = GetDC( 0 );
|
---|
96 | int gdc = GetDeviceCaps( hdc, LOGPIXELSY );
|
---|
97 | if ( gdc )
|
---|
98 | value = value * metrics.logicalDpiY() / gdc;
|
---|
99 | ReleaseDC( 0, hdc );
|
---|
100 | #elif defined (Q_WS_MAC)
|
---|
101 | value = value * metrics.logicalDpiY() / 75; // ##### FIXME
|
---|
102 | #elif defined (Q_WS_QWS)
|
---|
103 | value = value * metrics.logicalDpiY() / 75;
|
---|
104 | #endif
|
---|
105 | }
|
---|
106 | return value;
|
---|
107 | }
|
---|
108 |
|
---|
109 |
|
---|
110 | inline bool isBreakable( QTextString *string, int pos )
|
---|
111 | {
|
---|
112 | if (string->at(pos).nobreak)
|
---|
113 | return FALSE;
|
---|
114 | return (pos < string->length()-1 && string->at(pos+1).softBreak);
|
---|
115 | }
|
---|
116 |
|
---|
117 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
118 |
|
---|
119 | void QTextCommandHistory::addCommand( QTextCommand *cmd )
|
---|
120 | {
|
---|
121 | if ( current < (int)history.count() - 1 ) {
|
---|
122 | QPtrList<QTextCommand> commands;
|
---|
123 | commands.setAutoDelete( FALSE );
|
---|
124 |
|
---|
125 | for( int i = 0; i <= current; ++i ) {
|
---|
126 | commands.insert( i, history.at( 0 ) );
|
---|
127 | history.take( 0 );
|
---|
128 | }
|
---|
129 |
|
---|
130 | commands.append( cmd );
|
---|
131 | history.clear();
|
---|
132 | history = commands;
|
---|
133 | history.setAutoDelete( TRUE );
|
---|
134 | } else {
|
---|
135 | history.append( cmd );
|
---|
136 | }
|
---|
137 |
|
---|
138 | if ( (int)history.count() > steps )
|
---|
139 | history.removeFirst();
|
---|
140 | else
|
---|
141 | ++current;
|
---|
142 | }
|
---|
143 |
|
---|
144 | QTextCursor *QTextCommandHistory::undo( QTextCursor *c )
|
---|
145 | {
|
---|
146 | if ( current > -1 ) {
|
---|
147 | QTextCursor *c2 = history.at( current )->unexecute( c );
|
---|
148 | --current;
|
---|
149 | return c2;
|
---|
150 | }
|
---|
151 | return 0;
|
---|
152 | }
|
---|
153 |
|
---|
154 | QTextCursor *QTextCommandHistory::redo( QTextCursor *c )
|
---|
155 | {
|
---|
156 | if ( current > -1 ) {
|
---|
157 | if ( current < (int)history.count() - 1 ) {
|
---|
158 | ++current;
|
---|
159 | return history.at( current )->execute( c );
|
---|
160 | }
|
---|
161 | } else {
|
---|
162 | if ( history.count() > 0 ) {
|
---|
163 | ++current;
|
---|
164 | return history.at( current )->execute( c );
|
---|
165 | }
|
---|
166 | }
|
---|
167 | return 0;
|
---|
168 | }
|
---|
169 |
|
---|
170 | bool QTextCommandHistory::isUndoAvailable()
|
---|
171 | {
|
---|
172 | return current > -1;
|
---|
173 | }
|
---|
174 |
|
---|
175 | bool QTextCommandHistory::isRedoAvailable()
|
---|
176 | {
|
---|
177 | return current > -1 && current < (int)history.count() - 1 || current == -1 && history.count() > 0;
|
---|
178 | }
|
---|
179 |
|
---|
180 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
181 |
|
---|
182 | QTextDeleteCommand::QTextDeleteCommand( QTextDocument *d, int i, int idx, const QMemArray<QTextStringChar> &str,
|
---|
183 | const QByteArray& oldStyleInfo )
|
---|
184 | : QTextCommand( d ), id( i ), index( idx ), parag( 0 ), text( str ), styleInformation( oldStyleInfo )
|
---|
185 | {
|
---|
186 | for ( int j = 0; j < (int)text.size(); ++j ) {
|
---|
187 | if ( text[ j ].format() )
|
---|
188 | text[ j ].format()->addRef();
|
---|
189 | }
|
---|
190 | }
|
---|
191 |
|
---|
192 | QTextDeleteCommand::QTextDeleteCommand( QTextParagraph *p, int idx, const QMemArray<QTextStringChar> &str )
|
---|
193 | : QTextCommand( 0 ), id( -1 ), index( idx ), parag( p ), text( str )
|
---|
194 | {
|
---|
195 | for ( int i = 0; i < (int)text.size(); ++i ) {
|
---|
196 | if ( text[ i ].format() )
|
---|
197 | text[ i ].format()->addRef();
|
---|
198 | }
|
---|
199 | }
|
---|
200 |
|
---|
201 | QTextDeleteCommand::~QTextDeleteCommand()
|
---|
202 | {
|
---|
203 | for ( int i = 0; i < (int)text.size(); ++i ) {
|
---|
204 | if ( text[ i ].format() )
|
---|
205 | text[ i ].format()->removeRef();
|
---|
206 | }
|
---|
207 | text.resize( 0 );
|
---|
208 | }
|
---|
209 |
|
---|
210 | QTextCursor *QTextDeleteCommand::execute( QTextCursor *c )
|
---|
211 | {
|
---|
212 | QTextParagraph *s = doc ? doc->paragAt( id ) : parag;
|
---|
213 | if ( !s ) {
|
---|
214 | qWarning( "can't locate parag at %d, last parag: %d", id, doc->lastParagraph()->paragId() );
|
---|
215 | return 0;
|
---|
216 | }
|
---|
217 |
|
---|
218 | cursor.setParagraph( s );
|
---|
219 | cursor.setIndex( index );
|
---|
220 | int len = text.size();
|
---|
221 | if ( c )
|
---|
222 | *c = cursor;
|
---|
223 | if ( doc ) {
|
---|
224 | doc->setSelectionStart( QTextDocument::Temp, cursor );
|
---|
225 | for ( int i = 0; i < len; ++i )
|
---|
226 | cursor.gotoNextLetter();
|
---|
227 | doc->setSelectionEnd( QTextDocument::Temp, cursor );
|
---|
228 | doc->removeSelectedText( QTextDocument::Temp, &cursor );
|
---|
229 | if ( c )
|
---|
230 | *c = cursor;
|
---|
231 | } else {
|
---|
232 | s->remove( index, len );
|
---|
233 | }
|
---|
234 |
|
---|
235 | return c;
|
---|
236 | }
|
---|
237 |
|
---|
238 | QTextCursor *QTextDeleteCommand::unexecute( QTextCursor *c )
|
---|
239 | {
|
---|
240 | QTextParagraph *s = doc ? doc->paragAt( id ) : parag;
|
---|
241 | if ( !s ) {
|
---|
242 | qWarning( "can't locate parag at %d, last parag: %d", id, doc->lastParagraph()->paragId() );
|
---|
243 | return 0;
|
---|
244 | }
|
---|
245 |
|
---|
246 | cursor.setParagraph( s );
|
---|
247 | cursor.setIndex( index );
|
---|
248 | QString str = QTextString::toString( text );
|
---|
249 | cursor.insert( str, TRUE, &text );
|
---|
250 | if ( c )
|
---|
251 | *c = cursor;
|
---|
252 | cursor.setParagraph( s );
|
---|
253 | cursor.setIndex( index );
|
---|
254 |
|
---|
255 | #ifndef QT_NO_DATASTREAM
|
---|
256 | if ( !styleInformation.isEmpty() ) {
|
---|
257 | QDataStream styleStream( styleInformation, IO_ReadOnly );
|
---|
258 | int num;
|
---|
259 | styleStream >> num;
|
---|
260 | QTextParagraph *p = s;
|
---|
261 | while ( num-- && p ) {
|
---|
262 | p->readStyleInformation( styleStream );
|
---|
263 | p = p->next();
|
---|
264 | }
|
---|
265 | }
|
---|
266 | #endif
|
---|
267 | s = cursor.paragraph();
|
---|
268 | while ( s ) {
|
---|
269 | s->format();
|
---|
270 | s->setChanged( TRUE );
|
---|
271 | if ( s == c->paragraph() )
|
---|
272 | break;
|
---|
273 | s = s->next();
|
---|
274 | }
|
---|
275 |
|
---|
276 | return &cursor;
|
---|
277 | }
|
---|
278 |
|
---|
279 | QTextFormatCommand::QTextFormatCommand( QTextDocument *d, int sid, int sidx, int eid, int eidx,
|
---|
280 | const QMemArray<QTextStringChar> &old, QTextFormat *f, int fl )
|
---|
281 | : QTextCommand( d ), startId( sid ), startIndex( sidx ), endId( eid ), endIndex( eidx ), format( f ), oldFormats( old ), flags( fl )
|
---|
282 | {
|
---|
283 | format = d->formatCollection()->format( f );
|
---|
284 | for ( int j = 0; j < (int)oldFormats.size(); ++j ) {
|
---|
285 | if ( oldFormats[ j ].format() )
|
---|
286 | oldFormats[ j ].format()->addRef();
|
---|
287 | }
|
---|
288 | }
|
---|
289 |
|
---|
290 | QTextFormatCommand::~QTextFormatCommand()
|
---|
291 | {
|
---|
292 | format->removeRef();
|
---|
293 | for ( int j = 0; j < (int)oldFormats.size(); ++j ) {
|
---|
294 | if ( oldFormats[ j ].format() )
|
---|
295 | oldFormats[ j ].format()->removeRef();
|
---|
296 | }
|
---|
297 | }
|
---|
298 |
|
---|
299 | QTextCursor *QTextFormatCommand::execute( QTextCursor *c )
|
---|
300 | {
|
---|
301 | QTextParagraph *sp = doc->paragAt( startId );
|
---|
302 | QTextParagraph *ep = doc->paragAt( endId );
|
---|
303 | if ( !sp || !ep )
|
---|
304 | return c;
|
---|
305 |
|
---|
306 | QTextCursor start( doc );
|
---|
307 | start.setParagraph( sp );
|
---|
308 | start.setIndex( startIndex );
|
---|
309 | QTextCursor end( doc );
|
---|
310 | end.setParagraph( ep );
|
---|
311 | end.setIndex( endIndex );
|
---|
312 |
|
---|
313 | doc->setSelectionStart( QTextDocument::Temp, start );
|
---|
314 | doc->setSelectionEnd( QTextDocument::Temp, end );
|
---|
315 | doc->setFormat( QTextDocument::Temp, format, flags );
|
---|
316 | doc->removeSelection( QTextDocument::Temp );
|
---|
317 | if ( endIndex == ep->length() )
|
---|
318 | end.gotoLeft();
|
---|
319 | *c = end;
|
---|
320 | return c;
|
---|
321 | }
|
---|
322 |
|
---|
323 | QTextCursor *QTextFormatCommand::unexecute( QTextCursor *c )
|
---|
324 | {
|
---|
325 | QTextParagraph *sp = doc->paragAt( startId );
|
---|
326 | QTextParagraph *ep = doc->paragAt( endId );
|
---|
327 | if ( !sp || !ep )
|
---|
328 | return 0;
|
---|
329 |
|
---|
330 | int idx = startIndex;
|
---|
331 | int fIndex = 0;
|
---|
332 | for ( ;; ) {
|
---|
333 | if ( oldFormats.at( fIndex ).c == '\n' ) {
|
---|
334 | if ( idx > 0 ) {
|
---|
335 | if ( idx < sp->length() && fIndex > 0 )
|
---|
336 | sp->setFormat( idx, 1, oldFormats.at( fIndex - 1 ).format() );
|
---|
337 | if ( sp == ep )
|
---|
338 | break;
|
---|
339 | sp = sp->next();
|
---|
340 | idx = 0;
|
---|
341 | }
|
---|
342 | fIndex++;
|
---|
343 | }
|
---|
344 | if ( oldFormats.at( fIndex ).format() )
|
---|
345 | sp->setFormat( idx, 1, oldFormats.at( fIndex ).format() );
|
---|
346 | idx++;
|
---|
347 | fIndex++;
|
---|
348 | if ( fIndex >= (int)oldFormats.size() )
|
---|
349 | break;
|
---|
350 | if ( idx >= sp->length() ) {
|
---|
351 | if ( sp == ep )
|
---|
352 | break;
|
---|
353 | sp = sp->next();
|
---|
354 | idx = 0;
|
---|
355 | }
|
---|
356 | }
|
---|
357 |
|
---|
358 | QTextCursor end( doc );
|
---|
359 | end.setParagraph( ep );
|
---|
360 | end.setIndex( endIndex );
|
---|
361 | if ( endIndex == ep->length() )
|
---|
362 | end.gotoLeft();
|
---|
363 | *c = end;
|
---|
364 | return c;
|
---|
365 | }
|
---|
366 |
|
---|
367 | QTextStyleCommand::QTextStyleCommand( QTextDocument *d, int fParag, int lParag, const QByteArray& beforeChange )
|
---|
368 | : QTextCommand( d ), firstParag( fParag ), lastParag( lParag ), before( beforeChange )
|
---|
369 | {
|
---|
370 | after = readStyleInformation( d, fParag, lParag );
|
---|
371 | }
|
---|
372 |
|
---|
373 |
|
---|
374 | QByteArray QTextStyleCommand::readStyleInformation( QTextDocument* doc, int fParag, int lParag )
|
---|
375 | {
|
---|
376 | QByteArray style;
|
---|
377 | #ifndef QT_NO_DATASTREAM
|
---|
378 | QTextParagraph *p = doc->paragAt( fParag );
|
---|
379 | if ( !p )
|
---|
380 | return style;
|
---|
381 | QDataStream styleStream( style, IO_WriteOnly );
|
---|
382 | int num = lParag - fParag + 1;
|
---|
383 | styleStream << num;
|
---|
384 | while ( num -- && p ) {
|
---|
385 | p->writeStyleInformation( styleStream );
|
---|
386 | p = p->next();
|
---|
387 | }
|
---|
388 | #endif
|
---|
389 | return style;
|
---|
390 | }
|
---|
391 |
|
---|
392 | void QTextStyleCommand::writeStyleInformation( QTextDocument* doc, int fParag, const QByteArray& style )
|
---|
393 | {
|
---|
394 | #ifndef QT_NO_DATASTREAM
|
---|
395 | QTextParagraph *p = doc->paragAt( fParag );
|
---|
396 | if ( !p )
|
---|
397 | return;
|
---|
398 | QDataStream styleStream( style, IO_ReadOnly );
|
---|
399 | int num;
|
---|
400 | styleStream >> num;
|
---|
401 | while ( num-- && p ) {
|
---|
402 | p->readStyleInformation( styleStream );
|
---|
403 | p = p->next();
|
---|
404 | }
|
---|
405 | #endif
|
---|
406 | }
|
---|
407 |
|
---|
408 | QTextCursor *QTextStyleCommand::execute( QTextCursor *c )
|
---|
409 | {
|
---|
410 | writeStyleInformation( doc, firstParag, after );
|
---|
411 | return c;
|
---|
412 | }
|
---|
413 |
|
---|
414 | QTextCursor *QTextStyleCommand::unexecute( QTextCursor *c )
|
---|
415 | {
|
---|
416 | writeStyleInformation( doc, firstParag, before );
|
---|
417 | return c;
|
---|
418 | }
|
---|
419 |
|
---|
420 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
421 |
|
---|
422 | QTextCursor::QTextCursor( QTextDocument *d )
|
---|
423 | : idx( 0 ), tmpX( -1 ), ox( 0 ), oy( 0 ),
|
---|
424 | valid( TRUE )
|
---|
425 | {
|
---|
426 | para = d ? d->firstParagraph() : 0;
|
---|
427 | }
|
---|
428 |
|
---|
429 | QTextCursor::QTextCursor( const QTextCursor &c )
|
---|
430 | {
|
---|
431 | ox = c.ox;
|
---|
432 | oy = c.oy;
|
---|
433 | idx = c.idx;
|
---|
434 | para = c.para;
|
---|
435 | tmpX = c.tmpX;
|
---|
436 | indices = c.indices;
|
---|
437 | paras = c.paras;
|
---|
438 | xOffsets = c.xOffsets;
|
---|
439 | yOffsets = c.yOffsets;
|
---|
440 | valid = c.valid;
|
---|
441 | }
|
---|
442 |
|
---|
443 | QTextCursor &QTextCursor::operator=( const QTextCursor &c )
|
---|
444 | {
|
---|
445 | ox = c.ox;
|
---|
446 | oy = c.oy;
|
---|
447 | idx = c.idx;
|
---|
448 | para = c.para;
|
---|
449 | tmpX = c.tmpX;
|
---|
450 | indices = c.indices;
|
---|
451 | paras = c.paras;
|
---|
452 | xOffsets = c.xOffsets;
|
---|
453 | yOffsets = c.yOffsets;
|
---|
454 | valid = c.valid;
|
---|
455 |
|
---|
456 | return *this;
|
---|
457 | }
|
---|
458 |
|
---|
459 | bool QTextCursor::operator==( const QTextCursor &c ) const
|
---|
460 | {
|
---|
461 | return para == c.para && idx == c.idx;
|
---|
462 | }
|
---|
463 |
|
---|
464 | int QTextCursor::totalOffsetX() const
|
---|
465 | {
|
---|
466 | int xoff = ox;
|
---|
467 | for ( QValueStack<int>::ConstIterator xit = xOffsets.begin(); xit != xOffsets.end(); ++xit )
|
---|
468 | xoff += *xit;
|
---|
469 | return xoff;
|
---|
470 | }
|
---|
471 |
|
---|
472 | int QTextCursor::totalOffsetY() const
|
---|
473 | {
|
---|
474 | int yoff = oy;
|
---|
475 | for ( QValueStack<int>::ConstIterator yit = yOffsets.begin(); yit != yOffsets.end(); ++yit )
|
---|
476 | yoff += *yit;
|
---|
477 | return yoff;
|
---|
478 | }
|
---|
479 |
|
---|
480 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
481 | void QTextCursor::gotoIntoNested( const QPoint &globalPos )
|
---|
482 | {
|
---|
483 | if ( !para )
|
---|
484 | return;
|
---|
485 | Q_ASSERT( para->at( idx )->isCustom() );
|
---|
486 | push();
|
---|
487 | ox = 0;
|
---|
488 | int bl, y;
|
---|
489 | para->lineHeightOfChar( idx, &bl, &y );
|
---|
490 | oy = y + para->rect().y();
|
---|
491 | ox = para->at( idx )->x;
|
---|
492 | QTextDocument* doc = document();
|
---|
493 | para->at( idx )->customItem()->enterAt( this, doc, para, idx, ox, oy, globalPos-QPoint(ox,oy) );
|
---|
494 | }
|
---|
495 | #endif
|
---|
496 |
|
---|
497 | void QTextCursor::invalidateNested()
|
---|
498 | {
|
---|
499 | if ( nestedDepth() ) {
|
---|
500 | QValueStack<QTextParagraph*>::Iterator it = paras.begin();
|
---|
501 | QValueStack<int>::Iterator it2 = indices.begin();
|
---|
502 | for ( ; it != paras.end(); ++it, ++it2 ) {
|
---|
503 | if ( *it == para )
|
---|
504 | continue;
|
---|
505 | (*it)->invalidate( 0 );
|
---|
506 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
507 | if ( (*it)->at( *it2 )->isCustom() )
|
---|
508 | (*it)->at( *it2 )->customItem()->invalidate();
|
---|
509 | #endif
|
---|
510 | }
|
---|
511 | }
|
---|
512 | }
|
---|
513 |
|
---|
514 | void QTextCursor::insert( const QString &str, bool checkNewLine, QMemArray<QTextStringChar> *formatting )
|
---|
515 | {
|
---|
516 | tmpX = -1;
|
---|
517 | bool justInsert = TRUE;
|
---|
518 | QString s( str );
|
---|
519 | #if defined(Q_WS_WIN)
|
---|
520 | if ( checkNewLine ) {
|
---|
521 | int i = 0;
|
---|
522 | while ( ( i = s.find( '\r', i ) ) != -1 )
|
---|
523 | s.remove( i ,1 );
|
---|
524 | }
|
---|
525 | #endif
|
---|
526 | if ( checkNewLine )
|
---|
527 | justInsert = s.find( '\n' ) == -1;
|
---|
528 | if ( justInsert ) { // we ignore new lines and insert all in the current para at the current index
|
---|
529 | para->insert( idx, s.unicode(), s.length() );
|
---|
530 | if ( formatting ) {
|
---|
531 | for ( int i = 0; i < (int)s.length(); ++i ) {
|
---|
532 | if ( formatting->at( i ).format() ) {
|
---|
533 | formatting->at( i ).format()->addRef();
|
---|
534 | para->string()->setFormat( idx + i, formatting->at( i ).format(), TRUE );
|
---|
535 | }
|
---|
536 | }
|
---|
537 | }
|
---|
538 | idx += s.length();
|
---|
539 | } else { // we split at new lines
|
---|
540 | int start = -1;
|
---|
541 | int end;
|
---|
542 | int y = para->rect().y() + para->rect().height();
|
---|
543 | int lastIndex = 0;
|
---|
544 | do {
|
---|
545 | end = s.find( '\n', start + 1 ); // find line break
|
---|
546 | if ( end == -1 ) // didn't find one, so end of line is end of string
|
---|
547 | end = s.length();
|
---|
548 | int len = (start == -1 ? end : end - start - 1);
|
---|
549 | if ( len > 0 ) // insert the line
|
---|
550 | para->insert( idx, s.unicode() + start + 1, len );
|
---|
551 | else
|
---|
552 | para->invalidate( 0 );
|
---|
553 | if ( formatting ) { // set formats to the chars of the line
|
---|
554 | for ( int i = 0; i < len; ++i ) {
|
---|
555 | if ( formatting->at( i + lastIndex ).format() ) {
|
---|
556 | formatting->at( i + lastIndex ).format()->addRef();
|
---|
557 | para->string()->setFormat( i + idx, formatting->at( i + lastIndex ).format(), TRUE );
|
---|
558 | }
|
---|
559 | }
|
---|
560 | lastIndex += len;
|
---|
561 | }
|
---|
562 | start = end; // next start is at the end of this line
|
---|
563 | idx += len; // increase the index of the cursor to the end of the inserted text
|
---|
564 | if ( s[end] == '\n' ) { // if at the end was a line break, break the line
|
---|
565 | splitAndInsertEmptyParagraph( FALSE, TRUE );
|
---|
566 | para->setEndState( -1 );
|
---|
567 | para->prev()->format( -1, FALSE );
|
---|
568 | lastIndex++;
|
---|
569 | }
|
---|
570 |
|
---|
571 | } while ( end < (int)s.length() );
|
---|
572 |
|
---|
573 | para->format( -1, FALSE );
|
---|
574 | int dy = para->rect().y() + para->rect().height() - y;
|
---|
575 | QTextParagraph *p = para;
|
---|
576 | p->setParagId( p->prev() ? p->prev()->paragId() + 1 : 0 );
|
---|
577 | p = p->next();
|
---|
578 | while ( p ) {
|
---|
579 | p->setParagId( p->prev()->paragId() + 1 );
|
---|
580 | p->move( dy );
|
---|
581 | p->invalidate( 0 );
|
---|
582 | p->setEndState( -1 );
|
---|
583 | p = p->next();
|
---|
584 | }
|
---|
585 | }
|
---|
586 |
|
---|
587 | int h = para->rect().height();
|
---|
588 | para->format( -1, TRUE );
|
---|
589 | if ( h != para->rect().height() )
|
---|
590 | invalidateNested();
|
---|
591 | else if ( para->document() && para->document()->parent() )
|
---|
592 | para->document()->nextDoubleBuffered = TRUE;
|
---|
593 |
|
---|
594 | fixCursorPosition();
|
---|
595 | }
|
---|
596 |
|
---|
597 | void QTextCursor::gotoLeft()
|
---|
598 | {
|
---|
599 | if ( para->string()->isRightToLeft() )
|
---|
600 | gotoNextLetter();
|
---|
601 | else
|
---|
602 | gotoPreviousLetter();
|
---|
603 | }
|
---|
604 |
|
---|
605 | void QTextCursor::gotoPreviousLetter()
|
---|
606 | {
|
---|
607 | tmpX = -1;
|
---|
608 |
|
---|
609 | if ( idx > 0 ) {
|
---|
610 | idx = para->string()->previousCursorPosition( idx );
|
---|
611 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
612 | const QTextStringChar *tsc = para->at( idx );
|
---|
613 | if ( tsc && tsc->isCustom() && tsc->customItem()->isNested() )
|
---|
614 | processNesting( EnterEnd );
|
---|
615 | #endif
|
---|
616 | } else if ( para->prev() ) {
|
---|
617 | para = para->prev();
|
---|
618 | while ( !para->isVisible() && para->prev() )
|
---|
619 | para = para->prev();
|
---|
620 | idx = para->length() - 1;
|
---|
621 | } else if ( nestedDepth() ) {
|
---|
622 | pop();
|
---|
623 | processNesting( Prev );
|
---|
624 | if ( idx == -1 ) {
|
---|
625 | pop();
|
---|
626 | if ( idx > 0 ) {
|
---|
627 | idx = para->string()->previousCursorPosition( idx );
|
---|
628 | } else if ( para->prev() ) {
|
---|
629 | para = para->prev();
|
---|
630 | idx = para->length() - 1;
|
---|
631 | }
|
---|
632 | }
|
---|
633 | }
|
---|
634 | }
|
---|
635 |
|
---|
636 | void QTextCursor::push()
|
---|
637 | {
|
---|
638 | indices.push( idx );
|
---|
639 | paras.push( para );
|
---|
640 | xOffsets.push( ox );
|
---|
641 | yOffsets.push( oy );
|
---|
642 | }
|
---|
643 |
|
---|
644 | void QTextCursor::pop()
|
---|
645 | {
|
---|
646 | if ( indices.isEmpty() )
|
---|
647 | return;
|
---|
648 | idx = indices.pop();
|
---|
649 | para = paras.pop();
|
---|
650 | ox = xOffsets.pop();
|
---|
651 | oy = yOffsets.pop();
|
---|
652 | }
|
---|
653 |
|
---|
654 | void QTextCursor::restoreState()
|
---|
655 | {
|
---|
656 | while ( !indices.isEmpty() )
|
---|
657 | pop();
|
---|
658 | }
|
---|
659 |
|
---|
660 | bool QTextCursor::place( const QPoint &p, QTextParagraph *s, bool link )
|
---|
661 | {
|
---|
662 | QPoint pos( p );
|
---|
663 | QRect r;
|
---|
664 | QTextParagraph *str = s;
|
---|
665 | if ( pos.y() < s->rect().y() ) {
|
---|
666 | pos.setY( s->rect().y() );
|
---|
667 | #ifdef Q_WS_MACX
|
---|
668 | pos.setX( s->rect().x() );
|
---|
669 | #endif
|
---|
670 | }
|
---|
671 | while ( s ) {
|
---|
672 | r = s->rect();
|
---|
673 | r.setWidth( document() ? document()->width() : QWIDGETSIZE_MAX );
|
---|
674 | if ( s->isVisible() )
|
---|
675 | str = s;
|
---|
676 | if ( pos.y() >= r.y() && pos.y() <= r.y() + r.height() )
|
---|
677 | break;
|
---|
678 | if ( !s->next() ) {
|
---|
679 | #ifdef Q_WS_MACX
|
---|
680 | pos.setX( s->rect().x() + s->rect().width() );
|
---|
681 | #endif
|
---|
682 | break;
|
---|
683 | }
|
---|
684 | s = s->next();
|
---|
685 | }
|
---|
686 |
|
---|
687 | if ( !s || !str )
|
---|
688 | return FALSE;
|
---|
689 |
|
---|
690 | s = str;
|
---|
691 |
|
---|
692 | setParagraph( s );
|
---|
693 | int y = s->rect().y();
|
---|
694 | int lines = s->lines();
|
---|
695 | QTextStringChar *chr = 0;
|
---|
696 | int index = 0;
|
---|
697 | int i = 0;
|
---|
698 | int cy = 0;
|
---|
699 | int ch = 0;
|
---|
700 | for ( ; i < lines; ++i ) {
|
---|
701 | chr = s->lineStartOfLine( i, &index );
|
---|
702 | cy = s->lineY( i );
|
---|
703 | ch = s->lineHeight( i );
|
---|
704 | if ( !chr )
|
---|
705 | return FALSE;
|
---|
706 | if ( pos.y() <= y + cy + ch )
|
---|
707 | break;
|
---|
708 | }
|
---|
709 | int nextLine;
|
---|
710 | if ( i < lines - 1 )
|
---|
711 | s->lineStartOfLine( i+1, &nextLine );
|
---|
712 | else
|
---|
713 | nextLine = s->length();
|
---|
714 | i = index;
|
---|
715 | int x = s->rect().x();
|
---|
716 | if ( pos.x() < x )
|
---|
717 | pos.setX( x + 1 );
|
---|
718 | int cw;
|
---|
719 | int curpos = s->length()-1;
|
---|
720 | int dist = 10000000;
|
---|
721 | bool inCustom = FALSE;
|
---|
722 | while ( i < nextLine ) {
|
---|
723 | chr = s->at(i);
|
---|
724 | int cpos = x + chr->x;
|
---|
725 | cw = s->string()->width( i );
|
---|
726 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
727 | if ( chr->isCustom() && chr->customItem()->isNested() ) {
|
---|
728 | if ( pos.x() >= cpos && pos.x() <= cpos + cw &&
|
---|
729 | pos.y() >= y + cy && pos.y() <= y + cy + chr->height() ) {
|
---|
730 | inCustom = TRUE;
|
---|
731 | curpos = i;
|
---|
732 | break;
|
---|
733 | }
|
---|
734 | } else
|
---|
735 | #endif
|
---|
736 | {
|
---|
737 | if( chr->rightToLeft )
|
---|
738 | cpos += cw;
|
---|
739 | int d = cpos - pos.x();
|
---|
740 | bool dm = d < 0 ? !chr->rightToLeft : chr->rightToLeft;
|
---|
741 | if ( (QABS( d ) < dist || (dist == d && dm == TRUE )) && para->string()->validCursorPosition( i ) ) {
|
---|
742 | dist = QABS( d );
|
---|
743 | if ( !link || pos.x() >= x + chr->x )
|
---|
744 | curpos = i;
|
---|
745 | }
|
---|
746 | }
|
---|
747 | i++;
|
---|
748 | }
|
---|
749 | setIndex( curpos );
|
---|
750 |
|
---|
751 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
752 | if ( inCustom && para->document() && para->at( curpos )->isCustom() && para->at( curpos )->customItem()->isNested() ) {
|
---|
753 | QTextDocument *oldDoc = para->document();
|
---|
754 | gotoIntoNested( pos );
|
---|
755 | if ( oldDoc == para->document() )
|
---|
756 | return TRUE;
|
---|
757 | QPoint p( pos.x() - offsetX(), pos.y() - offsetY() );
|
---|
758 | if ( !place( p, document()->firstParagraph(), link ) )
|
---|
759 | pop();
|
---|
760 | }
|
---|
761 | #endif
|
---|
762 | return TRUE;
|
---|
763 | }
|
---|
764 |
|
---|
765 | bool QTextCursor::processNesting( Operation op )
|
---|
766 | {
|
---|
767 | if ( !para->document() )
|
---|
768 | return FALSE;
|
---|
769 | QTextDocument* doc = para->document();
|
---|
770 | push();
|
---|
771 | ox = para->at( idx )->x;
|
---|
772 | int bl, y;
|
---|
773 | para->lineHeightOfChar( idx, &bl, &y );
|
---|
774 | oy = y + para->rect().y();
|
---|
775 | bool ok = FALSE;
|
---|
776 |
|
---|
777 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
778 | switch ( op ) {
|
---|
779 | case EnterBegin:
|
---|
780 | ok = para->at( idx )->customItem()->enter( this, doc, para, idx, ox, oy );
|
---|
781 | break;
|
---|
782 | case EnterEnd:
|
---|
783 | ok = para->at( idx )->customItem()->enter( this, doc, para, idx, ox, oy, TRUE );
|
---|
784 | break;
|
---|
785 | case Next:
|
---|
786 | ok = para->at( idx )->customItem()->next( this, doc, para, idx, ox, oy );
|
---|
787 | break;
|
---|
788 | case Prev:
|
---|
789 | ok = para->at( idx )->customItem()->prev( this, doc, para, idx, ox, oy );
|
---|
790 | break;
|
---|
791 | case Down:
|
---|
792 | ok = para->at( idx )->customItem()->down( this, doc, para, idx, ox, oy );
|
---|
793 | break;
|
---|
794 | case Up:
|
---|
795 | ok = para->at( idx )->customItem()->up( this, doc, para, idx, ox, oy );
|
---|
796 | break;
|
---|
797 | }
|
---|
798 | if ( !ok )
|
---|
799 | #endif
|
---|
800 | pop();
|
---|
801 | return ok;
|
---|
802 | }
|
---|
803 |
|
---|
804 | void QTextCursor::gotoRight()
|
---|
805 | {
|
---|
806 | if ( para->string()->isRightToLeft() )
|
---|
807 | gotoPreviousLetter();
|
---|
808 | else
|
---|
809 | gotoNextLetter();
|
---|
810 | }
|
---|
811 |
|
---|
812 | void QTextCursor::gotoNextLetter()
|
---|
813 | {
|
---|
814 | tmpX = -1;
|
---|
815 |
|
---|
816 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
817 | const QTextStringChar *tsc = para->at( idx );
|
---|
818 | if ( tsc && tsc->isCustom() && tsc->customItem()->isNested() ) {
|
---|
819 | if ( processNesting( EnterBegin ) )
|
---|
820 | return;
|
---|
821 | }
|
---|
822 | #endif
|
---|
823 |
|
---|
824 | if ( idx < para->length() - 1 ) {
|
---|
825 | idx = para->string()->nextCursorPosition( idx );
|
---|
826 | } else if ( para->next() ) {
|
---|
827 | para = para->next();
|
---|
828 | while ( !para->isVisible() && para->next() )
|
---|
829 | para = para->next();
|
---|
830 | idx = 0;
|
---|
831 | } else if ( nestedDepth() ) {
|
---|
832 | pop();
|
---|
833 | processNesting( Next );
|
---|
834 | if ( idx == -1 ) {
|
---|
835 | pop();
|
---|
836 | if ( idx < para->length() - 1 ) {
|
---|
837 | idx = para->string()->nextCursorPosition( idx );
|
---|
838 | } else if ( para->next() ) {
|
---|
839 | para = para->next();
|
---|
840 | idx = 0;
|
---|
841 | }
|
---|
842 | }
|
---|
843 | }
|
---|
844 | }
|
---|
845 |
|
---|
846 | void QTextCursor::gotoUp()
|
---|
847 | {
|
---|
848 | int indexOfLineStart;
|
---|
849 | int line;
|
---|
850 | QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
|
---|
851 | if ( !c )
|
---|
852 | return;
|
---|
853 |
|
---|
854 | if (tmpX < 0)
|
---|
855 | tmpX = x();
|
---|
856 |
|
---|
857 | if ( indexOfLineStart == 0 ) {
|
---|
858 | if ( !para->prev() ) {
|
---|
859 | if ( !nestedDepth() )
|
---|
860 | return;
|
---|
861 | pop();
|
---|
862 | processNesting( Up );
|
---|
863 | if ( idx == -1 ) {
|
---|
864 | pop();
|
---|
865 | if ( !para->prev() )
|
---|
866 | return;
|
---|
867 | idx = tmpX = 0;
|
---|
868 | } else {
|
---|
869 | tmpX = -1;
|
---|
870 | return;
|
---|
871 | }
|
---|
872 | }
|
---|
873 | QTextParagraph *p = para->prev();
|
---|
874 | while ( p && !p->isVisible() )
|
---|
875 | p = p->prev();
|
---|
876 | if ( p )
|
---|
877 | para = p;
|
---|
878 | int lastLine = para->lines() - 1;
|
---|
879 | if ( !para->lineStartOfLine( lastLine, &indexOfLineStart ) )
|
---|
880 | return;
|
---|
881 | idx = indexOfLineStart;
|
---|
882 | while (idx < para->length()-1 && para->at(idx)->x < tmpX)
|
---|
883 | ++idx;
|
---|
884 | if (idx > indexOfLineStart &&
|
---|
885 | para->at(idx)->x - tmpX > tmpX - para->at(idx-1)->x)
|
---|
886 | --idx;
|
---|
887 | } else {
|
---|
888 | --line;
|
---|
889 | int oldIndexOfLineStart = indexOfLineStart;
|
---|
890 | if ( !para->lineStartOfLine( line, &indexOfLineStart ) )
|
---|
891 | return;
|
---|
892 | idx = indexOfLineStart;
|
---|
893 | while (idx < oldIndexOfLineStart-1 && para->at(idx)->x < tmpX)
|
---|
894 | ++idx;
|
---|
895 | if (idx > indexOfLineStart &&
|
---|
896 | para->at(idx)->x - tmpX > tmpX - para->at(idx-1)->x)
|
---|
897 | --idx;
|
---|
898 | }
|
---|
899 | fixCursorPosition();
|
---|
900 | }
|
---|
901 |
|
---|
902 | void QTextCursor::gotoDown()
|
---|
903 | {
|
---|
904 | int indexOfLineStart;
|
---|
905 | int line;
|
---|
906 | QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
|
---|
907 | if ( !c )
|
---|
908 | return;
|
---|
909 |
|
---|
910 | if (tmpX < 0)
|
---|
911 | tmpX = x();
|
---|
912 | if ( line == para->lines() - 1 ) {
|
---|
913 | if ( !para->next() ) {
|
---|
914 | if ( !nestedDepth() )
|
---|
915 | return;
|
---|
916 | pop();
|
---|
917 | processNesting( Down );
|
---|
918 | if ( idx == -1 ) {
|
---|
919 | pop();
|
---|
920 | if ( !para->next() )
|
---|
921 | return;
|
---|
922 | idx = tmpX = 0;
|
---|
923 | } else {
|
---|
924 | tmpX = -1;
|
---|
925 | return;
|
---|
926 | }
|
---|
927 | }
|
---|
928 | QTextParagraph *s = para->next();
|
---|
929 | while ( s && !s->isVisible() )
|
---|
930 | s = s->next();
|
---|
931 | if ( s )
|
---|
932 | para = s;
|
---|
933 | if ( !para->lineStartOfLine( 0, &indexOfLineStart ) )
|
---|
934 | return;
|
---|
935 | int end;
|
---|
936 | if ( para->lines() == 1 )
|
---|
937 | end = para->length();
|
---|
938 | else
|
---|
939 | para->lineStartOfLine( 1, &end );
|
---|
940 |
|
---|
941 | idx = indexOfLineStart;
|
---|
942 | while (idx < end-1 && para->at(idx)->x < tmpX)
|
---|
943 | ++idx;
|
---|
944 | if (idx > indexOfLineStart &&
|
---|
945 | para->at(idx)->x - tmpX > tmpX - para->at(idx-1)->x)
|
---|
946 | --idx;
|
---|
947 | } else {
|
---|
948 | ++line;
|
---|
949 | int end;
|
---|
950 | if ( line == para->lines() - 1 )
|
---|
951 | end = para->length();
|
---|
952 | else
|
---|
953 | para->lineStartOfLine( line + 1, &end );
|
---|
954 | if ( !para->lineStartOfLine( line, &indexOfLineStart ) )
|
---|
955 | return;
|
---|
956 | idx = indexOfLineStart;
|
---|
957 | while (idx < end-1 && para->at(idx)->x < tmpX)
|
---|
958 | ++idx;
|
---|
959 | if (idx > indexOfLineStart &&
|
---|
960 | para->at(idx)->x - tmpX > tmpX - para->at(idx-1)->x)
|
---|
961 | --idx;
|
---|
962 | }
|
---|
963 | fixCursorPosition();
|
---|
964 | }
|
---|
965 |
|
---|
966 | void QTextCursor::gotoLineEnd()
|
---|
967 | {
|
---|
968 | tmpX = -1;
|
---|
969 | int indexOfLineStart;
|
---|
970 | int line;
|
---|
971 | QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
|
---|
972 | if ( !c )
|
---|
973 | return;
|
---|
974 |
|
---|
975 | if ( line == para->lines() - 1 ) {
|
---|
976 | idx = para->length() - 1;
|
---|
977 | } else {
|
---|
978 | c = para->lineStartOfLine( ++line, &indexOfLineStart );
|
---|
979 | indexOfLineStart--;
|
---|
980 | idx = indexOfLineStart;
|
---|
981 | }
|
---|
982 | }
|
---|
983 |
|
---|
984 | void QTextCursor::gotoLineStart()
|
---|
985 | {
|
---|
986 | tmpX = -1;
|
---|
987 | int indexOfLineStart;
|
---|
988 | int line;
|
---|
989 | QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
|
---|
990 | if ( !c )
|
---|
991 | return;
|
---|
992 |
|
---|
993 | idx = indexOfLineStart;
|
---|
994 | }
|
---|
995 |
|
---|
996 | void QTextCursor::gotoHome()
|
---|
997 | {
|
---|
998 | if ( topParagraph()->document() )
|
---|
999 | gotoPosition( topParagraph()->document()->firstParagraph() );
|
---|
1000 | else
|
---|
1001 | gotoLineStart();
|
---|
1002 | }
|
---|
1003 |
|
---|
1004 | void QTextCursor::gotoEnd()
|
---|
1005 | {
|
---|
1006 | if ( topParagraph()->document() && topParagraph()->document()->lastParagraph()->isValid() )
|
---|
1007 | gotoPosition( topParagraph()->document()->lastParagraph(),
|
---|
1008 | topParagraph()->document()->lastParagraph()->length() - 1);
|
---|
1009 | else
|
---|
1010 | gotoLineEnd();
|
---|
1011 | }
|
---|
1012 |
|
---|
1013 | void QTextCursor::gotoPageUp( int visibleHeight )
|
---|
1014 | {
|
---|
1015 | int targetY = globalY() - visibleHeight;
|
---|
1016 | QTextParagraph* old; int index;
|
---|
1017 | do {
|
---|
1018 | old = para; index = idx;
|
---|
1019 | gotoUp();
|
---|
1020 | } while ( (old != para || index != idx) && globalY() > targetY );
|
---|
1021 | }
|
---|
1022 |
|
---|
1023 | void QTextCursor::gotoPageDown( int visibleHeight )
|
---|
1024 | {
|
---|
1025 | int targetY = globalY() + visibleHeight;
|
---|
1026 | QTextParagraph* old; int index;
|
---|
1027 | do {
|
---|
1028 | old = para; index = idx;
|
---|
1029 | gotoDown();
|
---|
1030 | } while ( (old != para || index != idx) && globalY() < targetY );
|
---|
1031 | }
|
---|
1032 |
|
---|
1033 | void QTextCursor::gotoWordRight()
|
---|
1034 | {
|
---|
1035 | if ( para->string()->isRightToLeft() )
|
---|
1036 | gotoPreviousWord();
|
---|
1037 | else
|
---|
1038 | gotoNextWord();
|
---|
1039 | }
|
---|
1040 |
|
---|
1041 | void QTextCursor::gotoWordLeft()
|
---|
1042 | {
|
---|
1043 | if ( para->string()->isRightToLeft() )
|
---|
1044 | gotoNextWord();
|
---|
1045 | else
|
---|
1046 | gotoPreviousWord();
|
---|
1047 | }
|
---|
1048 |
|
---|
1049 | static bool is_seperator( const QChar &c, bool onlySpace )
|
---|
1050 | {
|
---|
1051 | if ( onlySpace )
|
---|
1052 | return c.isSpace();
|
---|
1053 | return c.isSpace() ||
|
---|
1054 | c == '\t' ||
|
---|
1055 | c == '.' ||
|
---|
1056 | c == ',' ||
|
---|
1057 | c == ':' ||
|
---|
1058 | c == ';' ||
|
---|
1059 | c == '-' ||
|
---|
1060 | c == '<' ||
|
---|
1061 | c == '>' ||
|
---|
1062 | c == '[' ||
|
---|
1063 | c == ']' ||
|
---|
1064 | c == '(' ||
|
---|
1065 | c == ')' ||
|
---|
1066 | c == '{' ||
|
---|
1067 | c == '}';
|
---|
1068 | }
|
---|
1069 |
|
---|
1070 | void QTextCursor::gotoPreviousWord( bool onlySpace )
|
---|
1071 | {
|
---|
1072 | gotoPreviousLetter();
|
---|
1073 | tmpX = -1;
|
---|
1074 | QTextString *s = para->string();
|
---|
1075 | bool allowSame = FALSE;
|
---|
1076 | if ( idx == ((int)s->length()-1) )
|
---|
1077 | return;
|
---|
1078 | for ( int i = idx; i >= 0; --i ) {
|
---|
1079 | if ( is_seperator( s->at( i ).c, onlySpace ) ) {
|
---|
1080 | if ( !allowSame )
|
---|
1081 | continue;
|
---|
1082 | idx = i + 1;
|
---|
1083 | return;
|
---|
1084 | }
|
---|
1085 | if ( !allowSame && !is_seperator( s->at( i ).c, onlySpace ) )
|
---|
1086 | allowSame = TRUE;
|
---|
1087 | }
|
---|
1088 | idx = 0;
|
---|
1089 | }
|
---|
1090 |
|
---|
1091 | void QTextCursor::gotoNextWord( bool onlySpace )
|
---|
1092 | {
|
---|
1093 | tmpX = -1;
|
---|
1094 | QTextString *s = para->string();
|
---|
1095 | bool allowSame = FALSE;
|
---|
1096 | for ( int i = idx; i < (int)s->length(); ++i ) {
|
---|
1097 | if ( !is_seperator( s->at( i ).c, onlySpace ) ) {
|
---|
1098 | if ( !allowSame )
|
---|
1099 | continue;
|
---|
1100 | idx = i;
|
---|
1101 | return;
|
---|
1102 | }
|
---|
1103 | if ( !allowSame && is_seperator( s->at( i ).c, onlySpace ) )
|
---|
1104 | allowSame = TRUE;
|
---|
1105 |
|
---|
1106 | }
|
---|
1107 |
|
---|
1108 | if ( idx < ((int)s->length()-1) ) {
|
---|
1109 | gotoLineEnd();
|
---|
1110 | } else if ( para->next() ) {
|
---|
1111 | QTextParagraph *p = para->next();
|
---|
1112 | while ( p && !p->isVisible() )
|
---|
1113 | p = p->next();
|
---|
1114 | if ( s ) {
|
---|
1115 | para = p;
|
---|
1116 | idx = 0;
|
---|
1117 | }
|
---|
1118 | } else {
|
---|
1119 | gotoLineEnd();
|
---|
1120 | }
|
---|
1121 | }
|
---|
1122 |
|
---|
1123 | bool QTextCursor::atParagStart()
|
---|
1124 | {
|
---|
1125 | return idx == 0;
|
---|
1126 | }
|
---|
1127 |
|
---|
1128 | bool QTextCursor::atParagEnd()
|
---|
1129 | {
|
---|
1130 | return idx == para->length() - 1;
|
---|
1131 | }
|
---|
1132 |
|
---|
1133 | void QTextCursor::splitAndInsertEmptyParagraph( bool ind, bool updateIds )
|
---|
1134 | {
|
---|
1135 | if ( !para->document() )
|
---|
1136 | return;
|
---|
1137 | tmpX = -1;
|
---|
1138 | QTextFormat *f = 0;
|
---|
1139 | if ( para->document()->useFormatCollection() ) {
|
---|
1140 | f = para->at( idx )->format();
|
---|
1141 | if ( idx == para->length() - 1 && idx > 0 )
|
---|
1142 | f = para->at( idx - 1 )->format();
|
---|
1143 | if ( f->isMisspelled() ) {
|
---|
1144 | f->removeRef();
|
---|
1145 | f = para->document()->formatCollection()->format( f->font(), f->color() );
|
---|
1146 | }
|
---|
1147 | }
|
---|
1148 |
|
---|
1149 | if ( atParagEnd() ) {
|
---|
1150 | QTextParagraph *n = para->next();
|
---|
1151 | QTextParagraph *s = para->document()->createParagraph( para->document(), para, n, updateIds );
|
---|
1152 | if ( f )
|
---|
1153 | s->setFormat( 0, 1, f, TRUE );
|
---|
1154 | s->copyParagData( para );
|
---|
1155 | if ( ind ) {
|
---|
1156 | int oi, ni;
|
---|
1157 | s->indent( &oi, &ni );
|
---|
1158 | para = s;
|
---|
1159 | idx = ni;
|
---|
1160 | } else {
|
---|
1161 | para = s;
|
---|
1162 | idx = 0;
|
---|
1163 | }
|
---|
1164 | } else if ( atParagStart() ) {
|
---|
1165 | QTextParagraph *p = para->prev();
|
---|
1166 | QTextParagraph *s = para->document()->createParagraph( para->document(), p, para, updateIds );
|
---|
1167 | if ( f )
|
---|
1168 | s->setFormat( 0, 1, f, TRUE );
|
---|
1169 | s->copyParagData( para );
|
---|
1170 | if ( ind ) {
|
---|
1171 | s->indent();
|
---|
1172 | s->format();
|
---|
1173 | indent();
|
---|
1174 | para->format();
|
---|
1175 | }
|
---|
1176 | } else {
|
---|
1177 | QString str = para->string()->toString().mid( idx, 0xFFFFFF );
|
---|
1178 | QTextParagraph *n = para->next();
|
---|
1179 | QTextParagraph *s = para->document()->createParagraph( para->document(), para, n, updateIds );
|
---|
1180 | s->copyParagData( para );
|
---|
1181 | s->remove( 0, 1 );
|
---|
1182 | s->append( str, TRUE );
|
---|
1183 | for ( uint i = 0; i < str.length(); ++i ) {
|
---|
1184 | QTextStringChar* tsc = para->at( idx + i );
|
---|
1185 | s->setFormat( i, 1, tsc->format(), TRUE );
|
---|
1186 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
1187 | if ( tsc->isCustom() ) {
|
---|
1188 | QTextCustomItem * item = tsc->customItem();
|
---|
1189 | s->at( i )->setCustomItem( item );
|
---|
1190 | tsc->loseCustomItem();
|
---|
1191 | }
|
---|
1192 | #endif
|
---|
1193 | if ( tsc->isAnchor() )
|
---|
1194 | s->at( i )->setAnchor( tsc->anchorName(),
|
---|
1195 | tsc->anchorHref() );
|
---|
1196 | }
|
---|
1197 | para->truncate( idx );
|
---|
1198 | if ( ind ) {
|
---|
1199 | int oi, ni;
|
---|
1200 | s->indent( &oi, &ni );
|
---|
1201 | para = s;
|
---|
1202 | idx = ni;
|
---|
1203 | } else {
|
---|
1204 | para = s;
|
---|
1205 | idx = 0;
|
---|
1206 | }
|
---|
1207 | }
|
---|
1208 |
|
---|
1209 | invalidateNested();
|
---|
1210 | }
|
---|
1211 |
|
---|
1212 | bool QTextCursor::remove()
|
---|
1213 | {
|
---|
1214 | tmpX = -1;
|
---|
1215 | if ( !atParagEnd() ) {
|
---|
1216 | int next = para->string()->nextCursorPosition( idx );
|
---|
1217 | para->remove( idx, next-idx );
|
---|
1218 | int h = para->rect().height();
|
---|
1219 | para->format( -1, TRUE );
|
---|
1220 | if ( h != para->rect().height() )
|
---|
1221 | invalidateNested();
|
---|
1222 | else if ( para->document() && para->document()->parent() )
|
---|
1223 | para->document()->nextDoubleBuffered = TRUE;
|
---|
1224 | return FALSE;
|
---|
1225 | } else if ( para->next() ) {
|
---|
1226 | para->join( para->next() );
|
---|
1227 | invalidateNested();
|
---|
1228 | return TRUE;
|
---|
1229 | }
|
---|
1230 | return FALSE;
|
---|
1231 | }
|
---|
1232 |
|
---|
1233 | /* needed to implement backspace the correct way */
|
---|
1234 | bool QTextCursor::removePreviousChar()
|
---|
1235 | {
|
---|
1236 | tmpX = -1;
|
---|
1237 | if ( !atParagStart() ) {
|
---|
1238 | para->remove( idx-1, 1 );
|
---|
1239 | int h = para->rect().height();
|
---|
1240 | idx--;
|
---|
1241 | // shouldn't be needed, just to make sure.
|
---|
1242 | fixCursorPosition();
|
---|
1243 | para->format( -1, TRUE );
|
---|
1244 | if ( h != para->rect().height() )
|
---|
1245 | invalidateNested();
|
---|
1246 | else if ( para->document() && para->document()->parent() )
|
---|
1247 | para->document()->nextDoubleBuffered = TRUE;
|
---|
1248 | return FALSE;
|
---|
1249 | } else if ( para->prev() ) {
|
---|
1250 | para = para->prev();
|
---|
1251 | para->join( para->next() );
|
---|
1252 | invalidateNested();
|
---|
1253 | return TRUE;
|
---|
1254 | }
|
---|
1255 | return FALSE;
|
---|
1256 | }
|
---|
1257 |
|
---|
1258 | void QTextCursor::indent()
|
---|
1259 | {
|
---|
1260 | int oi = 0, ni = 0;
|
---|
1261 | para->indent( &oi, &ni );
|
---|
1262 | if ( oi == ni )
|
---|
1263 | return;
|
---|
1264 |
|
---|
1265 | if ( idx >= oi )
|
---|
1266 | idx += ni - oi;
|
---|
1267 | else
|
---|
1268 | idx = ni;
|
---|
1269 | }
|
---|
1270 |
|
---|
1271 | void QTextCursor::fixCursorPosition()
|
---|
1272 | {
|
---|
1273 | // searches for the closest valid cursor position
|
---|
1274 | if ( para->string()->validCursorPosition( idx ) )
|
---|
1275 | return;
|
---|
1276 |
|
---|
1277 | int lineIdx;
|
---|
1278 | QTextStringChar *start = para->lineStartOfChar( idx, &lineIdx, 0 );
|
---|
1279 | int x = para->string()->at( idx ).x;
|
---|
1280 | int diff = QABS(start->x - x);
|
---|
1281 | int best = lineIdx;
|
---|
1282 |
|
---|
1283 | QTextStringChar *c = start;
|
---|
1284 | ++c;
|
---|
1285 |
|
---|
1286 | QTextStringChar *end = ¶->string()->at( para->length()-1 );
|
---|
1287 | while ( c <= end && !c->lineStart ) {
|
---|
1288 | int xp = c->x;
|
---|
1289 | if ( c->rightToLeft )
|
---|
1290 | xp += para->string()->width( lineIdx + (c-start) );
|
---|
1291 | int ndiff = QABS(xp - x);
|
---|
1292 | if ( ndiff < diff && para->string()->validCursorPosition(lineIdx + (c-start)) ) {
|
---|
1293 | diff = ndiff;
|
---|
1294 | best = lineIdx + (c-start);
|
---|
1295 | }
|
---|
1296 | ++c;
|
---|
1297 | }
|
---|
1298 | idx = best;
|
---|
1299 | }
|
---|
1300 |
|
---|
1301 |
|
---|
1302 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
1303 |
|
---|
1304 | QTextDocument::QTextDocument( QTextDocument *p )
|
---|
1305 | : par( p ), parentPar( 0 )
|
---|
1306 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
1307 | , tc( 0 )
|
---|
1308 | #endif
|
---|
1309 | , tArray( 0 ), tStopWidth( 0 )
|
---|
1310 | {
|
---|
1311 | fCollection = new QTextFormatCollection;
|
---|
1312 | init();
|
---|
1313 | }
|
---|
1314 |
|
---|
1315 | QTextDocument::QTextDocument( QTextDocument *p, QTextFormatCollection *f )
|
---|
1316 | : par( p ), parentPar( 0 )
|
---|
1317 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
1318 | , tc( 0 )
|
---|
1319 | #endif
|
---|
1320 | , tArray( 0 ), tStopWidth( 0 )
|
---|
1321 | {
|
---|
1322 | fCollection = f;
|
---|
1323 | init();
|
---|
1324 | }
|
---|
1325 |
|
---|
1326 | void QTextDocument::init()
|
---|
1327 | {
|
---|
1328 | oTextValid = TRUE;
|
---|
1329 | mightHaveCustomItems = FALSE;
|
---|
1330 | if ( par )
|
---|
1331 | par->insertChild( this );
|
---|
1332 | pProcessor = 0;
|
---|
1333 | useFC = TRUE;
|
---|
1334 | pFormatter = 0;
|
---|
1335 | indenter = 0;
|
---|
1336 | fParag = 0;
|
---|
1337 | txtFormat = Qt::AutoText;
|
---|
1338 | preferRichText = FALSE;
|
---|
1339 | pages = FALSE;
|
---|
1340 | focusIndicator.parag = 0;
|
---|
1341 | minw = 0;
|
---|
1342 | wused = 0;
|
---|
1343 | minwParag = curParag = 0;
|
---|
1344 | align = AlignAuto;
|
---|
1345 | nSelections = 1;
|
---|
1346 |
|
---|
1347 | setStyleSheet( QStyleSheet::defaultSheet() );
|
---|
1348 | #ifndef QT_NO_MIME
|
---|
1349 | factory_ = QMimeSourceFactory::defaultFactory();
|
---|
1350 | #endif
|
---|
1351 | contxt = QString::null;
|
---|
1352 |
|
---|
1353 | underlLinks = par ? par->underlLinks : TRUE;
|
---|
1354 | backBrush = 0;
|
---|
1355 | buf_pixmap = 0;
|
---|
1356 | nextDoubleBuffered = FALSE;
|
---|
1357 |
|
---|
1358 | if ( par )
|
---|
1359 | withoutDoubleBuffer = par->withoutDoubleBuffer;
|
---|
1360 | else
|
---|
1361 | withoutDoubleBuffer = FALSE;
|
---|
1362 |
|
---|
1363 | lParag = fParag = createParagraph( this, 0, 0 );
|
---|
1364 |
|
---|
1365 | cx = 0;
|
---|
1366 | cy = 2;
|
---|
1367 | if ( par )
|
---|
1368 | cx = cy = 0;
|
---|
1369 | cw = 600;
|
---|
1370 | vw = 0;
|
---|
1371 | flow_ = new QTextFlow;
|
---|
1372 | flow_->setWidth( cw );
|
---|
1373 |
|
---|
1374 | leftmargin = rightmargin = 4;
|
---|
1375 | scaleFontsFactor = 1;
|
---|
1376 |
|
---|
1377 |
|
---|
1378 | selectionColors[ Standard ] = QApplication::palette().color( QPalette::Active, QColorGroup::Highlight );
|
---|
1379 | selectionText[ Standard ] = TRUE;
|
---|
1380 | selectionText[ IMSelectionText ] = TRUE;
|
---|
1381 | selectionText[ IMCompositionText ] = FALSE;
|
---|
1382 | commandHistory = new QTextCommandHistory( 100 );
|
---|
1383 | tStopWidth = formatCollection()->defaultFormat()->width( 'x' ) * 8;
|
---|
1384 | }
|
---|
1385 |
|
---|
1386 | QTextDocument::~QTextDocument()
|
---|
1387 | {
|
---|
1388 | delete commandHistory;
|
---|
1389 | if ( par )
|
---|
1390 | par->removeChild( this );
|
---|
1391 | clear();
|
---|
1392 | delete flow_;
|
---|
1393 | if ( !par )
|
---|
1394 | delete pFormatter;
|
---|
1395 | delete fCollection;
|
---|
1396 | delete pProcessor;
|
---|
1397 | delete buf_pixmap;
|
---|
1398 | delete indenter;
|
---|
1399 | delete backBrush;
|
---|
1400 | delete [] tArray;
|
---|
1401 | }
|
---|
1402 |
|
---|
1403 | void QTextDocument::clear( bool createEmptyParag )
|
---|
1404 | {
|
---|
1405 | while ( fParag ) {
|
---|
1406 | QTextParagraph *p = fParag->next();
|
---|
1407 | delete fParag;
|
---|
1408 | fParag = p;
|
---|
1409 | }
|
---|
1410 | if ( flow_ )
|
---|
1411 | flow_->clear();
|
---|
1412 | fParag = lParag = 0;
|
---|
1413 | if ( createEmptyParag )
|
---|
1414 | fParag = lParag = createParagraph( this );
|
---|
1415 | selections.clear();
|
---|
1416 | oText = QString::null;
|
---|
1417 | oTextValid = FALSE;
|
---|
1418 | }
|
---|
1419 |
|
---|
1420 | int QTextDocument::widthUsed() const
|
---|
1421 | {
|
---|
1422 | return wused + 2*border_tolerance;
|
---|
1423 | }
|
---|
1424 |
|
---|
1425 | int QTextDocument::height() const
|
---|
1426 | {
|
---|
1427 | int h = 0;
|
---|
1428 | if ( lParag )
|
---|
1429 | h = lParag->rect().top() + lParag->rect().height() + 1;
|
---|
1430 | int fh = flow_->boundingRect().bottom();
|
---|
1431 | return QMAX( h, fh );
|
---|
1432 | }
|
---|
1433 |
|
---|
1434 |
|
---|
1435 |
|
---|
1436 | QTextParagraph *QTextDocument::createParagraph( QTextDocument *d, QTextParagraph *pr, QTextParagraph *nx, bool updateIds )
|
---|
1437 | {
|
---|
1438 | return new QTextParagraph( d, pr, nx, updateIds );
|
---|
1439 | }
|
---|
1440 |
|
---|
1441 | bool QTextDocument::setMinimumWidth( int needed, int used, QTextParagraph *p )
|
---|
1442 | {
|
---|
1443 | if ( needed == -1 ) {
|
---|
1444 | minw = 0;
|
---|
1445 | wused = 0;
|
---|
1446 | p = 0;
|
---|
1447 | }
|
---|
1448 | if ( p == minwParag ) {
|
---|
1449 | if (minw > needed) {
|
---|
1450 | QTextParagraph *tp = fParag;
|
---|
1451 | while (tp) {
|
---|
1452 | if (tp != p && tp->minwidth > needed) {
|
---|
1453 | needed = tp->minwidth;
|
---|
1454 | minwParag = tp;
|
---|
1455 | }
|
---|
1456 | tp = tp->n;
|
---|
1457 | }
|
---|
1458 | }
|
---|
1459 | minw = needed;
|
---|
1460 | emit minimumWidthChanged( minw );
|
---|
1461 | } else if ( needed > minw ) {
|
---|
1462 | minw = needed;
|
---|
1463 | minwParag = p;
|
---|
1464 | emit minimumWidthChanged( minw );
|
---|
1465 | }
|
---|
1466 | wused = QMAX( wused, used );
|
---|
1467 | wused = QMAX( wused, minw );
|
---|
1468 | cw = QMAX( minw, cw );
|
---|
1469 | return TRUE;
|
---|
1470 | }
|
---|
1471 |
|
---|
1472 | void QTextDocument::setPlainText( const QString &text )
|
---|
1473 | {
|
---|
1474 | preferRichText = FALSE;
|
---|
1475 | clear();
|
---|
1476 | oTextValid = TRUE;
|
---|
1477 | oText = text;
|
---|
1478 |
|
---|
1479 | int lastNl = 0;
|
---|
1480 | int nl = text.find( '\n' );
|
---|
1481 | if ( nl == -1 ) {
|
---|
1482 | lParag = createParagraph( this, lParag, 0 );
|
---|
1483 | if ( !fParag )
|
---|
1484 | fParag = lParag;
|
---|
1485 | QString s = text;
|
---|
1486 | if ( !s.isEmpty() ) {
|
---|
1487 | if ( s[ (int)s.length() - 1 ] == '\r' )
|
---|
1488 | s.remove( s.length() - 1, 1 );
|
---|
1489 | lParag->append( s );
|
---|
1490 | }
|
---|
1491 | } else {
|
---|
1492 | for (;;) {
|
---|
1493 | lParag = createParagraph( this, lParag, 0 );
|
---|
1494 | if ( !fParag )
|
---|
1495 | fParag = lParag;
|
---|
1496 | int l = nl - lastNl;
|
---|
1497 | if ( l > 0 ) {
|
---|
1498 | if (text.unicode()[nl-1] == '\r')
|
---|
1499 | l--;
|
---|
1500 | QConstString cs(text.unicode()+lastNl, l);
|
---|
1501 | lParag->append( cs.string() );
|
---|
1502 | }
|
---|
1503 | if ( nl == (int)text.length() )
|
---|
1504 | break;
|
---|
1505 | lastNl = nl + 1;
|
---|
1506 | nl = text.find( '\n', nl + 1 );
|
---|
1507 | if ( nl == -1 )
|
---|
1508 | nl = text.length();
|
---|
1509 | }
|
---|
1510 | }
|
---|
1511 | if ( !lParag )
|
---|
1512 | lParag = fParag = createParagraph( this, 0, 0 );
|
---|
1513 | }
|
---|
1514 |
|
---|
1515 | struct Q_EXPORT QTextDocumentTag {
|
---|
1516 | QTextDocumentTag(){}
|
---|
1517 | QTextDocumentTag( const QString&n, const QStyleSheetItem* s, const QTextFormat& f )
|
---|
1518 | :name(n),style(s), format(f), alignment(Qt::AlignAuto), direction(QChar::DirON),liststyle(QStyleSheetItem::ListDisc) {
|
---|
1519 | wsm = QStyleSheetItem::WhiteSpaceNormal;
|
---|
1520 | }
|
---|
1521 | QString name;
|
---|
1522 | const QStyleSheetItem* style;
|
---|
1523 | QString anchorHref;
|
---|
1524 | QStyleSheetItem::WhiteSpaceMode wsm;
|
---|
1525 | QTextFormat format;
|
---|
1526 | int alignment : 16;
|
---|
1527 | int direction : 5;
|
---|
1528 | QStyleSheetItem::ListStyle liststyle;
|
---|
1529 |
|
---|
1530 | QTextDocumentTag( const QTextDocumentTag& t ) {
|
---|
1531 | name = t.name;
|
---|
1532 | style = t.style;
|
---|
1533 | anchorHref = t.anchorHref;
|
---|
1534 | wsm = t.wsm;
|
---|
1535 | format = t.format;
|
---|
1536 | alignment = t.alignment;
|
---|
1537 | direction = t.direction;
|
---|
1538 | liststyle = t.liststyle;
|
---|
1539 | }
|
---|
1540 | QTextDocumentTag& operator=(const QTextDocumentTag& t) {
|
---|
1541 | name = t.name;
|
---|
1542 | style = t.style;
|
---|
1543 | anchorHref = t.anchorHref;
|
---|
1544 | wsm = t.wsm;
|
---|
1545 | format = t.format;
|
---|
1546 | alignment = t.alignment;
|
---|
1547 | direction = t.direction;
|
---|
1548 | liststyle = t.liststyle;
|
---|
1549 | return *this;
|
---|
1550 | }
|
---|
1551 |
|
---|
1552 | Q_DUMMY_COMPARISON_OPERATOR(QTextDocumentTag)
|
---|
1553 | };
|
---|
1554 |
|
---|
1555 |
|
---|
1556 | #define NEWPAR do{ if ( !hasNewPar) { \
|
---|
1557 | if ( !textEditMode && curpar && curpar->length()>1 && curpar->at( curpar->length()-2)->c == QChar_linesep ) \
|
---|
1558 | curpar->remove( curpar->length()-2, 1 ); \
|
---|
1559 | curpar = createParagraph( this, curpar, curpar->next() ); styles.append( vec ); vec = 0;} \
|
---|
1560 | hasNewPar = TRUE; \
|
---|
1561 | curpar->rtext = TRUE; \
|
---|
1562 | curpar->align = curtag.alignment; \
|
---|
1563 | curpar->lstyle = curtag.liststyle; \
|
---|
1564 | curpar->litem = ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ); \
|
---|
1565 | curpar->str->setDirection( (QChar::Direction)curtag.direction ); \
|
---|
1566 | space = TRUE; \
|
---|
1567 | tabExpansionColumn = 0; \
|
---|
1568 | delete vec; vec = new QPtrVector<QStyleSheetItem>( (uint)tags.count() + 1); \
|
---|
1569 | int i = 0; \
|
---|
1570 | for ( QValueStack<QTextDocumentTag>::Iterator it = tags.begin(); it != tags.end(); ++it ) \
|
---|
1571 | vec->insert( i++, (*it).style ); \
|
---|
1572 | vec->insert( i, curtag.style ); \
|
---|
1573 | }while(FALSE);
|
---|
1574 |
|
---|
1575 |
|
---|
1576 | void QTextDocument::setRichText( const QString &text, const QString &context )
|
---|
1577 | {
|
---|
1578 | preferRichText = TRUE;
|
---|
1579 | if ( !context.isEmpty() )
|
---|
1580 | setContext( context );
|
---|
1581 | clear();
|
---|
1582 | fParag = lParag = createParagraph( this );
|
---|
1583 | oTextValid = TRUE;
|
---|
1584 | oText = text;
|
---|
1585 | setRichTextInternal( text );
|
---|
1586 | fParag->rtext = TRUE;
|
---|
1587 | }
|
---|
1588 |
|
---|
1589 | void QTextDocument::setRichTextInternal( const QString &text, QTextCursor* cursor )
|
---|
1590 | {
|
---|
1591 | QTextParagraph* curpar = lParag;
|
---|
1592 | int pos = 0;
|
---|
1593 | QValueStack<QTextDocumentTag> tags;
|
---|
1594 | QTextDocumentTag initag( "", sheet_->item(""), *formatCollection()->defaultFormat() );
|
---|
1595 | if ( bodyText.isValid() )
|
---|
1596 | initag.format.setColor( bodyText );
|
---|
1597 | QTextDocumentTag curtag = initag;
|
---|
1598 | bool space = TRUE;
|
---|
1599 | bool canMergeLi = FALSE;
|
---|
1600 |
|
---|
1601 | bool textEditMode = FALSE;
|
---|
1602 | int tabExpansionColumn = 0;
|
---|
1603 |
|
---|
1604 | const QChar* doc = text.unicode();
|
---|
1605 | int length = text.length();
|
---|
1606 | bool hasNewPar = curpar->length() <= 1;
|
---|
1607 | QString anchorName;
|
---|
1608 |
|
---|
1609 | // style sheet handling for margin and line spacing calculation below
|
---|
1610 | QTextParagraph* stylesPar = curpar;
|
---|
1611 | QPtrVector<QStyleSheetItem>* vec = 0;
|
---|
1612 | QPtrList< QPtrVector<QStyleSheetItem> > styles;
|
---|
1613 | styles.setAutoDelete( TRUE );
|
---|
1614 |
|
---|
1615 | if ( cursor ) {
|
---|
1616 | cursor->splitAndInsertEmptyParagraph();
|
---|
1617 | QTextCursor tmp = *cursor;
|
---|
1618 | tmp.gotoPreviousLetter();
|
---|
1619 | stylesPar = curpar = tmp.paragraph();
|
---|
1620 | hasNewPar = TRUE;
|
---|
1621 | textEditMode = TRUE;
|
---|
1622 | } else {
|
---|
1623 | NEWPAR;
|
---|
1624 | }
|
---|
1625 |
|
---|
1626 | // set rtext spacing to FALSE for the initial paragraph.
|
---|
1627 | curpar->rtext = FALSE;
|
---|
1628 |
|
---|
1629 | QString wellKnownTags = "br hr wsp table qt body meta title";
|
---|
1630 |
|
---|
1631 | while ( pos < length ) {
|
---|
1632 | if ( hasPrefix(doc, length, pos, '<' ) ){
|
---|
1633 | if ( !hasPrefix( doc, length, pos+1, QChar('/') ) ) {
|
---|
1634 | // open tag
|
---|
1635 | QMap<QString, QString> attr;
|
---|
1636 | bool emptyTag = FALSE;
|
---|
1637 | QString tagname = parseOpenTag(doc, length, pos, attr, emptyTag);
|
---|
1638 | if ( tagname.isEmpty() )
|
---|
1639 | continue; // nothing we could do with this, probably parse error
|
---|
1640 |
|
---|
1641 | const QStyleSheetItem* nstyle = sheet_->item(tagname);
|
---|
1642 |
|
---|
1643 | if ( nstyle ) {
|
---|
1644 | // we might have to close some 'forgotten' tags
|
---|
1645 | while ( !nstyle->allowedInContext( curtag.style ) ) {
|
---|
1646 | QString msg;
|
---|
1647 | msg.sprintf( "QText Warning: Document not valid ( '%s' not allowed in '%s' #%d)",
|
---|
1648 | tagname.ascii(), curtag.style->name().ascii(), pos);
|
---|
1649 | sheet_->error( msg );
|
---|
1650 | if ( tags.isEmpty() )
|
---|
1651 | break;
|
---|
1652 | curtag = tags.pop();
|
---|
1653 | }
|
---|
1654 |
|
---|
1655 | /* special handling for p and li for HTML
|
---|
1656 | compatibility. We do not want to embed blocks in
|
---|
1657 | p, and we do not want new blocks inside non-empty
|
---|
1658 | lis. Plus we want to merge empty lis sometimes. */
|
---|
1659 | if( nstyle->displayMode() == QStyleSheetItem::DisplayListItem ) {
|
---|
1660 | canMergeLi = TRUE;
|
---|
1661 | } else if ( nstyle->displayMode() == QStyleSheetItem::DisplayBlock ) {
|
---|
1662 | while ( curtag.style->name() == "p" ) {
|
---|
1663 | if ( tags.isEmpty() )
|
---|
1664 | break;
|
---|
1665 | curtag = tags.pop();
|
---|
1666 | }
|
---|
1667 |
|
---|
1668 | if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
|
---|
1669 | // we are in a li and a new block comes along
|
---|
1670 | if ( nstyle->name() == "ul" || nstyle->name() == "ol" )
|
---|
1671 | hasNewPar = FALSE; // we want an empty li (like most browsers)
|
---|
1672 | if ( !hasNewPar ) {
|
---|
1673 | /* do not add new blocks inside
|
---|
1674 | non-empty lis */
|
---|
1675 | while ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
|
---|
1676 | if ( tags.isEmpty() )
|
---|
1677 | break;
|
---|
1678 | curtag = tags.pop();
|
---|
1679 | }
|
---|
1680 | } else if ( canMergeLi ) {
|
---|
1681 | /* we have an empty li and a block
|
---|
1682 | comes along, merge them */
|
---|
1683 | nstyle = curtag.style;
|
---|
1684 | }
|
---|
1685 | canMergeLi = FALSE;
|
---|
1686 | }
|
---|
1687 | }
|
---|
1688 | }
|
---|
1689 |
|
---|
1690 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
1691 | QTextCustomItem* custom = 0;
|
---|
1692 | #else
|
---|
1693 | bool custom = FALSE;
|
---|
1694 | #endif
|
---|
1695 |
|
---|
1696 | // some well-known tags, some have a nstyle, some not
|
---|
1697 | if ( wellKnownTags.find( tagname ) != -1 ) {
|
---|
1698 | if ( tagname == "br" ) {
|
---|
1699 | emptyTag = space = TRUE;
|
---|
1700 | int index = QMAX( curpar->length(),1) - 1;
|
---|
1701 | QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
|
---|
1702 | curpar->append( QChar_linesep );
|
---|
1703 | curpar->setFormat( index, 1, &format );
|
---|
1704 | } else if ( tagname == "hr" ) {
|
---|
1705 | emptyTag = space = TRUE;
|
---|
1706 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
1707 | custom = sheet_->tag( tagname, attr, contxt, *factory_ , emptyTag, this );
|
---|
1708 | #endif
|
---|
1709 | } else if ( tagname == "table" ) {
|
---|
1710 | emptyTag = space = TRUE;
|
---|
1711 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
1712 | QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
|
---|
1713 | curpar->setAlignment( curtag.alignment );
|
---|
1714 | custom = parseTable( attr, format, doc, length, pos, curpar );
|
---|
1715 | #endif
|
---|
1716 | } else if ( tagname == "qt" || tagname == "body" ) {
|
---|
1717 | if ( attr.contains( "bgcolor" ) ) {
|
---|
1718 | QBrush *b = new QBrush( QColor( attr["bgcolor"] ) );
|
---|
1719 | setPaper( b );
|
---|
1720 | }
|
---|
1721 | if ( attr.contains( "background" ) ) {
|
---|
1722 | #ifndef QT_NO_MIME
|
---|
1723 | QImage img;
|
---|
1724 | QString bg = attr["background"];
|
---|
1725 | const QMimeSource* m = factory_->data( bg, contxt );
|
---|
1726 | if ( !m ) {
|
---|
1727 | qWarning("QRichText: no mimesource for %s", bg.latin1() );
|
---|
1728 | } else {
|
---|
1729 | if ( !QImageDrag::decode( m, img ) ) {
|
---|
1730 | qWarning("QTextImage: cannot decode %s", bg.latin1() );
|
---|
1731 | }
|
---|
1732 | }
|
---|
1733 | if ( !img.isNull() ) {
|
---|
1734 | QBrush *b = new QBrush( QColor(), QPixmap( img ) );
|
---|
1735 | setPaper( b );
|
---|
1736 | }
|
---|
1737 | #endif
|
---|
1738 | }
|
---|
1739 | if ( attr.contains( "text" ) ) {
|
---|
1740 | QColor c( attr["text"] );
|
---|
1741 | initag.format.setColor( c );
|
---|
1742 | curtag.format.setColor( c );
|
---|
1743 | bodyText = c;
|
---|
1744 | }
|
---|
1745 | if ( attr.contains( "link" ) )
|
---|
1746 | linkColor = QColor( attr["link"] );
|
---|
1747 | if ( attr.contains( "title" ) )
|
---|
1748 | attribs.replace( "title", attr["title"] );
|
---|
1749 |
|
---|
1750 | if ( textEditMode ) {
|
---|
1751 | if ( attr.contains("style" ) ) {
|
---|
1752 | QString a = attr["style"];
|
---|
1753 | for ( int s = 0; s < a.contains(';')+1; s++ ) {
|
---|
1754 | QString style = a.section( ';', s, s );
|
---|
1755 | if ( style.startsWith("font-size:" ) && style.endsWith("pt") ) {
|
---|
1756 | scaleFontsFactor = double( formatCollection()->defaultFormat()->fn.pointSize() ) /
|
---|
1757 | style.mid( 10, style.length() - 12 ).toInt();
|
---|
1758 | }
|
---|
1759 | }
|
---|
1760 | }
|
---|
1761 | nstyle = 0; // ignore body in textEditMode
|
---|
1762 | }
|
---|
1763 | // end qt- and body-tag handling
|
---|
1764 | } else if ( tagname == "meta" ) {
|
---|
1765 | if ( attr["name"] == "qrichtext" && attr["content"] == "1" )
|
---|
1766 | textEditMode = TRUE;
|
---|
1767 | } else if ( tagname == "title" ) {
|
---|
1768 | QString title;
|
---|
1769 | while ( pos < length ) {
|
---|
1770 | if ( hasPrefix( doc, length, pos, QChar('<') ) && hasPrefix( doc, length, pos+1, QChar('/') ) &&
|
---|
1771 | parseCloseTag( doc, length, pos ) == "title" )
|
---|
1772 | break;
|
---|
1773 | title += doc[ pos ];
|
---|
1774 | ++pos;
|
---|
1775 | }
|
---|
1776 | attribs.replace( "title", title );
|
---|
1777 | }
|
---|
1778 | } // end of well-known tag handling
|
---|
1779 |
|
---|
1780 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
1781 | if ( !custom ) // try generic custom item
|
---|
1782 | custom = sheet_->tag( tagname, attr, contxt, *factory_ , emptyTag, this );
|
---|
1783 | #endif
|
---|
1784 | if ( !nstyle && !custom ) // we have no clue what this tag could be, ignore it
|
---|
1785 | continue;
|
---|
1786 |
|
---|
1787 | if ( custom ) {
|
---|
1788 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
1789 | int index = QMAX( curpar->length(),1) - 1;
|
---|
1790 | QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
|
---|
1791 | curpar->append( QChar('*') );
|
---|
1792 | QTextFormat* f = formatCollection()->format( &format );
|
---|
1793 | curpar->setFormat( index, 1, f );
|
---|
1794 | curpar->at( index )->setCustomItem( custom );
|
---|
1795 | if ( !curtag.anchorHref.isEmpty() )
|
---|
1796 | curpar->at(index)->setAnchor( QString::null, curtag.anchorHref );
|
---|
1797 | if ( !anchorName.isEmpty() ) {
|
---|
1798 | curpar->at(index)->setAnchor( anchorName, curpar->at(index)->anchorHref() );
|
---|
1799 | anchorName = QString::null;
|
---|
1800 | }
|
---|
1801 | registerCustomItem( custom, curpar );
|
---|
1802 | hasNewPar = FALSE;
|
---|
1803 | #endif
|
---|
1804 | } else if ( !emptyTag ) {
|
---|
1805 | /* if we do nesting, push curtag on the stack,
|
---|
1806 | otherwise reinint curag. */
|
---|
1807 | if ( curtag.style->name() != tagname || nstyle->selfNesting() ) {
|
---|
1808 | tags.push( curtag );
|
---|
1809 | } else {
|
---|
1810 | if ( !tags.isEmpty() )
|
---|
1811 | curtag = tags.top();
|
---|
1812 | else
|
---|
1813 | curtag = initag;
|
---|
1814 | }
|
---|
1815 |
|
---|
1816 | curtag.name = tagname;
|
---|
1817 | curtag.style = nstyle;
|
---|
1818 | curtag.name = tagname;
|
---|
1819 | curtag.style = nstyle;
|
---|
1820 | if ( nstyle->whiteSpaceMode() != QStyleSheetItem::WhiteSpaceModeUndefined )
|
---|
1821 | curtag.wsm = nstyle->whiteSpaceMode();
|
---|
1822 |
|
---|
1823 | /* netscape compatibility: eat a newline and only a newline if a pre block starts */
|
---|
1824 | if ( curtag.wsm == QStyleSheetItem::WhiteSpacePre &&
|
---|
1825 | nstyle->displayMode() == QStyleSheetItem::DisplayBlock )
|
---|
1826 | eat( doc, length, pos, '\n' );
|
---|
1827 |
|
---|
1828 | /* ignore whitespace for inline elements if there
|
---|
1829 | was already one*/
|
---|
1830 | if ( !textEditMode &&
|
---|
1831 | (curtag.wsm == QStyleSheetItem::WhiteSpaceNormal
|
---|
1832 | || curtag.wsm == QStyleSheetItem::WhiteSpaceNoWrap)
|
---|
1833 | && ( space || nstyle->displayMode() != QStyleSheetItem::DisplayInline ) )
|
---|
1834 | eatSpace( doc, length, pos );
|
---|
1835 |
|
---|
1836 | curtag.format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
|
---|
1837 | if ( nstyle->isAnchor() ) {
|
---|
1838 | if ( !anchorName.isEmpty() )
|
---|
1839 | anchorName += "#" + attr["name"];
|
---|
1840 | else
|
---|
1841 | anchorName = attr["name"];
|
---|
1842 | curtag.anchorHref = attr["href"];
|
---|
1843 | }
|
---|
1844 |
|
---|
1845 | if ( nstyle->alignment() != QStyleSheetItem::Undefined )
|
---|
1846 | curtag.alignment = nstyle->alignment();
|
---|
1847 |
|
---|
1848 | if ( nstyle->listStyle() != QStyleSheetItem::ListStyleUndefined )
|
---|
1849 | curtag.liststyle = nstyle->listStyle();
|
---|
1850 |
|
---|
1851 | if ( nstyle->displayMode() == QStyleSheetItem::DisplayBlock
|
---|
1852 | || nstyle->displayMode() == QStyleSheetItem::DisplayListItem ) {
|
---|
1853 |
|
---|
1854 | if ( nstyle->name() == "ol" || nstyle->name() == "ul" || nstyle->name() == "li") {
|
---|
1855 | QString type = attr["type"];
|
---|
1856 | if ( !type.isEmpty() ) {
|
---|
1857 | if ( type == "1" ) {
|
---|
1858 | curtag.liststyle = QStyleSheetItem::ListDecimal;
|
---|
1859 | } else if ( type == "a" ) {
|
---|
1860 | curtag.liststyle = QStyleSheetItem::ListLowerAlpha;
|
---|
1861 | } else if ( type == "A" ) {
|
---|
1862 | curtag.liststyle = QStyleSheetItem::ListUpperAlpha;
|
---|
1863 | } else {
|
---|
1864 | type = type.lower();
|
---|
1865 | if ( type == "square" )
|
---|
1866 | curtag.liststyle = QStyleSheetItem::ListSquare;
|
---|
1867 | else if ( type == "disc" )
|
---|
1868 | curtag.liststyle = QStyleSheetItem::ListDisc;
|
---|
1869 | else if ( type == "circle" )
|
---|
1870 | curtag.liststyle = QStyleSheetItem::ListCircle;
|
---|
1871 | }
|
---|
1872 | }
|
---|
1873 | }
|
---|
1874 |
|
---|
1875 |
|
---|
1876 | /* Internally we treat ordered and bullet
|
---|
1877 | lists the same for margin calculations. In
|
---|
1878 | order to have fast pointer compares in the
|
---|
1879 | xMargin() functions we restrict ourselves to
|
---|
1880 | <ol>. Once we calculate the margins in the
|
---|
1881 | parser rathern than later, the unelegance of
|
---|
1882 | this approach goes awy
|
---|
1883 | */
|
---|
1884 | if ( nstyle->name() == "ul" )
|
---|
1885 | curtag.style = sheet_->item( "ol" );
|
---|
1886 |
|
---|
1887 | if ( attr.contains( "align" ) ) {
|
---|
1888 | QString align = attr["align"].lower();
|
---|
1889 | if ( align == "center" )
|
---|
1890 | curtag.alignment = Qt::AlignCenter;
|
---|
1891 | else if ( align == "right" )
|
---|
1892 | curtag.alignment = Qt::AlignRight;
|
---|
1893 | else if ( align == "justify" )
|
---|
1894 | curtag.alignment = Qt::AlignJustify;
|
---|
1895 | }
|
---|
1896 | if ( attr.contains( "dir" ) ) {
|
---|
1897 | QString dir = attr["dir"];
|
---|
1898 | if ( dir == "rtl" )
|
---|
1899 | curtag.direction = QChar::DirR;
|
---|
1900 | else if ( dir == "ltr" )
|
---|
1901 | curtag.direction = QChar::DirL;
|
---|
1902 | }
|
---|
1903 |
|
---|
1904 | NEWPAR;
|
---|
1905 |
|
---|
1906 | if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
|
---|
1907 | if ( attr.contains( "value " ) )
|
---|
1908 | curpar->setListValue( attr["value"].toInt() );
|
---|
1909 | }
|
---|
1910 |
|
---|
1911 | if ( attr.contains( "style" ) ) {
|
---|
1912 | QString a = attr["style"];
|
---|
1913 | bool ok = TRUE;
|
---|
1914 | for ( int s = 0; ok && s < a.contains(';')+1; s++ ) {
|
---|
1915 | QString style = a.section( ';', s, s );
|
---|
1916 | if ( style.startsWith("margin-top:" ) && style.endsWith("px") )
|
---|
1917 | curpar->utm = 1+style.mid(11, style.length() - 13).toInt(&ok);
|
---|
1918 | else if ( style.startsWith("margin-bottom:" ) && style.endsWith("px") )
|
---|
1919 | curpar->ubm = 1+style.mid(14, style.length() - 16).toInt(&ok);
|
---|
1920 | else if ( style.startsWith("margin-left:" ) && style.endsWith("px") )
|
---|
1921 | curpar->ulm = 1+style.mid(12, style.length() - 14).toInt(&ok);
|
---|
1922 | else if ( style.startsWith("margin-right:" ) && style.endsWith("px") )
|
---|
1923 | curpar->urm = 1+style.mid(13, style.length() - 15).toInt(&ok);
|
---|
1924 | else if ( style.startsWith("text-indent:" ) && style.endsWith("px") )
|
---|
1925 | curpar->uflm = 1+style.mid(12, style.length() - 14).toInt(&ok);
|
---|
1926 | }
|
---|
1927 | if ( !ok ) // be pressmistic
|
---|
1928 | curpar->utm = curpar->ubm = curpar->urm = curpar->ulm = 0;
|
---|
1929 | }
|
---|
1930 | }
|
---|
1931 | }
|
---|
1932 | } else {
|
---|
1933 | QString tagname = parseCloseTag( doc, length, pos );
|
---|
1934 | if ( tagname.isEmpty() )
|
---|
1935 | continue; // nothing we could do with this, probably parse error
|
---|
1936 | if ( !sheet_->item( tagname ) ) // ignore unknown tags
|
---|
1937 | continue;
|
---|
1938 | if ( tagname == "li" )
|
---|
1939 | continue;
|
---|
1940 |
|
---|
1941 | // we close a block item. Since the text may continue, we need to have a new paragraph
|
---|
1942 | bool needNewPar = curtag.style->displayMode() == QStyleSheetItem::DisplayBlock
|
---|
1943 | || curtag.style->displayMode() == QStyleSheetItem::DisplayListItem;
|
---|
1944 |
|
---|
1945 |
|
---|
1946 | // html slopiness: handle unbalanched tag closing
|
---|
1947 | while ( curtag.name != tagname ) {
|
---|
1948 | QString msg;
|
---|
1949 | msg.sprintf( "QText Warning: Document not valid ( '%s' not closed before '%s' #%d)",
|
---|
1950 | curtag.name.ascii(), tagname.ascii(), pos);
|
---|
1951 | sheet_->error( msg );
|
---|
1952 | if ( tags.isEmpty() )
|
---|
1953 | break;
|
---|
1954 | curtag = tags.pop();
|
---|
1955 | }
|
---|
1956 |
|
---|
1957 |
|
---|
1958 | // close the tag
|
---|
1959 | if ( !tags.isEmpty() )
|
---|
1960 | curtag = tags.pop();
|
---|
1961 | else
|
---|
1962 | curtag = initag;
|
---|
1963 |
|
---|
1964 | if ( needNewPar ) {
|
---|
1965 | if ( textEditMode && (tagname == "p" || tagname == "div" ) ) // preserve empty paragraphs
|
---|
1966 | hasNewPar = FALSE;
|
---|
1967 | NEWPAR;
|
---|
1968 | }
|
---|
1969 | }
|
---|
1970 | } else {
|
---|
1971 | // normal contents
|
---|
1972 | QString s;
|
---|
1973 | QChar c;
|
---|
1974 | while ( pos < length && !hasPrefix(doc, length, pos, QChar('<') ) ){
|
---|
1975 | if ( textEditMode ) {
|
---|
1976 | // text edit mode: we handle all white space but ignore newlines
|
---|
1977 | c = parseChar( doc, length, pos, QStyleSheetItem::WhiteSpacePre );
|
---|
1978 | if ( c == QChar_linesep )
|
---|
1979 | break;
|
---|
1980 | } else {
|
---|
1981 | int l = pos;
|
---|
1982 | c = parseChar( doc, length, pos, curtag.wsm );
|
---|
1983 |
|
---|
1984 | // in white space pre mode: treat any space as non breakable
|
---|
1985 | // and expand tabs to eight character wide columns.
|
---|
1986 | if ( curtag.wsm == QStyleSheetItem::WhiteSpacePre ) {
|
---|
1987 | if ( c == '\t' ) {
|
---|
1988 | c = ' ';
|
---|
1989 | while( (++tabExpansionColumn)%8 )
|
---|
1990 | s += c;
|
---|
1991 | }
|
---|
1992 | if ( c == QChar_linesep )
|
---|
1993 | tabExpansionColumn = 0;
|
---|
1994 | else
|
---|
1995 | tabExpansionColumn++;
|
---|
1996 |
|
---|
1997 | }
|
---|
1998 | if ( c == ' ' || c == QChar_linesep ) {
|
---|
1999 | /* avoid overlong paragraphs by forcing a new
|
---|
2000 | paragraph after 4096 characters. This case can
|
---|
2001 | occur when loading undiscovered plain text
|
---|
2002 | documents in rich text mode. Instead of hanging
|
---|
2003 | forever, we do the trick.
|
---|
2004 | */
|
---|
2005 | if ( curtag.wsm == QStyleSheetItem::WhiteSpaceNormal && s.length() > 4096 ) do {
|
---|
2006 | if ( doc[l] == '\n' ) {
|
---|
2007 | hasNewPar = FALSE; // for a new paragraph ...
|
---|
2008 | NEWPAR;
|
---|
2009 | hasNewPar = FALSE; // ... and make it non-reusable
|
---|
2010 | c = '\n'; // make sure we break below
|
---|
2011 | break;
|
---|
2012 | }
|
---|
2013 | } while ( ++l < pos );
|
---|
2014 | }
|
---|
2015 | }
|
---|
2016 |
|
---|
2017 | if ( c == '\n' )
|
---|
2018 | break; // break on newlines, pre delievers a QChar_linesep
|
---|
2019 |
|
---|
2020 | bool c_isSpace = c.isSpace() && c.unicode() != 0x00a0U && !textEditMode;
|
---|
2021 |
|
---|
2022 | if ( curtag.wsm == QStyleSheetItem::WhiteSpaceNormal && c_isSpace && space )
|
---|
2023 | continue;
|
---|
2024 | if ( c == '\r' )
|
---|
2025 | continue;
|
---|
2026 | space = c_isSpace;
|
---|
2027 | s += c;
|
---|
2028 | }
|
---|
2029 | if ( !s.isEmpty() && curtag.style->displayMode() != QStyleSheetItem::DisplayNone ) {
|
---|
2030 | hasNewPar = FALSE;
|
---|
2031 | int index = QMAX( curpar->length(),1) - 1;
|
---|
2032 | curpar->append( s );
|
---|
2033 | if (curtag.wsm != QStyleSheetItem::WhiteSpaceNormal) {
|
---|
2034 | QTextString *str = curpar->string();
|
---|
2035 | for (uint i = index; i < index + s.length(); ++i)
|
---|
2036 | str->at(i).nobreak = TRUE;
|
---|
2037 | }
|
---|
2038 |
|
---|
2039 | QTextFormat* f = formatCollection()->format( &curtag.format );
|
---|
2040 | curpar->setFormat( index, s.length(), f, FALSE ); // do not use collection because we have done that already
|
---|
2041 | f->ref += s.length() -1; // that what friends are for...
|
---|
2042 | if ( !curtag.anchorHref.isEmpty() ) {
|
---|
2043 | for ( int i = 0; i < int(s.length()); i++ )
|
---|
2044 | curpar->at(index + i)->setAnchor( QString::null, curtag.anchorHref );
|
---|
2045 | }
|
---|
2046 | if ( !anchorName.isEmpty() ) {
|
---|
2047 | for ( int i = 0; i < int(s.length()); i++ )
|
---|
2048 | curpar->at(index + i)->setAnchor( anchorName, curpar->at(index + i)->anchorHref() );
|
---|
2049 | anchorName = QString::null;
|
---|
2050 | }
|
---|
2051 | }
|
---|
2052 | }
|
---|
2053 | }
|
---|
2054 |
|
---|
2055 | if ( hasNewPar && curpar != fParag && !cursor && stylesPar != curpar ) {
|
---|
2056 | // cleanup unused last paragraphs
|
---|
2057 | curpar = curpar->p;
|
---|
2058 | delete curpar->n;
|
---|
2059 | }
|
---|
2060 |
|
---|
2061 | if ( !anchorName.isEmpty() ) {
|
---|
2062 | curpar->at(curpar->length() - 1)->setAnchor( anchorName, curpar->at( curpar->length() - 1 )->anchorHref() );
|
---|
2063 | anchorName = QString::null;
|
---|
2064 | }
|
---|
2065 |
|
---|
2066 |
|
---|
2067 | setRichTextMarginsInternal( styles, stylesPar );
|
---|
2068 |
|
---|
2069 | if ( cursor ) {
|
---|
2070 | cursor->gotoPreviousLetter();
|
---|
2071 | cursor->remove();
|
---|
2072 | }
|
---|
2073 | delete vec;
|
---|
2074 | }
|
---|
2075 |
|
---|
2076 | void QTextDocument::setRichTextMarginsInternal( QPtrList< QPtrVector<QStyleSheetItem> >& styles, QTextParagraph* stylesPar )
|
---|
2077 | {
|
---|
2078 | // margin and line spacing calculation
|
---|
2079 | QPtrVector<QStyleSheetItem>* prevStyle = 0;
|
---|
2080 | QPtrVector<QStyleSheetItem>* curStyle = styles.first();
|
---|
2081 | QPtrVector<QStyleSheetItem>* nextStyle = styles.next();
|
---|
2082 | while ( stylesPar ) {
|
---|
2083 | if ( !curStyle ) {
|
---|
2084 | stylesPar = stylesPar->next();
|
---|
2085 | prevStyle = curStyle;
|
---|
2086 | curStyle = nextStyle;
|
---|
2087 | nextStyle = styles.next();
|
---|
2088 | continue;
|
---|
2089 | }
|
---|
2090 |
|
---|
2091 | int i, mar;
|
---|
2092 | QStyleSheetItem* mainStyle = curStyle->size() ? (*curStyle)[curStyle->size()-1] : 0;
|
---|
2093 | if ( mainStyle && mainStyle->displayMode() == QStyleSheetItem::DisplayListItem )
|
---|
2094 | stylesPar->setListItem( TRUE );
|
---|
2095 | int numLists = 0;
|
---|
2096 | for ( i = 0; i < (int)curStyle->size(); ++i ) {
|
---|
2097 | if ( (*curStyle)[ i ]->displayMode() == QStyleSheetItem::DisplayBlock
|
---|
2098 | && (*curStyle)[ i ]->listStyle() != QStyleSheetItem::ListStyleUndefined )
|
---|
2099 | numLists++;
|
---|
2100 | }
|
---|
2101 | stylesPar->ldepth = numLists;
|
---|
2102 | if ( stylesPar->next() && nextStyle ) {
|
---|
2103 | // also set the depth of the next paragraph, required for the margin calculation
|
---|
2104 | numLists = 0;
|
---|
2105 | for ( i = 0; i < (int)nextStyle->size(); ++i ) {
|
---|
2106 | if ( (*nextStyle)[ i ]->displayMode() == QStyleSheetItem::DisplayBlock
|
---|
2107 | && (*nextStyle)[ i ]->listStyle() != QStyleSheetItem::ListStyleUndefined )
|
---|
2108 | numLists++;
|
---|
2109 | }
|
---|
2110 | stylesPar->next()->ldepth = numLists;
|
---|
2111 | }
|
---|
2112 |
|
---|
2113 | // do the top margin
|
---|
2114 | QStyleSheetItem* item = mainStyle;
|
---|
2115 | int m;
|
---|
2116 | if (stylesPar->utm > 0 ) {
|
---|
2117 | m = stylesPar->utm-1;
|
---|
2118 | stylesPar->utm = 0;
|
---|
2119 | } else {
|
---|
2120 | m = QMAX(0, item->margin( QStyleSheetItem::MarginTop ) );
|
---|
2121 | if ( stylesPar->ldepth )
|
---|
2122 | if ( item->displayMode() == QStyleSheetItem::DisplayListItem )
|
---|
2123 | m /= stylesPar->ldepth * stylesPar->ldepth;
|
---|
2124 | else
|
---|
2125 | m = 0;
|
---|
2126 | }
|
---|
2127 | for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
|
---|
2128 | item = (*curStyle)[ i ];
|
---|
2129 | if ( prevStyle && i < (int) prevStyle->size() &&
|
---|
2130 | ( item->displayMode() == QStyleSheetItem::DisplayBlock &&
|
---|
2131 | (*prevStyle)[ i ] == item ) )
|
---|
2132 | break;
|
---|
2133 | // emulate CSS2' standard 0 vertical margin for multiple ul or ol tags
|
---|
2134 | if ( item->listStyle() != QStyleSheetItem::ListStyleUndefined &&
|
---|
2135 | ( ( i> 0 && (*curStyle)[ i-1 ] == item ) || (*curStyle)[i+1] == item ) )
|
---|
2136 | continue;
|
---|
2137 | mar = QMAX( 0, item->margin( QStyleSheetItem::MarginTop ) );
|
---|
2138 | m = QMAX( m, mar );
|
---|
2139 | }
|
---|
2140 | stylesPar->utm = m - stylesPar->topMargin();
|
---|
2141 |
|
---|
2142 | // do the bottom margin
|
---|
2143 | item = mainStyle;
|
---|
2144 | if (stylesPar->ubm > 0 ) {
|
---|
2145 | m = stylesPar->ubm-1;
|
---|
2146 | stylesPar->ubm = 0;
|
---|
2147 | } else {
|
---|
2148 | m = QMAX(0, item->margin( QStyleSheetItem::MarginBottom ) );
|
---|
2149 | if ( stylesPar->ldepth )
|
---|
2150 | if ( item->displayMode() == QStyleSheetItem::DisplayListItem )
|
---|
2151 | m /= stylesPar->ldepth * stylesPar->ldepth;
|
---|
2152 | else
|
---|
2153 | m = 0;
|
---|
2154 | }
|
---|
2155 | for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
|
---|
2156 | item = (*curStyle)[ i ];
|
---|
2157 | if ( nextStyle && i < (int) nextStyle->size() &&
|
---|
2158 | ( item->displayMode() == QStyleSheetItem::DisplayBlock &&
|
---|
2159 | (*nextStyle)[ i ] == item ) )
|
---|
2160 | break;
|
---|
2161 | // emulate CSS2' standard 0 vertical margin for multiple ul or ol tags
|
---|
2162 | if ( item->listStyle() != QStyleSheetItem::ListStyleUndefined &&
|
---|
2163 | ( ( i> 0 && (*curStyle)[ i-1 ] == item ) || (*curStyle)[i+1] == item ) )
|
---|
2164 | continue;
|
---|
2165 | mar = QMAX(0, item->margin( QStyleSheetItem::MarginBottom ) );
|
---|
2166 | m = QMAX( m, mar );
|
---|
2167 | }
|
---|
2168 | stylesPar->ubm = m - stylesPar->bottomMargin();
|
---|
2169 |
|
---|
2170 | // do the left margin, simplyfied
|
---|
2171 | item = mainStyle;
|
---|
2172 | if (stylesPar->ulm > 0 ) {
|
---|
2173 | m = stylesPar->ulm-1;
|
---|
2174 | stylesPar->ulm = 0;
|
---|
2175 | } else {
|
---|
2176 | m = QMAX( 0, item->margin( QStyleSheetItem::MarginLeft ) );
|
---|
2177 | }
|
---|
2178 | for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
|
---|
2179 | item = (*curStyle)[ i ];
|
---|
2180 | m += QMAX( 0, item->margin( QStyleSheetItem::MarginLeft ) );
|
---|
2181 | }
|
---|
2182 | stylesPar->ulm = m - stylesPar->leftMargin();
|
---|
2183 |
|
---|
2184 | // do the right margin, simplyfied
|
---|
2185 | item = mainStyle;
|
---|
2186 | if (stylesPar->urm > 0 ) {
|
---|
2187 | m = stylesPar->urm-1;
|
---|
2188 | stylesPar->urm = 0;
|
---|
2189 | } else {
|
---|
2190 | m = QMAX( 0, item->margin( QStyleSheetItem::MarginRight ) );
|
---|
2191 | }
|
---|
2192 | for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
|
---|
2193 | item = (*curStyle)[ i ];
|
---|
2194 | m += QMAX( 0, item->margin( QStyleSheetItem::MarginRight ) );
|
---|
2195 | }
|
---|
2196 | stylesPar->urm = m - stylesPar->rightMargin();
|
---|
2197 |
|
---|
2198 | // do the first line margin, which really should be called text-indent
|
---|
2199 | item = mainStyle;
|
---|
2200 | if (stylesPar->uflm > 0 ) {
|
---|
2201 | m = stylesPar->uflm-1;
|
---|
2202 | stylesPar->uflm = 0;
|
---|
2203 | } else {
|
---|
2204 | m = QMAX( 0, item->margin( QStyleSheetItem::MarginFirstLine ) );
|
---|
2205 | }
|
---|
2206 | for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
|
---|
2207 | item = (*curStyle)[ i ];
|
---|
2208 | mar = QMAX( 0, item->margin( QStyleSheetItem::MarginFirstLine ) );
|
---|
2209 | m = QMAX( m, mar );
|
---|
2210 | }
|
---|
2211 | stylesPar->uflm =m - stylesPar->firstLineMargin();
|
---|
2212 |
|
---|
2213 | // do the bogus line "spacing", which really is just an extra margin
|
---|
2214 | item = mainStyle;
|
---|
2215 | for ( i = (int)curStyle->size() - 1 ; i >= 0; --i ) {
|
---|
2216 | item = (*curStyle)[ i ];
|
---|
2217 | if ( item->lineSpacing() != QStyleSheetItem::Undefined ) {
|
---|
2218 | stylesPar->ulinespacing = item->lineSpacing();
|
---|
2219 | if ( formatCollection() &&
|
---|
2220 | stylesPar->ulinespacing < formatCollection()->defaultFormat()->height() )
|
---|
2221 | stylesPar->ulinespacing += formatCollection()->defaultFormat()->height();
|
---|
2222 | break;
|
---|
2223 | }
|
---|
2224 | }
|
---|
2225 |
|
---|
2226 | stylesPar = stylesPar->next();
|
---|
2227 | prevStyle = curStyle;
|
---|
2228 | curStyle = nextStyle;
|
---|
2229 | nextStyle = styles.next();
|
---|
2230 | }
|
---|
2231 | }
|
---|
2232 |
|
---|
2233 | void QTextDocument::setText( const QString &text, const QString &context )
|
---|
2234 | {
|
---|
2235 | focusIndicator.parag = 0;
|
---|
2236 | selections.clear();
|
---|
2237 | if ( txtFormat == Qt::AutoText && QStyleSheet::mightBeRichText( text ) ||
|
---|
2238 | txtFormat == Qt::RichText )
|
---|
2239 | setRichText( text, context );
|
---|
2240 | else
|
---|
2241 | setPlainText( text );
|
---|
2242 | }
|
---|
2243 |
|
---|
2244 | QString QTextDocument::plainText() const
|
---|
2245 | {
|
---|
2246 | QString buffer;
|
---|
2247 | QString s;
|
---|
2248 | QTextParagraph *p = fParag;
|
---|
2249 | while ( p ) {
|
---|
2250 | if ( !p->mightHaveCustomItems ) {
|
---|
2251 | const QTextString *ts = p->string(); // workaround VC++ and Borland
|
---|
2252 | s = ts->toString(); // with FALSE we don't fix spaces (nbsp)
|
---|
2253 | } else {
|
---|
2254 | for ( int i = 0; i < p->length() - 1; ++i ) {
|
---|
2255 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
2256 | if ( p->at( i )->isCustom() ) {
|
---|
2257 | if ( p->at( i )->customItem()->isNested() ) {
|
---|
2258 | s += "\n";
|
---|
2259 | QTextTable *t = (QTextTable*)p->at( i )->customItem();
|
---|
2260 | QPtrList<QTextTableCell> cells = t->tableCells();
|
---|
2261 | for ( QTextTableCell *c = cells.first(); c; c = cells.next() )
|
---|
2262 | s += c->richText()->plainText() + "\n";
|
---|
2263 | s += "\n";
|
---|
2264 | }
|
---|
2265 | } else
|
---|
2266 | #endif
|
---|
2267 | {
|
---|
2268 | s += p->at( i )->c;
|
---|
2269 | }
|
---|
2270 | }
|
---|
2271 | }
|
---|
2272 | s.remove( s.length() - 1, 1 );
|
---|
2273 | if ( p->next() )
|
---|
2274 | s += "\n";
|
---|
2275 | buffer += s;
|
---|
2276 | p = p->next();
|
---|
2277 | }
|
---|
2278 | return buffer;
|
---|
2279 | }
|
---|
2280 |
|
---|
2281 | static QString align_to_string( int a )
|
---|
2282 | {
|
---|
2283 | if ( a & Qt::AlignRight )
|
---|
2284 | return " align=\"right\"";
|
---|
2285 | if ( a & Qt::AlignHCenter )
|
---|
2286 | return " align=\"center\"";
|
---|
2287 | if ( a & Qt::AlignJustify )
|
---|
2288 | return " align=\"justify\"";
|
---|
2289 | return QString::null;
|
---|
2290 | }
|
---|
2291 |
|
---|
2292 | static QString direction_to_string( int d )
|
---|
2293 | {
|
---|
2294 | if ( d != QChar::DirON )
|
---|
2295 | return ( d == QChar::DirL? " dir=\"ltr\"" : " dir=\"rtl\"" );
|
---|
2296 | return QString::null;
|
---|
2297 | }
|
---|
2298 |
|
---|
2299 | static QString list_value_to_string( int v )
|
---|
2300 | {
|
---|
2301 | if ( v != -1 )
|
---|
2302 | return " listvalue=\"" + QString::number( v ) + "\"";
|
---|
2303 | return QString::null;
|
---|
2304 | }
|
---|
2305 |
|
---|
2306 | static QString list_style_to_string( int v )
|
---|
2307 | {
|
---|
2308 | switch( v ) {
|
---|
2309 | case QStyleSheetItem::ListDecimal: return "\"1\"";
|
---|
2310 | case QStyleSheetItem::ListLowerAlpha: return "\"a\"";
|
---|
2311 | case QStyleSheetItem::ListUpperAlpha: return "\"A\"";
|
---|
2312 | case QStyleSheetItem::ListDisc: return "\"disc\"";
|
---|
2313 | case QStyleSheetItem::ListSquare: return "\"square\"";
|
---|
2314 | case QStyleSheetItem::ListCircle: return "\"circle\"";
|
---|
2315 | default:
|
---|
2316 | return QString::null;
|
---|
2317 | }
|
---|
2318 | }
|
---|
2319 |
|
---|
2320 | static inline bool list_is_ordered( int v )
|
---|
2321 | {
|
---|
2322 | return v == QStyleSheetItem::ListDecimal ||
|
---|
2323 | v == QStyleSheetItem::ListLowerAlpha ||
|
---|
2324 | v == QStyleSheetItem::ListUpperAlpha;
|
---|
2325 | }
|
---|
2326 |
|
---|
2327 |
|
---|
2328 | static QString margin_to_string( QStyleSheetItem* style, int t, int b, int l, int r, int fl )
|
---|
2329 | {
|
---|
2330 | QString s;
|
---|
2331 | if ( l > 0 )
|
---|
2332 | s += QString(!!s?";":"") + "margin-left:" + QString::number(l+QMAX(0,style->margin(QStyleSheetItem::MarginLeft))) + "px";
|
---|
2333 | if ( r > 0 )
|
---|
2334 | s += QString(!!s?";":"") + "margin-right:" + QString::number(r+QMAX(0,style->margin(QStyleSheetItem::MarginRight))) + "px";
|
---|
2335 | if ( t > 0 )
|
---|
2336 | s += QString(!!s?";":"") + "margin-top:" + QString::number(t+QMAX(0,style->margin(QStyleSheetItem::MarginTop))) + "px";
|
---|
2337 | if ( b > 0 )
|
---|
2338 | s += QString(!!s?";":"") + "margin-bottom:" + QString::number(b+QMAX(0,style->margin(QStyleSheetItem::MarginBottom))) + "px";
|
---|
2339 | if ( fl > 0 )
|
---|
2340 | s += QString(!!s?";":"") + "text-indent:" + QString::number(fl+QMAX(0,style->margin(QStyleSheetItem::MarginFirstLine))) + "px";
|
---|
2341 | if ( !!s )
|
---|
2342 | return " style=\"" + s + "\"";
|
---|
2343 | return QString::null;
|
---|
2344 | }
|
---|
2345 |
|
---|
2346 | QString QTextDocument::richText() const
|
---|
2347 | {
|
---|
2348 | QString s = "";
|
---|
2349 | if ( !par ) {
|
---|
2350 | s += "<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body style=\"font-size:" ;
|
---|
2351 | s += QString::number( formatCollection()->defaultFormat()->font().pointSize() );
|
---|
2352 | s += "pt;font-family:";
|
---|
2353 | s += formatCollection()->defaultFormat()->font().family();
|
---|
2354 | s +="\">";
|
---|
2355 | }
|
---|
2356 | QTextParagraph* p = fParag;
|
---|
2357 |
|
---|
2358 | QStyleSheetItem* item_p = styleSheet()->item("p");
|
---|
2359 | QStyleSheetItem* item_div = styleSheet()->item("div");
|
---|
2360 | QStyleSheetItem* item_ul = styleSheet()->item("ul");
|
---|
2361 | QStyleSheetItem* item_ol = styleSheet()->item("ol");
|
---|
2362 | QStyleSheetItem* item_li = styleSheet()->item("li");
|
---|
2363 | if ( !item_p || !item_div || !item_ul || !item_ol || !item_li ) {
|
---|
2364 | qWarning( "QTextEdit: cannot export HTML due to insufficient stylesheet (lack of p, div, ul, ol, or li)" );
|
---|
2365 | return QString::null;
|
---|
2366 | }
|
---|
2367 | int pastListDepth = 0;
|
---|
2368 | int listDepth = 0;
|
---|
2369 | #if 0
|
---|
2370 | int futureListDepth = 0;
|
---|
2371 | #endif
|
---|
2372 | QMemArray<int> listStyles(10);
|
---|
2373 |
|
---|
2374 | while ( p ) {
|
---|
2375 | listDepth = p->listDepth();
|
---|
2376 | if ( listDepth < pastListDepth ) {
|
---|
2377 | for ( int i = pastListDepth; i > listDepth; i-- )
|
---|
2378 | s += list_is_ordered( listStyles[i] ) ? "</ol>" : "</ul>";
|
---|
2379 | s += '\n';
|
---|
2380 | } else if ( listDepth > pastListDepth ) {
|
---|
2381 | s += '\n';
|
---|
2382 | listStyles.resize( QMAX( (int)listStyles.size(), listDepth+1 ) );
|
---|
2383 | QString list_type;
|
---|
2384 | listStyles[listDepth] = p->listStyle();
|
---|
2385 | if ( !list_is_ordered( p->listStyle() ) || item_ol->listStyle() != p->listStyle() )
|
---|
2386 | list_type = " type=" + list_style_to_string( p->listStyle() );
|
---|
2387 | for ( int i = pastListDepth; i < listDepth; i++ ) {
|
---|
2388 | s += list_is_ordered( p->listStyle() ) ? "<ol" : "<ul" ;
|
---|
2389 | s += list_type + ">";
|
---|
2390 | }
|
---|
2391 | } else {
|
---|
2392 | s += '\n';
|
---|
2393 | }
|
---|
2394 |
|
---|
2395 | QString ps = p->richText();
|
---|
2396 |
|
---|
2397 | #if 0
|
---|
2398 | // for the bottom margin we need to know whether we are at the end of a list
|
---|
2399 | futureListDepth = 0;
|
---|
2400 | if ( listDepth > 0 && p->next() )
|
---|
2401 | futureListDepth = p->next()->listDepth();
|
---|
2402 | #endif
|
---|
2403 |
|
---|
2404 | if ( richTextExportStart && richTextExportStart->paragraph() ==p &&
|
---|
2405 | richTextExportStart->index() == 0 )
|
---|
2406 | s += "<!--StartFragment-->";
|
---|
2407 |
|
---|
2408 | if ( p->isListItem() ) {
|
---|
2409 | s += "<li";
|
---|
2410 | if ( p->listStyle() != listStyles[listDepth] )
|
---|
2411 | s += " type=" + list_style_to_string( p->listStyle() );
|
---|
2412 | s +=align_to_string( p->alignment() );
|
---|
2413 | s += margin_to_string( item_li, p->utm, p->ubm, p->ulm, p->urm, p->uflm );
|
---|
2414 | s += list_value_to_string( p->listValue() );
|
---|
2415 | s += direction_to_string( p->direction() );
|
---|
2416 | s +=">";
|
---|
2417 | s += ps;
|
---|
2418 | s += "</li>";
|
---|
2419 | } else if ( p->listDepth() ) {
|
---|
2420 | s += "<div";
|
---|
2421 | s += align_to_string( p->alignment() );
|
---|
2422 | s += margin_to_string( item_div, p->utm, p->ubm, p->ulm, p->urm, p->uflm );
|
---|
2423 | s +=direction_to_string( p->direction() );
|
---|
2424 | s += ">";
|
---|
2425 | s += ps;
|
---|
2426 | s += "</div>";
|
---|
2427 | } else {
|
---|
2428 | // normal paragraph item
|
---|
2429 | s += "<p";
|
---|
2430 | s += align_to_string( p->alignment() );
|
---|
2431 | s += margin_to_string( item_p, p->utm, p->ubm, p->ulm, p->urm, p->uflm );
|
---|
2432 | s +=direction_to_string( p->direction() );
|
---|
2433 | s += ">";
|
---|
2434 | s += ps;
|
---|
2435 | s += "</p>";
|
---|
2436 | }
|
---|
2437 | pastListDepth = listDepth;
|
---|
2438 | p = p->next();
|
---|
2439 | }
|
---|
2440 | while ( listDepth > 0 ) {
|
---|
2441 | s += list_is_ordered( listStyles[listDepth] ) ? "</ol>" : "</ul>";
|
---|
2442 | listDepth--;
|
---|
2443 | }
|
---|
2444 |
|
---|
2445 | if ( !par )
|
---|
2446 | s += "\n</body></html>\n";
|
---|
2447 |
|
---|
2448 | return s;
|
---|
2449 | }
|
---|
2450 |
|
---|
2451 | QString QTextDocument::text() const
|
---|
2452 | {
|
---|
2453 | if ( txtFormat == Qt::AutoText && preferRichText || txtFormat == Qt::RichText )
|
---|
2454 | return richText();
|
---|
2455 | return plainText();
|
---|
2456 | }
|
---|
2457 |
|
---|
2458 | QString QTextDocument::text( int parag ) const
|
---|
2459 | {
|
---|
2460 | QTextParagraph *p = paragAt( parag );
|
---|
2461 | if ( !p )
|
---|
2462 | return QString::null;
|
---|
2463 |
|
---|
2464 | if ( txtFormat == Qt::AutoText && preferRichText || txtFormat == Qt::RichText )
|
---|
2465 | return p->richText();
|
---|
2466 | else
|
---|
2467 | return p->string()->toString();
|
---|
2468 | }
|
---|
2469 |
|
---|
2470 | void QTextDocument::invalidate()
|
---|
2471 | {
|
---|
2472 | QTextParagraph *s = fParag;
|
---|
2473 | while ( s ) {
|
---|
2474 | s->invalidate( 0 );
|
---|
2475 | s = s->next();
|
---|
2476 | }
|
---|
2477 | }
|
---|
2478 |
|
---|
2479 | void QTextDocument::selectionStart( int id, int ¶gId, int &index )
|
---|
2480 | {
|
---|
2481 | QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
|
---|
2482 | if ( it == selections.end() )
|
---|
2483 | return;
|
---|
2484 | QTextDocumentSelection &sel = *it;
|
---|
2485 | paragId = !sel.swapped ? sel.startCursor.paragraph()->paragId() : sel.endCursor.paragraph()->paragId();
|
---|
2486 | index = !sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
|
---|
2487 | }
|
---|
2488 |
|
---|
2489 | QTextCursor QTextDocument::selectionStartCursor( int id)
|
---|
2490 | {
|
---|
2491 | QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
|
---|
2492 | if ( it == selections.end() )
|
---|
2493 | return QTextCursor( this );
|
---|
2494 | QTextDocumentSelection &sel = *it;
|
---|
2495 | if ( sel.swapped )
|
---|
2496 | return sel.endCursor;
|
---|
2497 | return sel.startCursor;
|
---|
2498 | }
|
---|
2499 |
|
---|
2500 | QTextCursor QTextDocument::selectionEndCursor( int id)
|
---|
2501 | {
|
---|
2502 | QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
|
---|
2503 | if ( it == selections.end() )
|
---|
2504 | return QTextCursor( this );
|
---|
2505 | QTextDocumentSelection &sel = *it;
|
---|
2506 | if ( !sel.swapped )
|
---|
2507 | return sel.endCursor;
|
---|
2508 | return sel.startCursor;
|
---|
2509 | }
|
---|
2510 |
|
---|
2511 | void QTextDocument::selectionEnd( int id, int ¶gId, int &index )
|
---|
2512 | {
|
---|
2513 | QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
|
---|
2514 | if ( it == selections.end() )
|
---|
2515 | return;
|
---|
2516 | QTextDocumentSelection &sel = *it;
|
---|
2517 | paragId = sel.swapped ? sel.startCursor.paragraph()->paragId() : sel.endCursor.paragraph()->paragId();
|
---|
2518 | index = sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
|
---|
2519 | }
|
---|
2520 |
|
---|
2521 | void QTextDocument::addSelection( int id )
|
---|
2522 | {
|
---|
2523 | nSelections = QMAX( nSelections, id + 1 );
|
---|
2524 | }
|
---|
2525 |
|
---|
2526 | static void setSelectionEndHelper( int id, QTextDocumentSelection &sel, QTextCursor &start, QTextCursor &end )
|
---|
2527 | {
|
---|
2528 | QTextCursor c1 = start;
|
---|
2529 | QTextCursor c2 = end;
|
---|
2530 | if ( sel.swapped ) {
|
---|
2531 | c1 = end;
|
---|
2532 | c2 = start;
|
---|
2533 | }
|
---|
2534 |
|
---|
2535 | c1.paragraph()->removeSelection( id );
|
---|
2536 | c2.paragraph()->removeSelection( id );
|
---|
2537 | if ( c1.paragraph() != c2.paragraph() ) {
|
---|
2538 | c1.paragraph()->setSelection( id, c1.index(), c1.paragraph()->length() - 1 );
|
---|
2539 | c2.paragraph()->setSelection( id, 0, c2.index() );
|
---|
2540 | } else {
|
---|
2541 | c1.paragraph()->setSelection( id, QMIN( c1.index(), c2.index() ), QMAX( c1.index(), c2.index() ) );
|
---|
2542 | }
|
---|
2543 |
|
---|
2544 | sel.startCursor = start;
|
---|
2545 | sel.endCursor = end;
|
---|
2546 | if ( sel.startCursor.paragraph() == sel.endCursor.paragraph() )
|
---|
2547 | sel.swapped = sel.startCursor.index() > sel.endCursor.index();
|
---|
2548 | }
|
---|
2549 |
|
---|
2550 | bool QTextDocument::setSelectionEnd( int id, const QTextCursor &cursor )
|
---|
2551 | {
|
---|
2552 | QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
|
---|
2553 | if ( it == selections.end() )
|
---|
2554 | return FALSE;
|
---|
2555 | QTextDocumentSelection &sel = *it;
|
---|
2556 |
|
---|
2557 | QTextCursor start = sel.startCursor;
|
---|
2558 | QTextCursor end = cursor;
|
---|
2559 |
|
---|
2560 | if ( start == end ) {
|
---|
2561 | removeSelection( id );
|
---|
2562 | setSelectionStart( id, cursor );
|
---|
2563 | return TRUE;
|
---|
2564 | }
|
---|
2565 |
|
---|
2566 | if ( sel.endCursor.paragraph() == end.paragraph() ) {
|
---|
2567 | setSelectionEndHelper( id, sel, start, end );
|
---|
2568 | return TRUE;
|
---|
2569 | }
|
---|
2570 |
|
---|
2571 | bool inSelection = FALSE;
|
---|
2572 | QTextCursor c( this );
|
---|
2573 | QTextCursor tmp = sel.startCursor;
|
---|
2574 | if ( sel.swapped )
|
---|
2575 | tmp = sel.endCursor;
|
---|
2576 | tmp.restoreState();
|
---|
2577 | QTextCursor tmp2 = cursor;
|
---|
2578 | tmp2.restoreState();
|
---|
2579 | c.setParagraph( tmp.paragraph()->paragId() < tmp2.paragraph()->paragId() ? tmp.paragraph() : tmp2.paragraph() );
|
---|
2580 | bool hadStart = FALSE;
|
---|
2581 | bool hadEnd = FALSE;
|
---|
2582 | bool hadStartParag = FALSE;
|
---|
2583 | bool hadEndParag = FALSE;
|
---|
2584 | bool hadOldStart = FALSE;
|
---|
2585 | bool hadOldEnd = FALSE;
|
---|
2586 | bool leftSelection = FALSE;
|
---|
2587 | sel.swapped = FALSE;
|
---|
2588 | for ( ;; ) {
|
---|
2589 | if ( c == start )
|
---|
2590 | hadStart = TRUE;
|
---|
2591 | if ( c == end )
|
---|
2592 | hadEnd = TRUE;
|
---|
2593 | if ( c.paragraph() == start.paragraph() )
|
---|
2594 | hadStartParag = TRUE;
|
---|
2595 | if ( c.paragraph() == end.paragraph() )
|
---|
2596 | hadEndParag = TRUE;
|
---|
2597 | if ( c == sel.startCursor )
|
---|
2598 | hadOldStart = TRUE;
|
---|
2599 | if ( c == sel.endCursor )
|
---|
2600 | hadOldEnd = TRUE;
|
---|
2601 |
|
---|
2602 | if ( !sel.swapped &&
|
---|
2603 | ( hadEnd && !hadStart ||
|
---|
2604 | hadEnd && hadStart && start.paragraph() == end.paragraph() && start.index() > end.index() ) )
|
---|
2605 | sel.swapped = TRUE;
|
---|
2606 |
|
---|
2607 | if ( c == end && hadStartParag ||
|
---|
2608 | c == start && hadEndParag ) {
|
---|
2609 | QTextCursor tmp = c;
|
---|
2610 | tmp.restoreState();
|
---|
2611 | if ( tmp.paragraph() != c.paragraph() ) {
|
---|
2612 | int sstart = tmp.paragraph()->selectionStart( id );
|
---|
2613 | tmp.paragraph()->removeSelection( id );
|
---|
2614 | tmp.paragraph()->setSelection( id, sstart, tmp.index() );
|
---|
2615 | }
|
---|
2616 | }
|
---|
2617 |
|
---|
2618 | if ( inSelection &&
|
---|
2619 | ( c == end && hadStart || c == start && hadEnd ) )
|
---|
2620 | leftSelection = TRUE;
|
---|
2621 | else if ( !leftSelection && !inSelection && ( hadStart || hadEnd ) )
|
---|
2622 | inSelection = TRUE;
|
---|
2623 |
|
---|
2624 | bool noSelectionAnymore = hadOldStart && hadOldEnd && leftSelection && !inSelection && !c.paragraph()->hasSelection( id ) && c.atParagEnd();
|
---|
2625 | c.paragraph()->removeSelection( id );
|
---|
2626 | if ( inSelection ) {
|
---|
2627 | if ( c.paragraph() == start.paragraph() && start.paragraph() == end.paragraph() ) {
|
---|
2628 | c.paragraph()->setSelection( id, QMIN( start.index(), end.index() ), QMAX( start.index(), end.index() ) );
|
---|
2629 | } else if ( c.paragraph() == start.paragraph() && !hadEndParag ) {
|
---|
2630 | c.paragraph()->setSelection( id, start.index(), c.paragraph()->length() - 1 );
|
---|
2631 | } else if ( c.paragraph() == end.paragraph() && !hadStartParag ) {
|
---|
2632 | c.paragraph()->setSelection( id, end.index(), c.paragraph()->length() - 1 );
|
---|
2633 | } else if ( c.paragraph() == end.paragraph() && hadEndParag ) {
|
---|
2634 | c.paragraph()->setSelection( id, 0, end.index() );
|
---|
2635 | } else if ( c.paragraph() == start.paragraph() && hadStartParag ) {
|
---|
2636 | c.paragraph()->setSelection( id, 0, start.index() );
|
---|
2637 | } else {
|
---|
2638 | c.paragraph()->setSelection( id, 0, c.paragraph()->length() - 1 );
|
---|
2639 | }
|
---|
2640 | }
|
---|
2641 |
|
---|
2642 | if ( leftSelection )
|
---|
2643 | inSelection = FALSE;
|
---|
2644 |
|
---|
2645 | if ( noSelectionAnymore )
|
---|
2646 | break;
|
---|
2647 | // *ugle*hack optimization
|
---|
2648 | QTextParagraph *p = c.paragraph();
|
---|
2649 | if ( p->mightHaveCustomItems || p == start.paragraph() || p == end.paragraph() || p == lastParagraph() ) {
|
---|
2650 | c.gotoNextLetter();
|
---|
2651 | if ( p == lastParagraph() && c.atParagEnd() )
|
---|
2652 | break;
|
---|
2653 | } else {
|
---|
2654 | if ( p->document()->parent() )
|
---|
2655 | do {
|
---|
2656 | c.gotoNextLetter();
|
---|
2657 | } while ( c.paragraph() == p );
|
---|
2658 | else
|
---|
2659 | c.setParagraph( p->next() );
|
---|
2660 | }
|
---|
2661 | }
|
---|
2662 |
|
---|
2663 | if ( !sel.swapped )
|
---|
2664 | sel.startCursor.paragraph()->setSelection( id, sel.startCursor.index(), sel.startCursor.paragraph()->length() - 1 );
|
---|
2665 |
|
---|
2666 | sel.startCursor = start;
|
---|
2667 | sel.endCursor = end;
|
---|
2668 | if ( sel.startCursor.paragraph() == sel.endCursor.paragraph() )
|
---|
2669 | sel.swapped = sel.startCursor.index() > sel.endCursor.index();
|
---|
2670 |
|
---|
2671 | setSelectionEndHelper( id, sel, start, end );
|
---|
2672 |
|
---|
2673 | return TRUE;
|
---|
2674 | }
|
---|
2675 |
|
---|
2676 | void QTextDocument::selectAll( int id )
|
---|
2677 | {
|
---|
2678 | removeSelection( id );
|
---|
2679 |
|
---|
2680 | QTextDocumentSelection sel;
|
---|
2681 | sel.swapped = FALSE;
|
---|
2682 | QTextCursor c( this );
|
---|
2683 |
|
---|
2684 | c.setParagraph( fParag );
|
---|
2685 | c.setIndex( 0 );
|
---|
2686 | sel.startCursor = c;
|
---|
2687 |
|
---|
2688 | c.setParagraph( lParag );
|
---|
2689 | c.setIndex( lParag->length() - 1 );
|
---|
2690 | sel.endCursor = c;
|
---|
2691 |
|
---|
2692 | selections.insert( id, sel );
|
---|
2693 |
|
---|
2694 | QTextParagraph *p = fParag;
|
---|
2695 | while ( p ) {
|
---|
2696 | p->setSelection( id, 0, p->length() - 1 );
|
---|
2697 | p = p->next();
|
---|
2698 | }
|
---|
2699 |
|
---|
2700 | for ( QTextDocument *d = childList.first(); d; d = childList.next() )
|
---|
2701 | d->selectAll( id );
|
---|
2702 | }
|
---|
2703 |
|
---|
2704 | bool QTextDocument::removeSelection( int id )
|
---|
2705 | {
|
---|
2706 | if ( !selections.contains( id ) )
|
---|
2707 | return FALSE;
|
---|
2708 |
|
---|
2709 | QTextDocumentSelection &sel = selections[ id ];
|
---|
2710 |
|
---|
2711 | QTextCursor start = sel.swapped ? sel.endCursor : sel.startCursor;
|
---|
2712 | QTextCursor end = sel.swapped ? sel.startCursor : sel.endCursor;
|
---|
2713 | QTextParagraph* p = 0;
|
---|
2714 | while ( start != end ) {
|
---|
2715 | if ( p != start.paragraph() ) {
|
---|
2716 | p = start.paragraph();
|
---|
2717 | p->removeSelection( id );
|
---|
2718 | //### avoid endless loop by all means necessary, did somebody mention refactoring?
|
---|
2719 | if ( !parent() && p == lParag )
|
---|
2720 | break;
|
---|
2721 | }
|
---|
2722 | start.gotoNextLetter();
|
---|
2723 | }
|
---|
2724 | p = start.paragraph();
|
---|
2725 | p->removeSelection( id );
|
---|
2726 | selections.remove( id );
|
---|
2727 | return TRUE;
|
---|
2728 | }
|
---|
2729 |
|
---|
2730 | QString QTextDocument::selectedText( int id, bool asRichText ) const
|
---|
2731 | {
|
---|
2732 | QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( id );
|
---|
2733 | if ( it == selections.end() )
|
---|
2734 | return QString::null;
|
---|
2735 |
|
---|
2736 | QTextDocumentSelection sel = *it;
|
---|
2737 |
|
---|
2738 |
|
---|
2739 | QTextCursor c1 = sel.startCursor;
|
---|
2740 | QTextCursor c2 = sel.endCursor;
|
---|
2741 | if ( sel.swapped ) {
|
---|
2742 | c2 = sel.startCursor;
|
---|
2743 | c1 = sel.endCursor;
|
---|
2744 | }
|
---|
2745 |
|
---|
2746 | /* 3.0.3 improvement: Make it possible to get a reasonable
|
---|
2747 | selection inside a table. This approach is very conservative:
|
---|
2748 | make sure that both cursors have the same depth level and point
|
---|
2749 | to paragraphs within the same text document.
|
---|
2750 |
|
---|
2751 | Meaning if you select text in two table cells, you will get the
|
---|
2752 | entire table. This is still far better than the 3.0.2, where
|
---|
2753 | you always got the entire table.
|
---|
2754 |
|
---|
2755 | ### Fix this properly when refactoring
|
---|
2756 | */
|
---|
2757 | while ( c2.nestedDepth() > c1.nestedDepth() )
|
---|
2758 | c2.oneUp();
|
---|
2759 | while ( c1.nestedDepth() > c2.nestedDepth() )
|
---|
2760 | c1.oneUp();
|
---|
2761 | while ( c1.nestedDepth() && c2.nestedDepth() &&
|
---|
2762 | c1.paragraph()->document() != c2.paragraph()->document() ) {
|
---|
2763 | c1.oneUp();
|
---|
2764 | c2.oneUp();
|
---|
2765 | }
|
---|
2766 | // do not trust sel_swapped with tables. Fix this properly when refactoring as well
|
---|
2767 | if ( c1.paragraph()->paragId() > c2.paragraph()->paragId() ||
|
---|
2768 | (c1.paragraph() == c2.paragraph() && c1.index() > c2.index() ) ) {
|
---|
2769 | QTextCursor tmp = c1;
|
---|
2770 | c2 = c1;
|
---|
2771 | c1 = tmp;
|
---|
2772 | }
|
---|
2773 |
|
---|
2774 | // end selection 3.0.3 improvement
|
---|
2775 |
|
---|
2776 | if ( asRichText && !parent() ) {
|
---|
2777 | richTextExportStart = &c1;
|
---|
2778 | richTextExportEnd = &c2;
|
---|
2779 |
|
---|
2780 | QString sel = richText();
|
---|
2781 | int from = sel.find( "<!--StartFragment-->" );
|
---|
2782 | if ( from >= 0 ) {
|
---|
2783 | from += 20;
|
---|
2784 | // find the previous span and move it into the start fragment before we clip it
|
---|
2785 | QString prevspan;
|
---|
2786 | int pspan = sel.findRev( "<span", from-21 );
|
---|
2787 | if ( pspan > sel.findRev( "</span", from-21 ) ) {
|
---|
2788 | int spanend = sel.find( '>', pspan );
|
---|
2789 | prevspan = sel.mid( pspan, spanend - pspan + 1 );
|
---|
2790 | }
|
---|
2791 | int to = sel.findRev( "<!--EndFragment-->" );
|
---|
2792 | if ( from <= to )
|
---|
2793 | sel = "<!--StartFragment-->" + prevspan + sel.mid( from, to - from );
|
---|
2794 | }
|
---|
2795 | richTextExportStart = richTextExportEnd = 0;
|
---|
2796 | return sel;
|
---|
2797 | }
|
---|
2798 |
|
---|
2799 | QString s;
|
---|
2800 | if ( c1.paragraph() == c2.paragraph() ) {
|
---|
2801 | QTextParagraph *p = c1.paragraph();
|
---|
2802 | int end = c2.index();
|
---|
2803 | if ( p->at( QMAX( 0, end - 1 ) )->isCustom() )
|
---|
2804 | ++end;
|
---|
2805 | if ( !p->mightHaveCustomItems ) {
|
---|
2806 | s += p->string()->toString().mid( c1.index(), end - c1.index() );
|
---|
2807 | } else {
|
---|
2808 | for ( int i = c1.index(); i < end; ++i ) {
|
---|
2809 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
2810 | if ( p->at( i )->isCustom() ) {
|
---|
2811 | if ( p->at( i )->customItem()->isNested() ) {
|
---|
2812 | s += "\n";
|
---|
2813 | QTextTable *t = (QTextTable*)p->at( i )->customItem();
|
---|
2814 | QPtrList<QTextTableCell> cells = t->tableCells();
|
---|
2815 | for ( QTextTableCell *c = cells.first(); c; c = cells.next() )
|
---|
2816 | s += c->richText()->plainText() + "\n";
|
---|
2817 | s += "\n";
|
---|
2818 | }
|
---|
2819 | } else
|
---|
2820 | #endif
|
---|
2821 | {
|
---|
2822 | s += p->at( i )->c;
|
---|
2823 | }
|
---|
2824 | }
|
---|
2825 | }
|
---|
2826 | } else {
|
---|
2827 | QTextParagraph *p = c1.paragraph();
|
---|
2828 | int start = c1.index();
|
---|
2829 | while ( p ) {
|
---|
2830 | int end = p == c2.paragraph() ? c2.index() : p->length() - 1;
|
---|
2831 | if ( p == c2.paragraph() && p->at( QMAX( 0, end - 1 ) )->isCustom() )
|
---|
2832 | ++end;
|
---|
2833 | if ( !p->mightHaveCustomItems ) {
|
---|
2834 | s += p->string()->toString().mid( start, end - start );
|
---|
2835 | if ( p != c2.paragraph() )
|
---|
2836 | s += "\n";
|
---|
2837 | } else {
|
---|
2838 | for ( int i = start; i < end; ++i ) {
|
---|
2839 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
2840 | if ( p->at( i )->isCustom() ) {
|
---|
2841 | if ( p->at( i )->customItem()->isNested() ) {
|
---|
2842 | s += "\n";
|
---|
2843 | QTextTable *t = (QTextTable*)p->at( i )->customItem();
|
---|
2844 | QPtrList<QTextTableCell> cells = t->tableCells();
|
---|
2845 | for ( QTextTableCell *c = cells.first(); c; c = cells.next() )
|
---|
2846 | s += c->richText()->plainText() + "\n";
|
---|
2847 | s += "\n";
|
---|
2848 | }
|
---|
2849 | } else
|
---|
2850 | #endif
|
---|
2851 | {
|
---|
2852 | s += p->at( i )->c;
|
---|
2853 | }
|
---|
2854 | }
|
---|
2855 | }
|
---|
2856 | start = 0;
|
---|
2857 | if ( p == c2.paragraph() )
|
---|
2858 | break;
|
---|
2859 | p = p->next();
|
---|
2860 | }
|
---|
2861 | }
|
---|
2862 | // ### workaround for plain text export until we get proper
|
---|
2863 | // mime types: turn unicode line seperators into the more
|
---|
2864 | // widely understood \n. Makes copy and pasting code snipplets
|
---|
2865 | // from within Assistent possible
|
---|
2866 | QChar* uc = (QChar*) s.unicode();
|
---|
2867 | for ( uint ii = 0; ii < s.length(); ii++ )
|
---|
2868 | if ( uc[(int)ii] == QChar_linesep )
|
---|
2869 | uc[(int)ii] = QChar('\n');
|
---|
2870 | return s;
|
---|
2871 | }
|
---|
2872 |
|
---|
2873 | void QTextDocument::setFormat( int id, QTextFormat *f, int flags )
|
---|
2874 | {
|
---|
2875 | QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( id );
|
---|
2876 | if ( it == selections.end() )
|
---|
2877 | return;
|
---|
2878 |
|
---|
2879 | QTextDocumentSelection sel = *it;
|
---|
2880 |
|
---|
2881 | QTextCursor c1 = sel.startCursor;
|
---|
2882 | QTextCursor c2 = sel.endCursor;
|
---|
2883 | if ( sel.swapped ) {
|
---|
2884 | c2 = sel.startCursor;
|
---|
2885 | c1 = sel.endCursor;
|
---|
2886 | }
|
---|
2887 |
|
---|
2888 | c2.restoreState();
|
---|
2889 | c1.restoreState();
|
---|
2890 |
|
---|
2891 | if ( c1.paragraph() == c2.paragraph() ) {
|
---|
2892 | c1.paragraph()->setFormat( c1.index(), c2.index() - c1.index(), f, TRUE, flags );
|
---|
2893 | return;
|
---|
2894 | }
|
---|
2895 |
|
---|
2896 | c1.paragraph()->setFormat( c1.index(), c1.paragraph()->length() - c1.index(), f, TRUE, flags );
|
---|
2897 | QTextParagraph *p = c1.paragraph()->next();
|
---|
2898 | while ( p && p != c2.paragraph() ) {
|
---|
2899 | p->setFormat( 0, p->length(), f, TRUE, flags );
|
---|
2900 | p = p->next();
|
---|
2901 | }
|
---|
2902 | c2.paragraph()->setFormat( 0, c2.index(), f, TRUE, flags );
|
---|
2903 | }
|
---|
2904 |
|
---|
2905 | void QTextDocument::removeSelectedText( int id, QTextCursor *cursor )
|
---|
2906 | {
|
---|
2907 | QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
|
---|
2908 | if ( it == selections.end() )
|
---|
2909 | return;
|
---|
2910 |
|
---|
2911 | QTextDocumentSelection sel = *it;
|
---|
2912 | QTextCursor c1 = sel.startCursor;
|
---|
2913 | QTextCursor c2 = sel.endCursor;
|
---|
2914 | if ( sel.swapped ) {
|
---|
2915 | c2 = sel.startCursor;
|
---|
2916 | c1 = sel.endCursor;
|
---|
2917 | }
|
---|
2918 |
|
---|
2919 | // ### no support for editing tables yet
|
---|
2920 | if ( c1.nestedDepth() || c2.nestedDepth() )
|
---|
2921 | return;
|
---|
2922 |
|
---|
2923 | c2.restoreState();
|
---|
2924 | c1.restoreState();
|
---|
2925 |
|
---|
2926 | *cursor = c1;
|
---|
2927 | removeSelection( id );
|
---|
2928 |
|
---|
2929 | if ( c1.paragraph() == c2.paragraph() ) {
|
---|
2930 | c1.paragraph()->remove( c1.index(), c2.index() - c1.index() );
|
---|
2931 | return;
|
---|
2932 | }
|
---|
2933 |
|
---|
2934 | if ( c1.paragraph() == fParag && c1.index() == 0 &&
|
---|
2935 | c2.paragraph() == lParag && c2.index() == lParag->length() - 1 )
|
---|
2936 | cursor->setValid( FALSE );
|
---|
2937 |
|
---|
2938 | bool didGoLeft = FALSE;
|
---|
2939 | if ( c1.index() == 0 && c1.paragraph() != fParag ) {
|
---|
2940 | cursor->gotoPreviousLetter();
|
---|
2941 | didGoLeft = cursor->isValid();
|
---|
2942 | }
|
---|
2943 |
|
---|
2944 | c1.paragraph()->remove( c1.index(), c1.paragraph()->length() - 1 - c1.index() );
|
---|
2945 | QTextParagraph *p = c1.paragraph()->next();
|
---|
2946 | int dy = 0;
|
---|
2947 | QTextParagraph *tmp;
|
---|
2948 | while ( p && p != c2.paragraph() ) {
|
---|
2949 | tmp = p->next();
|
---|
2950 | dy -= p->rect().height();
|
---|
2951 | delete p;
|
---|
2952 | p = tmp;
|
---|
2953 | }
|
---|
2954 | c2.paragraph()->remove( 0, c2.index() );
|
---|
2955 | while ( p ) {
|
---|
2956 | p->move( dy );
|
---|
2957 | p->invalidate( 0 );
|
---|
2958 | p->setEndState( -1 );
|
---|
2959 | p = p->next();
|
---|
2960 | }
|
---|
2961 |
|
---|
2962 |
|
---|
2963 | c1.paragraph()->join( c2.paragraph() );
|
---|
2964 |
|
---|
2965 | if ( didGoLeft )
|
---|
2966 | cursor->gotoNextLetter();
|
---|
2967 | }
|
---|
2968 |
|
---|
2969 | void QTextDocument::indentSelection( int id )
|
---|
2970 | {
|
---|
2971 | QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
|
---|
2972 | if ( it == selections.end() )
|
---|
2973 | return;
|
---|
2974 |
|
---|
2975 | QTextDocumentSelection sel = *it;
|
---|
2976 | QTextParagraph *startParag = sel.startCursor.paragraph();
|
---|
2977 | QTextParagraph *endParag = sel.endCursor.paragraph();
|
---|
2978 | if ( sel.endCursor.paragraph()->paragId() < sel.startCursor.paragraph()->paragId() ) {
|
---|
2979 | endParag = sel.startCursor.paragraph();
|
---|
2980 | startParag = sel.endCursor.paragraph();
|
---|
2981 | }
|
---|
2982 |
|
---|
2983 | QTextParagraph *p = startParag;
|
---|
2984 | while ( p && p != endParag ) {
|
---|
2985 | p->indent();
|
---|
2986 | p = p->next();
|
---|
2987 | }
|
---|
2988 | }
|
---|
2989 |
|
---|
2990 | void QTextDocument::addCommand( QTextCommand *cmd )
|
---|
2991 | {
|
---|
2992 | commandHistory->addCommand( cmd );
|
---|
2993 | }
|
---|
2994 |
|
---|
2995 | QTextCursor *QTextDocument::undo( QTextCursor *c )
|
---|
2996 | {
|
---|
2997 | return commandHistory->undo( c );
|
---|
2998 | }
|
---|
2999 |
|
---|
3000 | QTextCursor *QTextDocument::redo( QTextCursor *c )
|
---|
3001 | {
|
---|
3002 | return commandHistory->redo( c );
|
---|
3003 | }
|
---|
3004 |
|
---|
3005 | bool QTextDocument::find( QTextCursor& cursor, const QString &expr, bool cs, bool wo, bool forward )
|
---|
3006 | {
|
---|
3007 | removeSelection( Standard );
|
---|
3008 | QTextParagraph *p = 0;
|
---|
3009 | if ( expr.isEmpty() )
|
---|
3010 | return FALSE;
|
---|
3011 | for (;;) {
|
---|
3012 | if ( p != cursor.paragraph() ) {
|
---|
3013 | p = cursor.paragraph();
|
---|
3014 | QString s = cursor.paragraph()->string()->toString();
|
---|
3015 | int start = cursor.index();
|
---|
3016 | for ( ;; ) {
|
---|
3017 | int res = forward ? s.find( expr, start, cs ) : s.findRev( expr, start, cs );
|
---|
3018 | int end = res + expr.length();
|
---|
3019 | if ( res == -1 || ( !forward && start <= res ) )
|
---|
3020 | break;
|
---|
3021 | if ( !wo || ( ( res == 0 || s[ res - 1 ].isSpace() || s[ res - 1 ].isPunct() ) &&
|
---|
3022 | ( end == (int)s.length() || s[ end ].isSpace() || s[ end ].isPunct() ) ) ) {
|
---|
3023 | removeSelection( Standard );
|
---|
3024 | cursor.setIndex( forward ? end : res );
|
---|
3025 | setSelectionStart( Standard, cursor );
|
---|
3026 | cursor.setIndex( forward ? res : end );
|
---|
3027 | setSelectionEnd( Standard, cursor );
|
---|
3028 | if ( !forward )
|
---|
3029 | cursor.setIndex( res );
|
---|
3030 | return TRUE;
|
---|
3031 | }
|
---|
3032 | start = res + (forward ? 1 : -1);
|
---|
3033 | }
|
---|
3034 | }
|
---|
3035 | if ( forward ) {
|
---|
3036 | if ( cursor.paragraph() == lastParagraph() && cursor.atParagEnd() )
|
---|
3037 | break;
|
---|
3038 | cursor.gotoNextLetter();
|
---|
3039 | } else {
|
---|
3040 | if ( cursor.paragraph() == firstParagraph() && cursor.atParagStart() )
|
---|
3041 | break;
|
---|
3042 | cursor.gotoPreviousLetter();
|
---|
3043 | }
|
---|
3044 | }
|
---|
3045 | return FALSE;
|
---|
3046 | }
|
---|
3047 |
|
---|
3048 | void QTextDocument::setTextFormat( Qt::TextFormat f )
|
---|
3049 | {
|
---|
3050 | txtFormat = f;
|
---|
3051 | if ( fParag == lParag && fParag->length() <= 1 )
|
---|
3052 | fParag->rtext = ( f == Qt::RichText );
|
---|
3053 | }
|
---|
3054 |
|
---|
3055 | Qt::TextFormat QTextDocument::textFormat() const
|
---|
3056 | {
|
---|
3057 | return txtFormat;
|
---|
3058 | }
|
---|
3059 |
|
---|
3060 | bool QTextDocument::inSelection( int selId, const QPoint &pos ) const
|
---|
3061 | {
|
---|
3062 | QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( selId );
|
---|
3063 | if ( it == selections.end() )
|
---|
3064 | return FALSE;
|
---|
3065 |
|
---|
3066 | QTextDocumentSelection sel = *it;
|
---|
3067 | QTextParagraph *startParag = sel.startCursor.paragraph();
|
---|
3068 | QTextParagraph *endParag = sel.endCursor.paragraph();
|
---|
3069 | if ( sel.startCursor.paragraph() == sel.endCursor.paragraph() &&
|
---|
3070 | sel.startCursor.paragraph()->selectionStart( selId ) == sel.endCursor.paragraph()->selectionEnd( selId ) )
|
---|
3071 | return FALSE;
|
---|
3072 | if ( sel.endCursor.paragraph()->paragId() < sel.startCursor.paragraph()->paragId() ) {
|
---|
3073 | endParag = sel.startCursor.paragraph();
|
---|
3074 | startParag = sel.endCursor.paragraph();
|
---|
3075 | }
|
---|
3076 |
|
---|
3077 | QTextParagraph *p = startParag;
|
---|
3078 | while ( p ) {
|
---|
3079 | if ( p->rect().contains( pos ) ) {
|
---|
3080 | bool inSel = FALSE;
|
---|
3081 | int selStart = p->selectionStart( selId );
|
---|
3082 | int selEnd = p->selectionEnd( selId );
|
---|
3083 | int y = 0;
|
---|
3084 | int h = 0;
|
---|
3085 | for ( int i = 0; i < p->length(); ++i ) {
|
---|
3086 | if ( i == selStart )
|
---|
3087 | inSel = TRUE;
|
---|
3088 | if ( i == selEnd )
|
---|
3089 | break;
|
---|
3090 | if ( p->at( i )->lineStart ) {
|
---|
3091 | y = (*p->lineStarts.find( i ))->y;
|
---|
3092 | h = (*p->lineStarts.find( i ))->h;
|
---|
3093 | }
|
---|
3094 | if ( pos.y() - p->rect().y() >= y && pos.y() - p->rect().y() <= y + h ) {
|
---|
3095 | if ( inSel && pos.x() >= p->at( i )->x &&
|
---|
3096 | pos.x() <= p->at( i )->x + p->at( i )->format()->width( p->at( i )->c ) )
|
---|
3097 | return TRUE;
|
---|
3098 | }
|
---|
3099 | }
|
---|
3100 | }
|
---|
3101 | if ( pos.y() < p->rect().y() )
|
---|
3102 | break;
|
---|
3103 | if ( p == endParag )
|
---|
3104 | break;
|
---|
3105 | p = p->next();
|
---|
3106 | }
|
---|
3107 |
|
---|
3108 | return FALSE;
|
---|
3109 | }
|
---|
3110 |
|
---|
3111 | void QTextDocument::doLayout( QPainter *p, int w )
|
---|
3112 | {
|
---|
3113 | minw = wused = 0;
|
---|
3114 | if ( !is_printer( p ) )
|
---|
3115 | p = 0;
|
---|
3116 | withoutDoubleBuffer = ( p != 0 );
|
---|
3117 | QPainter * oldPainter = QTextFormat::painter();
|
---|
3118 | QTextFormat::setPainter( p );
|
---|
3119 | flow_->setWidth( w );
|
---|
3120 | cw = w;
|
---|
3121 | vw = w;
|
---|
3122 | QTextParagraph *parag = fParag;
|
---|
3123 | while ( parag ) {
|
---|
3124 | parag->invalidate( 0 );
|
---|
3125 | if ( p )
|
---|
3126 | parag->adjustToPainter( p );
|
---|
3127 | parag->format();
|
---|
3128 | parag = parag->next();
|
---|
3129 | }
|
---|
3130 | QTextFormat::setPainter( oldPainter );
|
---|
3131 | }
|
---|
3132 |
|
---|
3133 | QPixmap *QTextDocument::bufferPixmap( const QSize &s )
|
---|
3134 | {
|
---|
3135 | if ( !buf_pixmap )
|
---|
3136 | buf_pixmap = new QPixmap( s.expandedTo( QSize(1,1) ) );
|
---|
3137 | else if ( buf_pixmap->size() != s )
|
---|
3138 | buf_pixmap->resize( s.expandedTo( buf_pixmap->size() ) );
|
---|
3139 | return buf_pixmap;
|
---|
3140 | }
|
---|
3141 |
|
---|
3142 | void QTextDocument::draw( QPainter *p, const QRect &rect, const QColorGroup &cg, const QBrush *paper )
|
---|
3143 | {
|
---|
3144 | if ( !firstParagraph() )
|
---|
3145 | return;
|
---|
3146 |
|
---|
3147 | if ( paper ) {
|
---|
3148 | p->setBrushOrigin( -int( p->translationX() ),
|
---|
3149 | -int( p->translationY() ) );
|
---|
3150 |
|
---|
3151 | p->fillRect( rect, *paper );
|
---|
3152 | }
|
---|
3153 |
|
---|
3154 | QPainter * oldPainter = QTextFormat::painter();
|
---|
3155 | QTextFormat::setPainter( p );
|
---|
3156 |
|
---|
3157 | if ( formatCollection()->defaultFormat()->color() != cg.text() )
|
---|
3158 | setDefaultFormat( formatCollection()->defaultFormat()->font(), cg.text() );
|
---|
3159 |
|
---|
3160 | QTextParagraph *parag = firstParagraph();
|
---|
3161 | while ( parag ) {
|
---|
3162 | if ( !parag->isValid() )
|
---|
3163 | parag->format();
|
---|
3164 | int y = parag->rect().y();
|
---|
3165 | QRect pr( parag->rect() );
|
---|
3166 | pr.setX( 0 );
|
---|
3167 | pr.setWidth( QWIDGETSIZE_MAX );
|
---|
3168 | if ( !rect.isNull() && !rect.intersects( pr ) ) {
|
---|
3169 | parag = parag->next();
|
---|
3170 | continue;
|
---|
3171 | }
|
---|
3172 | p->translate( 0, y );
|
---|
3173 | if ( rect.isValid() )
|
---|
3174 | parag->paint( *p, cg, 0, FALSE, rect.x(), rect.y(), rect.width(), rect.height() );
|
---|
3175 | else
|
---|
3176 | parag->paint( *p, cg, 0, FALSE );
|
---|
3177 | p->translate( 0, -y );
|
---|
3178 | parag = parag->next();
|
---|
3179 | if ( !flow()->isEmpty() )
|
---|
3180 | flow()->drawFloatingItems( p, rect.x(), rect.y(), rect.width(), rect.height(), cg, FALSE );
|
---|
3181 | }
|
---|
3182 | QTextFormat::setPainter(oldPainter);
|
---|
3183 | }
|
---|
3184 |
|
---|
3185 | void QTextDocument::drawParagraph( QPainter *p, QTextParagraph *parag, int cx, int cy, int cw, int ch,
|
---|
3186 | QPixmap *&doubleBuffer, const QColorGroup &cg,
|
---|
3187 | bool drawCursor, QTextCursor *cursor, bool resetChanged )
|
---|
3188 | {
|
---|
3189 | QPainter *painter = 0;
|
---|
3190 | if ( resetChanged )
|
---|
3191 | parag->setChanged( FALSE );
|
---|
3192 | QRect ir( parag->rect() );
|
---|
3193 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
3194 | if (!parag->tableCell())
|
---|
3195 | #endif
|
---|
3196 | ir.setWidth(width());
|
---|
3197 |
|
---|
3198 | bool uDoubleBuffer = useDoubleBuffer( parag, p );
|
---|
3199 |
|
---|
3200 | if ( uDoubleBuffer ) {
|
---|
3201 | painter = new QPainter;
|
---|
3202 | if ( cx >= 0 && cy >= 0 )
|
---|
3203 | ir = ir.intersect( QRect( cx, cy, cw, ch ) );
|
---|
3204 | if ( !doubleBuffer ||
|
---|
3205 | ir.width() > doubleBuffer->width() ||
|
---|
3206 | ir.height() > doubleBuffer->height() ) {
|
---|
3207 | doubleBuffer = bufferPixmap( ir.size() );
|
---|
3208 | painter->begin( doubleBuffer );
|
---|
3209 | } else {
|
---|
3210 | painter->begin( doubleBuffer );
|
---|
3211 | }
|
---|
3212 | } else {
|
---|
3213 | painter = p;
|
---|
3214 | painter->translate( ir.x(), ir.y() );
|
---|
3215 | }
|
---|
3216 |
|
---|
3217 | painter->setBrushOrigin( -ir.x(), -ir.y() );
|
---|
3218 |
|
---|
3219 | if ( uDoubleBuffer || is_printer( painter ) )
|
---|
3220 | painter->fillRect( QRect( 0, 0, ir.width(), ir.height() ), parag->backgroundBrush( cg ) );
|
---|
3221 | else if ( cursor && cursor->paragraph() == parag )
|
---|
3222 | painter->fillRect( QRect( parag->at( cursor->index() )->x, 0, 2, ir.height() ),
|
---|
3223 | parag->backgroundBrush( cg ) );
|
---|
3224 |
|
---|
3225 | painter->translate( -( ir.x() - parag->rect().x() ),
|
---|
3226 | -( ir.y() - parag->rect().y() ) );
|
---|
3227 | parag->paint( *painter, cg, drawCursor ? cursor : 0, TRUE, cx, cy, cw, ch );
|
---|
3228 |
|
---|
3229 | if ( uDoubleBuffer ) {
|
---|
3230 | delete painter;
|
---|
3231 | painter = 0;
|
---|
3232 | p->drawPixmap( ir.topLeft(), *doubleBuffer, QRect( QPoint( 0, 0 ), ir.size() ) );
|
---|
3233 | } else {
|
---|
3234 | painter->translate( -ir.x(), -ir.y() );
|
---|
3235 | }
|
---|
3236 |
|
---|
3237 | parag->document()->nextDoubleBuffered = FALSE;
|
---|
3238 | }
|
---|
3239 |
|
---|
3240 | QTextParagraph *QTextDocument::draw( QPainter *p, int cx, int cy, int cw, int ch, const QColorGroup &cg,
|
---|
3241 | bool onlyChanged, bool drawCursor, QTextCursor *cursor, bool resetChanged )
|
---|
3242 | {
|
---|
3243 | if ( withoutDoubleBuffer || par && par->withoutDoubleBuffer ) {
|
---|
3244 | withoutDoubleBuffer = TRUE;
|
---|
3245 | QRect r;
|
---|
3246 | draw( p, r, cg );
|
---|
3247 | return 0;
|
---|
3248 | }
|
---|
3249 | withoutDoubleBuffer = FALSE;
|
---|
3250 |
|
---|
3251 | if ( !firstParagraph() )
|
---|
3252 | return 0;
|
---|
3253 |
|
---|
3254 | QPainter * oldPainter = QTextFormat::painter();
|
---|
3255 | QTextFormat::setPainter( p );
|
---|
3256 | if ( formatCollection()->defaultFormat()->color() != cg.text() )
|
---|
3257 | setDefaultFormat( formatCollection()->defaultFormat()->font(), cg.text() );
|
---|
3258 |
|
---|
3259 | if ( cx < 0 && cy < 0 ) {
|
---|
3260 | cx = 0;
|
---|
3261 | cy = 0;
|
---|
3262 | cw = width();
|
---|
3263 | ch = height();
|
---|
3264 | }
|
---|
3265 |
|
---|
3266 | QTextParagraph *lastFormatted = 0;
|
---|
3267 | QTextParagraph *parag = firstParagraph();
|
---|
3268 |
|
---|
3269 | QPixmap *doubleBuffer = 0;
|
---|
3270 |
|
---|
3271 | while ( parag ) {
|
---|
3272 | lastFormatted = parag;
|
---|
3273 | if ( !parag->isValid() )
|
---|
3274 | parag->format();
|
---|
3275 |
|
---|
3276 | QRect pr = parag->rect();
|
---|
3277 | pr.setWidth( parag->document()->width() );
|
---|
3278 | if ( pr.y() > cy + ch )
|
---|
3279 | goto floating;
|
---|
3280 | QRect clipr( cx, cy, cw, ch );
|
---|
3281 | if ( !pr.intersects( clipr ) || ( onlyChanged && !parag->hasChanged() ) ) {
|
---|
3282 | pr.setWidth( parag->document()->width() );
|
---|
3283 | parag = parag->next();
|
---|
3284 | continue;
|
---|
3285 | }
|
---|
3286 |
|
---|
3287 | drawParagraph( p, parag, cx, cy, cw, ch, doubleBuffer, cg, drawCursor, cursor, resetChanged );
|
---|
3288 | parag = parag->next();
|
---|
3289 | }
|
---|
3290 |
|
---|
3291 | parag = lastParagraph();
|
---|
3292 |
|
---|
3293 | floating:
|
---|
3294 | if ( parag->rect().y() + parag->rect().height() < parag->document()->height() ) {
|
---|
3295 | if ( !parag->document()->parent() ) {
|
---|
3296 | QRect fillRect = QRect( 0, parag->rect().y() + parag->rect().height(), parag->document()->width(),
|
---|
3297 | parag->document()->height() - ( parag->rect().y() + parag->rect().height() ) );
|
---|
3298 | if ( QRect( cx, cy, cw, ch ).intersects( fillRect ) )
|
---|
3299 | p->fillRect( fillRect, cg.brush( QColorGroup::Base ) );
|
---|
3300 | }
|
---|
3301 | if ( !flow()->isEmpty() ) {
|
---|
3302 | QRect cr( cx, cy, cw, ch );
|
---|
3303 | flow()->drawFloatingItems( p, cr.x(), cr.y(), cr.width(), cr.height(), cg, FALSE );
|
---|
3304 | }
|
---|
3305 | }
|
---|
3306 |
|
---|
3307 | if ( buf_pixmap && buf_pixmap->height() > 300 ) {
|
---|
3308 | delete buf_pixmap;
|
---|
3309 | buf_pixmap = 0;
|
---|
3310 | }
|
---|
3311 |
|
---|
3312 | QTextFormat::setPainter(oldPainter);
|
---|
3313 | return lastFormatted;
|
---|
3314 | }
|
---|
3315 |
|
---|
3316 | /*
|
---|
3317 | #### this function only sets the default font size in the format collection
|
---|
3318 | */
|
---|
3319 | void QTextDocument::setDefaultFormat( const QFont &font, const QColor &color )
|
---|
3320 | {
|
---|
3321 | bool reformat = font != fCollection->defaultFormat()->font();
|
---|
3322 | for ( QTextDocument *d = childList.first(); d; d = childList.next() )
|
---|
3323 | d->setDefaultFormat( font, color );
|
---|
3324 | fCollection->updateDefaultFormat( font, color, sheet_ );
|
---|
3325 |
|
---|
3326 | if ( !reformat )
|
---|
3327 | return;
|
---|
3328 | tStopWidth = formatCollection()->defaultFormat()->width( 'x' ) * 8;
|
---|
3329 |
|
---|
3330 | // invalidate paragraphs and custom items
|
---|
3331 | QTextParagraph *p = fParag;
|
---|
3332 | while ( p ) {
|
---|
3333 | p->invalidate( 0 );
|
---|
3334 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
3335 | for ( int i = 0; i < p->length() - 1; ++i )
|
---|
3336 | if ( p->at( i )->isCustom() )
|
---|
3337 | p->at( i )->customItem()->invalidate();
|
---|
3338 | #endif
|
---|
3339 | p = p->next();
|
---|
3340 | }
|
---|
3341 | }
|
---|
3342 |
|
---|
3343 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
3344 | void QTextDocument::registerCustomItem( QTextCustomItem *i, QTextParagraph *p )
|
---|
3345 | {
|
---|
3346 | if ( i && i->placement() != QTextCustomItem::PlaceInline ) {
|
---|
3347 | flow_->registerFloatingItem( i );
|
---|
3348 | p->registerFloatingItem( i );
|
---|
3349 | i->setParagraph( p );
|
---|
3350 | }
|
---|
3351 | p->mightHaveCustomItems = mightHaveCustomItems = TRUE;
|
---|
3352 | }
|
---|
3353 |
|
---|
3354 | void QTextDocument::unregisterCustomItem( QTextCustomItem *i, QTextParagraph *p )
|
---|
3355 | {
|
---|
3356 | p->unregisterFloatingItem( i );
|
---|
3357 | i->setParagraph( 0 );
|
---|
3358 | flow_->unregisterFloatingItem( i );
|
---|
3359 | }
|
---|
3360 | #endif
|
---|
3361 |
|
---|
3362 | bool QTextDocument::hasFocusParagraph() const
|
---|
3363 | {
|
---|
3364 | return !!focusIndicator.parag;
|
---|
3365 | }
|
---|
3366 |
|
---|
3367 | QString QTextDocument::focusHref() const
|
---|
3368 | {
|
---|
3369 | return focusIndicator.href;
|
---|
3370 | }
|
---|
3371 |
|
---|
3372 | QString QTextDocument::focusName() const
|
---|
3373 | {
|
---|
3374 | return focusIndicator.name;
|
---|
3375 | }
|
---|
3376 |
|
---|
3377 | bool QTextDocument::focusNextPrevChild( bool next )
|
---|
3378 | {
|
---|
3379 | if ( !focusIndicator.parag ) {
|
---|
3380 | if ( next ) {
|
---|
3381 | focusIndicator.parag = fParag;
|
---|
3382 | focusIndicator.start = 0;
|
---|
3383 | focusIndicator.len = 0;
|
---|
3384 | } else {
|
---|
3385 | focusIndicator.parag = lParag;
|
---|
3386 | focusIndicator.start = lParag->length();
|
---|
3387 | focusIndicator.len = 0;
|
---|
3388 | }
|
---|
3389 | } else {
|
---|
3390 | focusIndicator.parag->setChanged( TRUE );
|
---|
3391 | }
|
---|
3392 | focusIndicator.href = QString::null;
|
---|
3393 | focusIndicator.name = QString::null;
|
---|
3394 |
|
---|
3395 | if ( next ) {
|
---|
3396 | QTextParagraph *p = focusIndicator.parag;
|
---|
3397 | int index = focusIndicator.start + focusIndicator.len;
|
---|
3398 | while ( p ) {
|
---|
3399 | for ( int i = index; i < p->length(); ++i ) {
|
---|
3400 | if ( p->at( i )->isAnchor() ) {
|
---|
3401 | p->setChanged( TRUE );
|
---|
3402 | focusIndicator.parag = p;
|
---|
3403 | focusIndicator.start = i;
|
---|
3404 | focusIndicator.len = 0;
|
---|
3405 | focusIndicator.href = p->at( i )->anchorHref();
|
---|
3406 | focusIndicator.name = p->at( i )->anchorName();
|
---|
3407 | while ( i < p->length() ) {
|
---|
3408 | if ( !p->at( i )->isAnchor() )
|
---|
3409 | return TRUE;
|
---|
3410 | focusIndicator.len++;
|
---|
3411 | i++;
|
---|
3412 | }
|
---|
3413 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
3414 | } else if ( p->at( i )->isCustom() ) {
|
---|
3415 | if ( p->at( i )->customItem()->isNested() ) {
|
---|
3416 | QTextTable *t = (QTextTable*)p->at( i )->customItem();
|
---|
3417 | QPtrList<QTextTableCell> cells = t->tableCells();
|
---|
3418 | // first try to continue
|
---|
3419 | QTextTableCell *c;
|
---|
3420 | bool resetCells = TRUE;
|
---|
3421 | for ( c = cells.first(); c; c = cells.next() ) {
|
---|
3422 | if ( c->richText()->hasFocusParagraph() ) {
|
---|
3423 | if ( c->richText()->focusNextPrevChild( next ) ) {
|
---|
3424 | p->setChanged( TRUE );
|
---|
3425 | focusIndicator.parag = p;
|
---|
3426 | focusIndicator.start = i;
|
---|
3427 | focusIndicator.len = 0;
|
---|
3428 | focusIndicator.href = c->richText()->focusHref();
|
---|
3429 | focusIndicator.name = c->richText()->focusName();
|
---|
3430 | return TRUE;
|
---|
3431 | } else {
|
---|
3432 | resetCells = FALSE;
|
---|
3433 | c = cells.next();
|
---|
3434 | break;
|
---|
3435 | }
|
---|
3436 | }
|
---|
3437 | }
|
---|
3438 | // now really try
|
---|
3439 | if ( resetCells )
|
---|
3440 | c = cells.first();
|
---|
3441 | for ( ; c; c = cells.next() ) {
|
---|
3442 | if ( c->richText()->focusNextPrevChild( next ) ) {
|
---|
3443 | p->setChanged( TRUE );
|
---|
3444 | focusIndicator.parag = p;
|
---|
3445 | focusIndicator.start = i;
|
---|
3446 | focusIndicator.len = 0;
|
---|
3447 | focusIndicator.href = c->richText()->focusHref();
|
---|
3448 | focusIndicator.name = c->richText()->focusName();
|
---|
3449 | return TRUE;
|
---|
3450 | }
|
---|
3451 | }
|
---|
3452 | }
|
---|
3453 | #endif
|
---|
3454 | }
|
---|
3455 | }
|
---|
3456 | index = 0;
|
---|
3457 | p = p->next();
|
---|
3458 | }
|
---|
3459 | } else {
|
---|
3460 | QTextParagraph *p = focusIndicator.parag;
|
---|
3461 | int index = focusIndicator.start - 1;
|
---|
3462 | if ( focusIndicator.len == 0 && index < focusIndicator.parag->length() - 1 )
|
---|
3463 | index++;
|
---|
3464 | while ( p ) {
|
---|
3465 | for ( int i = index; i >= 0; --i ) {
|
---|
3466 | if ( p->at( i )->isAnchor() ) {
|
---|
3467 | p->setChanged( TRUE );
|
---|
3468 | focusIndicator.parag = p;
|
---|
3469 | focusIndicator.start = i;
|
---|
3470 | focusIndicator.len = 0;
|
---|
3471 | focusIndicator.href = p->at( i )->anchorHref();
|
---|
3472 | focusIndicator.name = p->at( i )->anchorName();
|
---|
3473 | while ( i >= -1 ) {
|
---|
3474 | if ( i < 0 || !p->at( i )->isAnchor() ) {
|
---|
3475 | focusIndicator.start++;
|
---|
3476 | return TRUE;
|
---|
3477 | }
|
---|
3478 | if ( i < 0 )
|
---|
3479 | break;
|
---|
3480 | focusIndicator.len++;
|
---|
3481 | focusIndicator.start--;
|
---|
3482 | i--;
|
---|
3483 | }
|
---|
3484 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
3485 | } else if ( p->at( i )->isCustom() ) {
|
---|
3486 | if ( p->at( i )->customItem()->isNested() ) {
|
---|
3487 | QTextTable *t = (QTextTable*)p->at( i )->customItem();
|
---|
3488 | QPtrList<QTextTableCell> cells = t->tableCells();
|
---|
3489 | // first try to continue
|
---|
3490 | QTextTableCell *c;
|
---|
3491 | bool resetCells = TRUE;
|
---|
3492 | for ( c = cells.last(); c; c = cells.prev() ) {
|
---|
3493 | if ( c->richText()->hasFocusParagraph() ) {
|
---|
3494 | if ( c->richText()->focusNextPrevChild( next ) ) {
|
---|
3495 | p->setChanged( TRUE );
|
---|
3496 | focusIndicator.parag = p;
|
---|
3497 | focusIndicator.start = i;
|
---|
3498 | focusIndicator.len = 0;
|
---|
3499 | focusIndicator.href = c->richText()->focusHref();
|
---|
3500 | focusIndicator.name = c->richText()->focusName();
|
---|
3501 | return TRUE;
|
---|
3502 | } else {
|
---|
3503 | resetCells = FALSE;
|
---|
3504 | c = cells.prev();
|
---|
3505 | break;
|
---|
3506 | }
|
---|
3507 | }
|
---|
3508 | if ( cells.at() == 0 )
|
---|
3509 | break;
|
---|
3510 | }
|
---|
3511 | // now really try
|
---|
3512 | if ( resetCells )
|
---|
3513 | c = cells.last();
|
---|
3514 | for ( ; c; c = cells.prev() ) {
|
---|
3515 | if ( c->richText()->focusNextPrevChild( next ) ) {
|
---|
3516 | p->setChanged( TRUE );
|
---|
3517 | focusIndicator.parag = p;
|
---|
3518 | focusIndicator.start = i;
|
---|
3519 | focusIndicator.len = 0;
|
---|
3520 | focusIndicator.href = c->richText()->focusHref();
|
---|
3521 | focusIndicator.name = c->richText()->focusName();
|
---|
3522 | return TRUE;
|
---|
3523 | }
|
---|
3524 | if ( cells.at() == 0 )
|
---|
3525 | break;
|
---|
3526 | }
|
---|
3527 | }
|
---|
3528 | #endif
|
---|
3529 | }
|
---|
3530 | }
|
---|
3531 | p = p->prev();
|
---|
3532 | if ( p )
|
---|
3533 | index = p->length() - 1;
|
---|
3534 | }
|
---|
3535 | }
|
---|
3536 |
|
---|
3537 | focusIndicator.parag = 0;
|
---|
3538 |
|
---|
3539 | return FALSE;
|
---|
3540 | }
|
---|
3541 |
|
---|
3542 | int QTextDocument::length() const
|
---|
3543 | {
|
---|
3544 | int l = -1;
|
---|
3545 | QTextParagraph *p = fParag;
|
---|
3546 | while ( p ) {
|
---|
3547 | l += p->length();
|
---|
3548 | p = p->next();
|
---|
3549 | }
|
---|
3550 | return QMAX(0,l);
|
---|
3551 | }
|
---|
3552 |
|
---|
3553 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
3554 |
|
---|
3555 | int QTextFormat::width( const QChar &c ) const
|
---|
3556 | {
|
---|
3557 | if ( c.unicode() == 0xad ) // soft hyphen
|
---|
3558 | return 0;
|
---|
3559 | if ( !pntr || !pntr->isActive() ) {
|
---|
3560 | if ( c == '\t' )
|
---|
3561 | return fm.width( ' ' );
|
---|
3562 | if ( ha == AlignNormal ) {
|
---|
3563 | int w;
|
---|
3564 | if ( c.row() )
|
---|
3565 | w = fm.width( c );
|
---|
3566 | else
|
---|
3567 | w = widths[ c.unicode() ];
|
---|
3568 | if ( w == 0 && !c.row() ) {
|
---|
3569 | w = fm.width( c );
|
---|
3570 | ( (QTextFormat*)this )->widths[ c.unicode() ] = w;
|
---|
3571 | }
|
---|
3572 | return w;
|
---|
3573 | } else {
|
---|
3574 | QFont f( fn );
|
---|
3575 | if ( usePixelSizes )
|
---|
3576 | f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
|
---|
3577 | else
|
---|
3578 | f.setPointSize( ( f.pointSize() * 2 ) / 3 );
|
---|
3579 | QFontMetrics fm_( f );
|
---|
3580 | return fm_.width( c );
|
---|
3581 | }
|
---|
3582 | }
|
---|
3583 |
|
---|
3584 | QFont f( fn );
|
---|
3585 | if ( ha != AlignNormal ) {
|
---|
3586 | if ( usePixelSizes )
|
---|
3587 | f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
|
---|
3588 | else
|
---|
3589 | f.setPointSize( ( f.pointSize() * 2 ) / 3 );
|
---|
3590 | }
|
---|
3591 | applyFont( f );
|
---|
3592 |
|
---|
3593 | return pntr_fm->width( c );
|
---|
3594 | }
|
---|
3595 |
|
---|
3596 | int QTextFormat::width( const QString &str, int pos ) const
|
---|
3597 | {
|
---|
3598 | int w = 0;
|
---|
3599 | if ( str.unicode()[ pos ].unicode() == 0xad )
|
---|
3600 | return w;
|
---|
3601 | if ( !pntr || !pntr->isActive() ) {
|
---|
3602 | if ( ha == AlignNormal ) {
|
---|
3603 | w = fm.charWidth( str, pos );
|
---|
3604 | } else {
|
---|
3605 | QFont f( fn );
|
---|
3606 | if ( usePixelSizes )
|
---|
3607 | f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
|
---|
3608 | else
|
---|
3609 | f.setPointSize( ( f.pointSize() * 2 ) / 3 );
|
---|
3610 | QFontMetrics fm_( f );
|
---|
3611 | w = fm_.charWidth( str, pos );
|
---|
3612 | }
|
---|
3613 | } else {
|
---|
3614 | QFont f( fn );
|
---|
3615 | if ( ha != AlignNormal ) {
|
---|
3616 | if ( usePixelSizes )
|
---|
3617 | f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
|
---|
3618 | else
|
---|
3619 | f.setPointSize( ( f.pointSize() * 2 ) / 3 );
|
---|
3620 | }
|
---|
3621 | applyFont( f );
|
---|
3622 | w = pntr_fm->charWidth( str, pos );
|
---|
3623 | }
|
---|
3624 | return w;
|
---|
3625 | }
|
---|
3626 |
|
---|
3627 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
3628 |
|
---|
3629 | QTextString::QTextString()
|
---|
3630 | {
|
---|
3631 | bidiDirty = TRUE;
|
---|
3632 | bidi = FALSE;
|
---|
3633 | rightToLeft = FALSE;
|
---|
3634 | dir = QChar::DirON;
|
---|
3635 | }
|
---|
3636 |
|
---|
3637 | QTextString::QTextString( const QTextString &s )
|
---|
3638 | {
|
---|
3639 | bidiDirty = TRUE;
|
---|
3640 | bidi = s.bidi;
|
---|
3641 | rightToLeft = s.rightToLeft;
|
---|
3642 | dir = s.dir;
|
---|
3643 | data = s.data;
|
---|
3644 | data.detach();
|
---|
3645 | for ( int i = 0; i < (int)data.size(); ++i ) {
|
---|
3646 | QTextFormat *f = data[i].format();
|
---|
3647 | if ( f )
|
---|
3648 | f->addRef();
|
---|
3649 | }
|
---|
3650 | }
|
---|
3651 |
|
---|
3652 | void QTextString::insert( int index, const QString &s, QTextFormat *f )
|
---|
3653 | {
|
---|
3654 | insert( index, s.unicode(), s.length(), f );
|
---|
3655 | }
|
---|
3656 |
|
---|
3657 | void QTextString::insert( int index, const QChar *unicode, int len, QTextFormat *f )
|
---|
3658 | {
|
---|
3659 | int os = data.size();
|
---|
3660 | data.resize( data.size() + len, QGArray::SpeedOptim );
|
---|
3661 | if ( index < os ) {
|
---|
3662 | memmove( data.data() + index + len, data.data() + index,
|
---|
3663 | sizeof( QTextStringChar ) * ( os - index ) );
|
---|
3664 | }
|
---|
3665 | QTextStringChar *ch = data.data() + index;
|
---|
3666 | for ( int i = 0; i < len; ++i ) {
|
---|
3667 | ch->x = 0;
|
---|
3668 | ch->lineStart = 0;
|
---|
3669 | ch->d.format = 0;
|
---|
3670 | ch->nobreak = FALSE;
|
---|
3671 | ch->type = QTextStringChar::Regular;
|
---|
3672 | ch->d.format = f;
|
---|
3673 | ch->rightToLeft = 0;
|
---|
3674 | ch->c = unicode[i];
|
---|
3675 | ++ch;
|
---|
3676 | }
|
---|
3677 | bidiDirty = TRUE;
|
---|
3678 | }
|
---|
3679 |
|
---|
3680 | QTextString::~QTextString()
|
---|
3681 | {
|
---|
3682 | clear();
|
---|
3683 | }
|
---|
3684 |
|
---|
3685 | void QTextString::insert( int index, QTextStringChar *c, bool doAddRefFormat )
|
---|
3686 | {
|
---|
3687 | int os = data.size();
|
---|
3688 | data.resize( data.size() + 1, QGArray::SpeedOptim );
|
---|
3689 | if ( index < os ) {
|
---|
3690 | memmove( data.data() + index + 1, data.data() + index,
|
---|
3691 | sizeof( QTextStringChar ) * ( os - index ) );
|
---|
3692 | }
|
---|
3693 | QTextStringChar &ch = data[ (int)index ];
|
---|
3694 | ch.c = c->c;
|
---|
3695 | ch.x = 0;
|
---|
3696 | ch.lineStart = 0;
|
---|
3697 | ch.rightToLeft = 0;
|
---|
3698 | ch.d.format = 0;
|
---|
3699 | ch.type = QTextStringChar::Regular;
|
---|
3700 | ch.nobreak = FALSE;
|
---|
3701 | if ( doAddRefFormat && c->format() )
|
---|
3702 | c->format()->addRef();
|
---|
3703 | ch.setFormat( c->format() );
|
---|
3704 | bidiDirty = TRUE;
|
---|
3705 | }
|
---|
3706 |
|
---|
3707 | void QTextString::truncate( int index )
|
---|
3708 | {
|
---|
3709 | index = QMAX( index, 0 );
|
---|
3710 | index = QMIN( index, (int)data.size() - 1 );
|
---|
3711 | if ( index < (int)data.size() ) {
|
---|
3712 | for ( int i = index + 1; i < (int)data.size(); ++i ) {
|
---|
3713 | QTextStringChar &ch = data[ i ];
|
---|
3714 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
3715 | if ( !(ch.type == QTextStringChar::Regular) ) {
|
---|
3716 | delete ch.customItem();
|
---|
3717 | if ( ch.d.custom->format )
|
---|
3718 | ch.d.custom->format->removeRef();
|
---|
3719 | delete ch.d.custom;
|
---|
3720 | ch.d.custom = 0;
|
---|
3721 | } else
|
---|
3722 | #endif
|
---|
3723 | if ( ch.format() ) {
|
---|
3724 | ch.format()->removeRef();
|
---|
3725 | }
|
---|
3726 | }
|
---|
3727 | }
|
---|
3728 | data.truncate( index );
|
---|
3729 | bidiDirty = TRUE;
|
---|
3730 | }
|
---|
3731 |
|
---|
3732 | void QTextString::remove( int index, int len )
|
---|
3733 | {
|
---|
3734 | for ( int i = index; i < (int)data.size() && i - index < len; ++i ) {
|
---|
3735 | QTextStringChar &ch = data[ i ];
|
---|
3736 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
3737 | if ( !(ch.type == QTextStringChar::Regular) ) {
|
---|
3738 | delete ch.customItem();
|
---|
3739 | if ( ch.d.custom->format )
|
---|
3740 | ch.d.custom->format->removeRef();
|
---|
3741 | delete ch.d.custom;
|
---|
3742 | ch.d.custom = 0;
|
---|
3743 | } else
|
---|
3744 | #endif
|
---|
3745 | if ( ch.format() ) {
|
---|
3746 | ch.format()->removeRef();
|
---|
3747 | }
|
---|
3748 | }
|
---|
3749 | memmove( data.data() + index, data.data() + index + len,
|
---|
3750 | sizeof( QTextStringChar ) * ( data.size() - index - len ) );
|
---|
3751 | data.resize( data.size() - len, QGArray::SpeedOptim );
|
---|
3752 | bidiDirty = TRUE;
|
---|
3753 | }
|
---|
3754 |
|
---|
3755 | void QTextString::clear()
|
---|
3756 | {
|
---|
3757 | for ( int i = 0; i < (int)data.count(); ++i ) {
|
---|
3758 | QTextStringChar &ch = data[ i ];
|
---|
3759 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
3760 | if ( !(ch.type == QTextStringChar::Regular) ) {
|
---|
3761 | if ( ch.customItem() && ch.customItem()->placement() == QTextCustomItem::PlaceInline )
|
---|
3762 | delete ch.customItem();
|
---|
3763 | if ( ch.d.custom->format )
|
---|
3764 | ch.d.custom->format->removeRef();
|
---|
3765 | delete ch.d.custom;
|
---|
3766 | ch.d.custom = 0;
|
---|
3767 | } else
|
---|
3768 | #endif
|
---|
3769 | if ( ch.format() ) {
|
---|
3770 | ch.format()->removeRef();
|
---|
3771 | }
|
---|
3772 | }
|
---|
3773 | data.resize( 0 );
|
---|
3774 | bidiDirty = TRUE;
|
---|
3775 | }
|
---|
3776 |
|
---|
3777 | void QTextString::setFormat( int index, QTextFormat *f, bool useCollection )
|
---|
3778 | {
|
---|
3779 | QTextStringChar &ch = data[ index ];
|
---|
3780 | if ( useCollection && ch.format() )
|
---|
3781 | ch.format()->removeRef();
|
---|
3782 | ch.setFormat( f );
|
---|
3783 | }
|
---|
3784 |
|
---|
3785 | void QTextString::checkBidi() const
|
---|
3786 | {
|
---|
3787 | QTextString *that = (QTextString *)this;
|
---|
3788 | that->bidiDirty = FALSE;
|
---|
3789 | int length = data.size();
|
---|
3790 | if ( !length ) {
|
---|
3791 | that->bidi = FALSE;
|
---|
3792 | that->rightToLeft = dir == QChar::DirR;
|
---|
3793 | return;
|
---|
3794 | }
|
---|
3795 | const QTextStringChar *start = data.data();
|
---|
3796 | const QTextStringChar *end = start + length;
|
---|
3797 |
|
---|
3798 | // determines the properties we need for layouting
|
---|
3799 | QTextEngine textEngine( toString(), 0 );
|
---|
3800 | textEngine.itemize(QTextEngine::SingleLine);
|
---|
3801 | const QCharAttributes *ca = textEngine.attributes() + length-1;
|
---|
3802 | QTextStringChar *ch = (QTextStringChar *)end - 1;
|
---|
3803 | QScriptItem *item = &textEngine.items[textEngine.items.size()-1];
|
---|
3804 | unsigned char bidiLevel = item->analysis.bidiLevel;
|
---|
3805 | if ( bidiLevel )
|
---|
3806 | that->bidi = TRUE;
|
---|
3807 | int pos = length-1;
|
---|
3808 | while ( ch >= start ) {
|
---|
3809 | if ( item->position > pos ) {
|
---|
3810 | --item;
|
---|
3811 | Q_ASSERT( item >= &textEngine.items[0] );
|
---|
3812 | Q_ASSERT( item < &textEngine.items[textEngine.items.size()] );
|
---|
3813 | bidiLevel = item->analysis.bidiLevel;
|
---|
3814 | if ( bidiLevel )
|
---|
3815 | that->bidi = TRUE;
|
---|
3816 | }
|
---|
3817 | ch->softBreak = ca->softBreak;
|
---|
3818 | ch->whiteSpace = ca->whiteSpace;
|
---|
3819 | ch->charStop = ca->charStop;
|
---|
3820 | ch->wordStop = ca->wordStop;
|
---|
3821 | ch->bidiLevel = bidiLevel;
|
---|
3822 | ch->rightToLeft = (bidiLevel%2);
|
---|
3823 | --ch;
|
---|
3824 | --ca;
|
---|
3825 | --pos;
|
---|
3826 | }
|
---|
3827 |
|
---|
3828 | if ( dir == QChar::DirR ) {
|
---|
3829 | that->bidi = TRUE;
|
---|
3830 | that->rightToLeft = TRUE;
|
---|
3831 | } else if ( dir == QChar::DirL ) {
|
---|
3832 | that->rightToLeft = FALSE;
|
---|
3833 | } else {
|
---|
3834 | that->rightToLeft = (textEngine.items[0].analysis.bidiLevel % 2);
|
---|
3835 | }
|
---|
3836 | }
|
---|
3837 |
|
---|
3838 | void QTextDocument::setStyleSheet( QStyleSheet *s )
|
---|
3839 | {
|
---|
3840 | if ( !s )
|
---|
3841 | return;
|
---|
3842 | sheet_ = s;
|
---|
3843 | list_tm = list_bm = par_tm = par_bm = 12;
|
---|
3844 | list_lm = 40;
|
---|
3845 | li_tm = li_bm = 0;
|
---|
3846 | QStyleSheetItem* item = s->item( "ol" );
|
---|
3847 | if ( item ) {
|
---|
3848 | list_tm = QMAX(0,item->margin( QStyleSheetItem::MarginTop ));
|
---|
3849 | list_bm = QMAX(0,item->margin( QStyleSheetItem::MarginBottom ));
|
---|
3850 | list_lm = QMAX(0,item->margin( QStyleSheetItem::MarginLeft ));
|
---|
3851 | }
|
---|
3852 | if ( (item = s->item( "li" ) ) ) {
|
---|
3853 | li_tm = QMAX(0,item->margin( QStyleSheetItem::MarginTop ));
|
---|
3854 | li_bm = QMAX(0,item->margin( QStyleSheetItem::MarginBottom ));
|
---|
3855 | }
|
---|
3856 | if ( (item = s->item( "p" ) ) ) {
|
---|
3857 | par_tm = QMAX(0,item->margin( QStyleSheetItem::MarginTop ));
|
---|
3858 | par_bm = QMAX(0,item->margin( QStyleSheetItem::MarginBottom ));
|
---|
3859 | }
|
---|
3860 | }
|
---|
3861 |
|
---|
3862 | void QTextDocument::setUnderlineLinks( bool b ) {
|
---|
3863 | underlLinks = b;
|
---|
3864 | for ( QTextDocument *d = childList.first(); d; d = childList.next() )
|
---|
3865 | d->setUnderlineLinks( b );
|
---|
3866 | }
|
---|
3867 |
|
---|
3868 | void QTextStringChar::setFormat( QTextFormat *f )
|
---|
3869 | {
|
---|
3870 | if ( type == Regular ) {
|
---|
3871 | d.format = f;
|
---|
3872 | } else {
|
---|
3873 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
3874 | if ( !d.custom ) {
|
---|
3875 | d.custom = new CustomData;
|
---|
3876 | d.custom->custom = 0;
|
---|
3877 | }
|
---|
3878 | d.custom->format = f;
|
---|
3879 | #endif
|
---|
3880 | }
|
---|
3881 | }
|
---|
3882 |
|
---|
3883 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
3884 | void QTextStringChar::setCustomItem( QTextCustomItem *i )
|
---|
3885 | {
|
---|
3886 | if ( type == Regular ) {
|
---|
3887 | QTextFormat *f = format();
|
---|
3888 | d.custom = new CustomData;
|
---|
3889 | d.custom->format = f;
|
---|
3890 | } else {
|
---|
3891 | delete d.custom->custom;
|
---|
3892 | }
|
---|
3893 | d.custom->custom = i;
|
---|
3894 | type = (type == Anchor ? CustomAnchor : Custom);
|
---|
3895 | }
|
---|
3896 |
|
---|
3897 | void QTextStringChar::loseCustomItem()
|
---|
3898 | {
|
---|
3899 | if ( type == Custom ) {
|
---|
3900 | QTextFormat *f = d.custom->format;
|
---|
3901 | d.custom->custom = 0;
|
---|
3902 | delete d.custom;
|
---|
3903 | type = Regular;
|
---|
3904 | d.format = f;
|
---|
3905 | } else if ( type == CustomAnchor ) {
|
---|
3906 | d.custom->custom = 0;
|
---|
3907 | type = Anchor;
|
---|
3908 | }
|
---|
3909 | }
|
---|
3910 |
|
---|
3911 | #endif
|
---|
3912 |
|
---|
3913 | QString QTextStringChar::anchorName() const
|
---|
3914 | {
|
---|
3915 | if ( type == Regular )
|
---|
3916 | return QString::null;
|
---|
3917 | else
|
---|
3918 | return d.custom->anchorName;
|
---|
3919 | }
|
---|
3920 |
|
---|
3921 | QString QTextStringChar::anchorHref() const
|
---|
3922 | {
|
---|
3923 | if ( type == Regular )
|
---|
3924 | return QString::null;
|
---|
3925 | else
|
---|
3926 | return d.custom->anchorHref;
|
---|
3927 | }
|
---|
3928 |
|
---|
3929 | void QTextStringChar::setAnchor( const QString& name, const QString& href )
|
---|
3930 | {
|
---|
3931 | if ( type == Regular ) {
|
---|
3932 | QTextFormat *f = format();
|
---|
3933 | d.custom = new CustomData;
|
---|
3934 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
3935 | d.custom->custom = 0;
|
---|
3936 | #endif
|
---|
3937 | d.custom->format = f;
|
---|
3938 | type = Anchor;
|
---|
3939 | } else if ( type == Custom ) {
|
---|
3940 | type = CustomAnchor;
|
---|
3941 | }
|
---|
3942 | d.custom->anchorName = name;
|
---|
3943 | d.custom->anchorHref = href;
|
---|
3944 | }
|
---|
3945 |
|
---|
3946 |
|
---|
3947 | int QTextString::width( int idx ) const
|
---|
3948 | {
|
---|
3949 | int w = 0;
|
---|
3950 | QTextStringChar *c = &at( idx );
|
---|
3951 | if ( !c->charStop || c->c.unicode() == 0xad || c->c.unicode() == 0x2028 )
|
---|
3952 | return 0;
|
---|
3953 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
3954 | if( c->isCustom() ) {
|
---|
3955 | if( c->customItem()->placement() == QTextCustomItem::PlaceInline )
|
---|
3956 | w = c->customItem()->width;
|
---|
3957 | } else
|
---|
3958 | #endif
|
---|
3959 | {
|
---|
3960 | int r = c->c.row();
|
---|
3961 | if(r < 0x06 || (r > 0x1f && !(r > 0xd7 && r < 0xe0))) {
|
---|
3962 | w = c->format()->width( c->c );
|
---|
3963 | } else {
|
---|
3964 | // complex text. We need some hacks to get the right metric here
|
---|
3965 | QString str;
|
---|
3966 | int pos = 0;
|
---|
3967 | if( idx > 8 )
|
---|
3968 | pos = idx - 8;
|
---|
3969 | int off = idx - pos;
|
---|
3970 | int end = QMIN( length(), idx + 8 );
|
---|
3971 | str.setLength( end-pos );
|
---|
3972 | QChar *uc = (QChar *)str.unicode();
|
---|
3973 | while ( pos < end ) {
|
---|
3974 | *(uc++) = at(pos).c;
|
---|
3975 | pos++;
|
---|
3976 | }
|
---|
3977 | w = c->format()->width( str, off );
|
---|
3978 | }
|
---|
3979 | }
|
---|
3980 | return w;
|
---|
3981 | }
|
---|
3982 |
|
---|
3983 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
3984 |
|
---|
3985 | QTextParagraph::QTextParagraph( QTextDocument *d, QTextParagraph *pr, QTextParagraph *nx, bool updateIds )
|
---|
3986 | : p( pr ), n( nx ), docOrPseudo( d ),
|
---|
3987 | changed(FALSE), firstFormat(TRUE), firstPProcess(TRUE), needPreProcess(FALSE), fullWidth(TRUE),
|
---|
3988 | lastInFrame(FALSE), visible(TRUE), breakable(TRUE), movedDown(FALSE),
|
---|
3989 | mightHaveCustomItems(FALSE), hasdoc( d != 0 ), litem(FALSE), rtext(FALSE),
|
---|
3990 | align( 0 ), lstyle( QStyleSheetItem::ListDisc ), invalid( 0 ), mSelections( 0 ),
|
---|
3991 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
3992 | mFloatingItems( 0 ),
|
---|
3993 | #endif
|
---|
3994 | utm( 0 ), ubm( 0 ), ulm( 0 ), urm( 0 ), uflm( 0 ), ulinespacing( 0 ),
|
---|
3995 | tabStopWidth(0), minwidth(0), tArray(0), eData( 0 ), ldepth( 0 )
|
---|
3996 | {
|
---|
3997 | lstyle = QStyleSheetItem::ListDisc;
|
---|
3998 | if ( !hasdoc )
|
---|
3999 | docOrPseudo = new QTextParagraphPseudoDocument;
|
---|
4000 | bgcol = 0;
|
---|
4001 | list_val = -1;
|
---|
4002 | paintdevice = 0;
|
---|
4003 | QTextFormat* defFormat = formatCollection()->defaultFormat();
|
---|
4004 | if ( !hasdoc ) {
|
---|
4005 | tabStopWidth = defFormat->width( 'x' ) * 8;
|
---|
4006 | pseudoDocument()->commandHistory = new QTextCommandHistory( 100 );
|
---|
4007 | }
|
---|
4008 |
|
---|
4009 | if ( p )
|
---|
4010 | p->n = this;
|
---|
4011 | if ( n )
|
---|
4012 | n->p = this;
|
---|
4013 |
|
---|
4014 | if ( !p && hasdoc )
|
---|
4015 | document()->setFirstParagraph( this );
|
---|
4016 | if ( !n && hasdoc )
|
---|
4017 | document()->setLastParagraph( this );
|
---|
4018 |
|
---|
4019 | state = -1;
|
---|
4020 |
|
---|
4021 | if ( p )
|
---|
4022 | id = p->id + 1;
|
---|
4023 | else
|
---|
4024 | id = 0;
|
---|
4025 | if ( n && updateIds ) {
|
---|
4026 | QTextParagraph *s = n;
|
---|
4027 | while ( s ) {
|
---|
4028 | s->id = s->p->id + 1;
|
---|
4029 | s->invalidateStyleCache();
|
---|
4030 | s = s->n;
|
---|
4031 | }
|
---|
4032 | }
|
---|
4033 |
|
---|
4034 | str = new QTextString();
|
---|
4035 | QChar ch(' ');
|
---|
4036 | str->insert( 0, &ch, 1, formatCollection()->defaultFormat() );
|
---|
4037 | }
|
---|
4038 |
|
---|
4039 | QTextParagraph::~QTextParagraph()
|
---|
4040 | {
|
---|
4041 | delete str;
|
---|
4042 | if ( hasdoc ) {
|
---|
4043 | register QTextDocument *doc = document();
|
---|
4044 | if ( this == doc->minwParag ) {
|
---|
4045 | doc->minwParag = 0;
|
---|
4046 | doc->minw = 0;
|
---|
4047 | }
|
---|
4048 | if ( this == doc->curParag )
|
---|
4049 | doc->curParag = 0;
|
---|
4050 | } else {
|
---|
4051 | delete pseudoDocument();
|
---|
4052 | }
|
---|
4053 | delete [] tArray;
|
---|
4054 | delete eData;
|
---|
4055 | QMap<int, QTextLineStart*>::Iterator it = lineStarts.begin();
|
---|
4056 | for ( ; it != lineStarts.end(); ++it )
|
---|
4057 | delete *it;
|
---|
4058 | if ( mSelections )
|
---|
4059 | delete mSelections;
|
---|
4060 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
4061 | if ( mFloatingItems )
|
---|
4062 | delete mFloatingItems;
|
---|
4063 | #endif
|
---|
4064 | if ( p )
|
---|
4065 | p->setNext( n );
|
---|
4066 | if ( n )
|
---|
4067 | n->setPrev( p );
|
---|
4068 | }
|
---|
4069 |
|
---|
4070 | void QTextParagraph::setNext( QTextParagraph *s )
|
---|
4071 | {
|
---|
4072 | n = s;
|
---|
4073 | if ( !n && hasdoc )
|
---|
4074 | document()->setLastParagraph( this );
|
---|
4075 | }
|
---|
4076 |
|
---|
4077 | void QTextParagraph::setPrev( QTextParagraph *s )
|
---|
4078 | {
|
---|
4079 | p = s;
|
---|
4080 | if ( !p && hasdoc )
|
---|
4081 | document()->setFirstParagraph( this );
|
---|
4082 | }
|
---|
4083 |
|
---|
4084 | void QTextParagraph::invalidate( int chr )
|
---|
4085 | {
|
---|
4086 | if ( invalid < 0 )
|
---|
4087 | invalid = chr;
|
---|
4088 | else
|
---|
4089 | invalid = QMIN( invalid, chr );
|
---|
4090 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
4091 | if ( mFloatingItems ) {
|
---|
4092 | for ( QTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() )
|
---|
4093 | i->ypos = -1;
|
---|
4094 | }
|
---|
4095 | #endif
|
---|
4096 | invalidateStyleCache();
|
---|
4097 | }
|
---|
4098 |
|
---|
4099 | void QTextParagraph::invalidateStyleCache()
|
---|
4100 | {
|
---|
4101 | if ( list_val < 0 )
|
---|
4102 | list_val = -1;
|
---|
4103 | }
|
---|
4104 |
|
---|
4105 |
|
---|
4106 | void QTextParagraph::insert( int index, const QString &s )
|
---|
4107 | {
|
---|
4108 | insert( index, s.unicode(), s.length() );
|
---|
4109 | }
|
---|
4110 |
|
---|
4111 | void QTextParagraph::insert( int index, const QChar *unicode, int len )
|
---|
4112 | {
|
---|
4113 | if ( hasdoc && !document()->useFormatCollection() && document()->preProcessor() )
|
---|
4114 | str->insert( index, unicode, len,
|
---|
4115 | document()->preProcessor()->format( QTextPreProcessor::Standard ) );
|
---|
4116 | else
|
---|
4117 | str->insert( index, unicode, len, formatCollection()->defaultFormat() );
|
---|
4118 | invalidate( index );
|
---|
4119 | needPreProcess = TRUE;
|
---|
4120 | }
|
---|
4121 |
|
---|
4122 | void QTextParagraph::truncate( int index )
|
---|
4123 | {
|
---|
4124 | str->truncate( index );
|
---|
4125 | insert( length(), " " );
|
---|
4126 | needPreProcess = TRUE;
|
---|
4127 | }
|
---|
4128 |
|
---|
4129 | void QTextParagraph::remove( int index, int len )
|
---|
4130 | {
|
---|
4131 | if ( index + len - str->length() > 0 )
|
---|
4132 | return;
|
---|
4133 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
4134 | for ( int i = index; i < index + len; ++i ) {
|
---|
4135 | QTextStringChar *c = at( i );
|
---|
4136 | if ( hasdoc && c->isCustom() ) {
|
---|
4137 | document()->unregisterCustomItem( c->customItem(), this );
|
---|
4138 | }
|
---|
4139 | }
|
---|
4140 | #endif
|
---|
4141 | str->remove( index, len );
|
---|
4142 | invalidate( 0 );
|
---|
4143 | needPreProcess = TRUE;
|
---|
4144 | }
|
---|
4145 |
|
---|
4146 | void QTextParagraph::join( QTextParagraph *s )
|
---|
4147 | {
|
---|
4148 | int oh = r.height() + s->r.height();
|
---|
4149 | n = s->n;
|
---|
4150 | if ( n )
|
---|
4151 | n->p = this;
|
---|
4152 | else if ( hasdoc )
|
---|
4153 | document()->setLastParagraph( this );
|
---|
4154 |
|
---|
4155 | int start = str->length();
|
---|
4156 | if ( length() > 0 && at( length() - 1 )->c == ' ' ) {
|
---|
4157 | remove( length() - 1, 1 );
|
---|
4158 | --start;
|
---|
4159 | }
|
---|
4160 | append( s->str->toString(), TRUE );
|
---|
4161 |
|
---|
4162 | for ( int i = 0; i < s->length(); ++i ) {
|
---|
4163 | if ( !hasdoc || document()->useFormatCollection() ) {
|
---|
4164 | s->str->at( i ).format()->addRef();
|
---|
4165 | str->setFormat( i + start, s->str->at( i ).format(), TRUE );
|
---|
4166 | }
|
---|
4167 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
4168 | if ( s->str->at( i ).isCustom() ) {
|
---|
4169 | QTextCustomItem * item = s->str->at( i ).customItem();
|
---|
4170 | str->at( i + start ).setCustomItem( item );
|
---|
4171 | s->str->at( i ).loseCustomItem();
|
---|
4172 | if ( hasdoc ) {
|
---|
4173 | document()->unregisterCustomItem( item, s );
|
---|
4174 | document()->registerCustomItem( item, this );
|
---|
4175 | }
|
---|
4176 | }
|
---|
4177 | if ( s->str->at( i ).isAnchor() ) {
|
---|
4178 | str->at( i + start ).setAnchor( s->str->at( i ).anchorName(),
|
---|
4179 | s->str->at( i ).anchorHref() );
|
---|
4180 | }
|
---|
4181 | #endif
|
---|
4182 | }
|
---|
4183 |
|
---|
4184 | if ( !extraData() && s->extraData() ) {
|
---|
4185 | setExtraData( s->extraData() );
|
---|
4186 | s->setExtraData( 0 );
|
---|
4187 | } else if ( extraData() && s->extraData() ) {
|
---|
4188 | extraData()->join( s->extraData() );
|
---|
4189 | }
|
---|
4190 | delete s;
|
---|
4191 | invalidate( 0 );
|
---|
4192 | r.setHeight( oh );
|
---|
4193 | needPreProcess = TRUE;
|
---|
4194 | if ( n ) {
|
---|
4195 | QTextParagraph *s = n;
|
---|
4196 | s->invalidate( 0 );
|
---|
4197 | while ( s ) {
|
---|
4198 | s->id = s->p->id + 1;
|
---|
4199 | s->state = -1;
|
---|
4200 | s->needPreProcess = TRUE;
|
---|
4201 | s->changed = TRUE;
|
---|
4202 | s->invalidateStyleCache();
|
---|
4203 | s = s->n;
|
---|
4204 | }
|
---|
4205 | }
|
---|
4206 | format();
|
---|
4207 | state = -1;
|
---|
4208 | }
|
---|
4209 |
|
---|
4210 | void QTextParagraph::move( int &dy )
|
---|
4211 | {
|
---|
4212 | if ( dy == 0 )
|
---|
4213 | return;
|
---|
4214 | changed = TRUE;
|
---|
4215 | r.moveBy( 0, dy );
|
---|
4216 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
4217 | if ( mFloatingItems ) {
|
---|
4218 | for ( QTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() )
|
---|
4219 | i->ypos += dy;
|
---|
4220 | }
|
---|
4221 | #endif
|
---|
4222 | if ( p )
|
---|
4223 | p->lastInFrame = TRUE;
|
---|
4224 |
|
---|
4225 | // do page breaks if required
|
---|
4226 | if ( hasdoc && document()->isPageBreakEnabled() ) {
|
---|
4227 | int shift;
|
---|
4228 | if ( ( shift = document()->formatter()->formatVertically( document(), this ) ) ) {
|
---|
4229 | if ( p )
|
---|
4230 | p->setChanged( TRUE );
|
---|
4231 | dy += shift;
|
---|
4232 | }
|
---|
4233 | }
|
---|
4234 | }
|
---|
4235 |
|
---|
4236 | void QTextParagraph::format( int start, bool doMove )
|
---|
4237 | {
|
---|
4238 | if ( !str || str->length() == 0 || !formatter() )
|
---|
4239 | return;
|
---|
4240 |
|
---|
4241 | if ( hasdoc &&
|
---|
4242 | document()->preProcessor() &&
|
---|
4243 | ( needPreProcess || state == -1 ) )
|
---|
4244 | document()->preProcessor()->process( document(), this, invalid <= 0 ? 0 : invalid );
|
---|
4245 | needPreProcess = FALSE;
|
---|
4246 |
|
---|
4247 | if ( invalid == -1 )
|
---|
4248 | return;
|
---|
4249 |
|
---|
4250 | r.moveTopLeft( QPoint( documentX(), p ? p->r.y() + p->r.height() : documentY() ) );
|
---|
4251 | if ( p )
|
---|
4252 | p->lastInFrame = FALSE;
|
---|
4253 |
|
---|
4254 | movedDown = FALSE;
|
---|
4255 | bool formattedAgain = FALSE;
|
---|
4256 |
|
---|
4257 | formatAgain:
|
---|
4258 |
|
---|
4259 | r.setWidth( documentWidth() );
|
---|
4260 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
4261 | if ( hasdoc && mFloatingItems ) {
|
---|
4262 | for ( QTextCustomItem *i = mFloatingItems->first(); i; i = mFloatingItems->next() ) {
|
---|
4263 | i->ypos = r.y();
|
---|
4264 | if ( i->placement() == QTextCustomItem::PlaceRight ) {
|
---|
4265 | i->xpos = r.x() + r.width() - i->width;
|
---|
4266 | }
|
---|
4267 | }
|
---|
4268 | }
|
---|
4269 | #endif
|
---|
4270 | QMap<int, QTextLineStart*> oldLineStarts = lineStarts;
|
---|
4271 | lineStarts.clear();
|
---|
4272 | int y = formatter()->format( document(), this, start, oldLineStarts );
|
---|
4273 |
|
---|
4274 |
|
---|
4275 | r.setWidth( QMAX( r.width(), formatter()->minimumWidth() ) );
|
---|
4276 |
|
---|
4277 |
|
---|
4278 | QMap<int, QTextLineStart*>::Iterator it = oldLineStarts.begin();
|
---|
4279 |
|
---|
4280 | for ( ; it != oldLineStarts.end(); ++it )
|
---|
4281 | delete *it;
|
---|
4282 |
|
---|
4283 | if ( !hasdoc ) { // qt_format_text bounding rect handling
|
---|
4284 | it = lineStarts.begin();
|
---|
4285 | int usedw = 0;
|
---|
4286 | for ( ; it != lineStarts.end(); ++it )
|
---|
4287 | usedw = QMAX( usedw, (*it)->w );
|
---|
4288 | if ( r.width() <= 0 ) {
|
---|
4289 | // if the user specifies an invalid rect, this means that the
|
---|
4290 | // bounding box should grow to the width that the text actually
|
---|
4291 | // needs
|
---|
4292 | r.setWidth( usedw );
|
---|
4293 | } else {
|
---|
4294 | r.setWidth( QMIN( usedw, r.width() ) );
|
---|
4295 | }
|
---|
4296 | }
|
---|
4297 |
|
---|
4298 | if ( y != r.height() )
|
---|
4299 | r.setHeight( y );
|
---|
4300 |
|
---|
4301 | if ( !visible ) {
|
---|
4302 | r.setHeight( 0 );
|
---|
4303 | } else {
|
---|
4304 | int minw = minwidth = formatter()->minimumWidth();
|
---|
4305 | int wused = formatter()->widthUsed();
|
---|
4306 | wused = QMAX( minw, wused );
|
---|
4307 | if ( hasdoc ) {
|
---|
4308 | document()->setMinimumWidth( minw, wused, this );
|
---|
4309 | } else {
|
---|
4310 | pseudoDocument()->minw = QMAX( pseudoDocument()->minw, minw );
|
---|
4311 | pseudoDocument()->wused = QMAX( pseudoDocument()->wused, wused );
|
---|
4312 | }
|
---|
4313 | }
|
---|
4314 |
|
---|
4315 | // do page breaks if required
|
---|
4316 | if ( hasdoc && document()->isPageBreakEnabled() ) {
|
---|
4317 | int shift = document()->formatter()->formatVertically( document(), this );
|
---|
4318 | if ( shift && !formattedAgain ) {
|
---|
4319 | formattedAgain = TRUE;
|
---|
4320 | goto formatAgain;
|
---|
4321 | }
|
---|
4322 | }
|
---|
4323 |
|
---|
4324 | if ( n && doMove && n->invalid == -1 && r.y() + r.height() != n->r.y() ) {
|
---|
4325 | int dy = ( r.y() + r.height() ) - n->r.y();
|
---|
4326 | QTextParagraph *s = n;
|
---|
4327 | bool makeInvalid = p && p->lastInFrame;
|
---|
4328 | while ( s && dy ) {
|
---|
4329 | if ( !s->isFullWidth() )
|
---|
4330 | makeInvalid = TRUE;
|
---|
4331 | if ( makeInvalid )
|
---|
4332 | s->invalidate( 0 );
|
---|
4333 | s->move( dy );
|
---|
4334 | if ( s->lastInFrame )
|
---|
4335 | makeInvalid = TRUE;
|
---|
4336 | s = s->n;
|
---|
4337 | }
|
---|
4338 | }
|
---|
4339 |
|
---|
4340 | firstFormat = FALSE;
|
---|
4341 | changed = TRUE;
|
---|
4342 | invalid = -1;
|
---|
4343 | //##### string()->setTextChanged( FALSE );
|
---|
4344 | }
|
---|
4345 |
|
---|
4346 | int QTextParagraph::lineHeightOfChar( int i, int *bl, int *y ) const
|
---|
4347 | {
|
---|
4348 | if ( !isValid() )
|
---|
4349 | ( (QTextParagraph*)this )->format();
|
---|
4350 |
|
---|
4351 | QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.end();
|
---|
4352 | --it;
|
---|
4353 | for ( ;; ) {
|
---|
4354 | if ( i >= it.key() ) {
|
---|
4355 | if ( bl )
|
---|
4356 | *bl = ( *it )->baseLine;
|
---|
4357 | if ( y )
|
---|
4358 | *y = ( *it )->y;
|
---|
4359 | return ( *it )->h;
|
---|
4360 | }
|
---|
4361 | if ( it == lineStarts.begin() )
|
---|
4362 | break;
|
---|
4363 | --it;
|
---|
4364 | }
|
---|
4365 |
|
---|
4366 | qWarning( "QTextParagraph::lineHeightOfChar: couldn't find lh for %d", i );
|
---|
4367 | return 15;
|
---|
4368 | }
|
---|
4369 |
|
---|
4370 | QTextStringChar *QTextParagraph::lineStartOfChar( int i, int *index, int *line ) const
|
---|
4371 | {
|
---|
4372 | if ( !isValid() )
|
---|
4373 | ( (QTextParagraph*)this )->format();
|
---|
4374 |
|
---|
4375 | int l = (int)lineStarts.count() - 1;
|
---|
4376 | QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.end();
|
---|
4377 | --it;
|
---|
4378 | for ( ;; ) {
|
---|
4379 | if ( i >= it.key() ) {
|
---|
4380 | if ( index )
|
---|
4381 | *index = it.key();
|
---|
4382 | if ( line )
|
---|
4383 | *line = l;
|
---|
4384 | return &str->at( it.key() );
|
---|
4385 | }
|
---|
4386 | if ( it == lineStarts.begin() )
|
---|
4387 | break;
|
---|
4388 | --it;
|
---|
4389 | --l;
|
---|
4390 | }
|
---|
4391 |
|
---|
4392 | qWarning( "QTextParagraph::lineStartOfChar: couldn't find %d", i );
|
---|
4393 | return 0;
|
---|
4394 | }
|
---|
4395 |
|
---|
4396 | int QTextParagraph::lines() const
|
---|
4397 | {
|
---|
4398 | if ( !isValid() )
|
---|
4399 | ( (QTextParagraph*)this )->format();
|
---|
4400 |
|
---|
4401 | return (int)lineStarts.count();
|
---|
4402 | }
|
---|
4403 |
|
---|
4404 | QTextStringChar *QTextParagraph::lineStartOfLine( int line, int *index ) const
|
---|
4405 | {
|
---|
4406 | if ( !isValid() )
|
---|
4407 | ( (QTextParagraph*)this )->format();
|
---|
4408 |
|
---|
4409 | if ( line >= 0 && line < (int)lineStarts.count() ) {
|
---|
4410 | QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.begin();
|
---|
4411 | while ( line-- > 0 )
|
---|
4412 | ++it;
|
---|
4413 | int i = it.key();
|
---|
4414 | if ( index )
|
---|
4415 | *index = i;
|
---|
4416 | return &str->at( i );
|
---|
4417 | }
|
---|
4418 |
|
---|
4419 | qWarning( "QTextParagraph::lineStartOfLine: couldn't find %d", line );
|
---|
4420 | return 0;
|
---|
4421 | }
|
---|
4422 |
|
---|
4423 | int QTextParagraph::leftGap() const
|
---|
4424 | {
|
---|
4425 | if ( !isValid() )
|
---|
4426 | ( (QTextParagraph*)this )->format();
|
---|
4427 |
|
---|
4428 | if ( str->length() == 0)
|
---|
4429 | return 0;
|
---|
4430 |
|
---|
4431 | int line = 0;
|
---|
4432 | int x = str->length() ? str->at(0).x : 0; /* set x to x of first char */
|
---|
4433 | if ( str->isBidi() ) {
|
---|
4434 | for ( int i = 1; i < str->length()-1; ++i )
|
---|
4435 | x = QMIN(x, str->at(i).x);
|
---|
4436 | return x;
|
---|
4437 | }
|
---|
4438 |
|
---|
4439 | QMap<int, QTextLineStart*>::ConstIterator it = lineStarts.begin();
|
---|
4440 | while (line < (int)lineStarts.count()) {
|
---|
4441 | int i = it.key(); /* char index */
|
---|
4442 | x = QMIN(x, str->at(i).x);
|
---|
4443 | ++it;
|
---|
4444 | ++line;
|
---|
4445 | }
|
---|
4446 | return x;
|
---|
4447 | }
|
---|
4448 |
|
---|
4449 | void QTextParagraph::setFormat( int index, int len, QTextFormat *f, bool useCollection, int flags )
|
---|
4450 | {
|
---|
4451 | if ( !f )
|
---|
4452 | return;
|
---|
4453 | if ( index < 0 )
|
---|
4454 | index = 0;
|
---|
4455 | if ( index > str->length() - 1 )
|
---|
4456 | index = str->length() - 1;
|
---|
4457 | if ( index + len >= str->length() )
|
---|
4458 | len = str->length() - index;
|
---|
4459 |
|
---|
4460 | QTextFormatCollection *fc = 0;
|
---|
4461 | if ( useCollection )
|
---|
4462 | fc = formatCollection();
|
---|
4463 | QTextFormat *of;
|
---|
4464 | for ( int i = 0; i < len; ++i ) {
|
---|
4465 | of = str->at( i + index ).format();
|
---|
4466 | if ( !changed && ( !of || f->key() != of->key() ) )
|
---|
4467 | changed = TRUE;
|
---|
4468 | if ( invalid == -1 &&
|
---|
4469 | ( f->font().family() != of->font().family() ||
|
---|
4470 | f->font().pointSize() != of->font().pointSize() ||
|
---|
4471 | f->font().weight() != of->font().weight() ||
|
---|
4472 | f->font().italic() != of->font().italic() ||
|
---|
4473 | f->vAlign() != of->vAlign() ) ) {
|
---|
4474 | invalidate( 0 );
|
---|
4475 | }
|
---|
4476 | if ( flags == -1 || flags == QTextFormat::Format || !fc ) {
|
---|
4477 | if ( fc )
|
---|
4478 | f = fc->format( f );
|
---|
4479 | str->setFormat( i + index, f, useCollection );
|
---|
4480 | } else {
|
---|
4481 | QTextFormat *fm = fc->format( of, f, flags );
|
---|
4482 | str->setFormat( i + index, fm, useCollection );
|
---|
4483 | }
|
---|
4484 | }
|
---|
4485 | }
|
---|
4486 |
|
---|
4487 | void QTextParagraph::indent( int *oldIndent, int *newIndent )
|
---|
4488 | {
|
---|
4489 | if ( !hasdoc || !document()->indent() || isListItem() ) {
|
---|
4490 | if ( oldIndent )
|
---|
4491 | *oldIndent = 0;
|
---|
4492 | if ( newIndent )
|
---|
4493 | *newIndent = 0;
|
---|
4494 | if ( oldIndent && newIndent )
|
---|
4495 | *newIndent = *oldIndent;
|
---|
4496 | return;
|
---|
4497 | }
|
---|
4498 | document()->indent()->indent( document(), this, oldIndent, newIndent );
|
---|
4499 | }
|
---|
4500 |
|
---|
4501 | void QTextParagraph::paint( QPainter &painter, const QColorGroup &cg, QTextCursor *cursor, bool drawSelections,
|
---|
4502 | int clipx, int clipy, int clipw, int cliph )
|
---|
4503 | {
|
---|
4504 | if ( !visible )
|
---|
4505 | return;
|
---|
4506 | int i, y, h, baseLine, xstart, xend = 0;
|
---|
4507 | i = y =h = baseLine = 0;
|
---|
4508 | QRect cursorRect;
|
---|
4509 | drawSelections &= ( mSelections != 0 );
|
---|
4510 | // macintosh full-width selection style
|
---|
4511 | bool fullWidthStyle = QApplication::style().styleHint(QStyle::SH_RichText_FullWidthSelection);
|
---|
4512 | int fullSelectionWidth = 0;
|
---|
4513 | if ( drawSelections && fullWidthStyle )
|
---|
4514 | fullSelectionWidth = (hasdoc ? document()->width() : r.width());
|
---|
4515 |
|
---|
4516 | QString qstr = str->toString();
|
---|
4517 | // ### workaround so that \n are not drawn, actually this should
|
---|
4518 | // be fixed in QFont somewhere (under Windows you get ugly boxes
|
---|
4519 | // otherwise)
|
---|
4520 | QChar* uc = (QChar*) qstr.unicode();
|
---|
4521 | for ( uint ii = 0; ii < qstr.length(); ii++ )
|
---|
4522 | if ( uc[(int)ii]== '\n' || uc[(int)ii] == '\t' )
|
---|
4523 | uc[(int)ii] = 0x20;
|
---|
4524 |
|
---|
4525 | int line = -1;
|
---|
4526 | int paintStart = 0;
|
---|
4527 | QTextStringChar *chr = 0;
|
---|
4528 | QTextStringChar *nextchr = at( 0 );
|
---|
4529 | for ( i = 0; i < length(); i++ ) {
|
---|
4530 | chr = nextchr;
|
---|
4531 | if ( i < length()-1 )
|
---|
4532 | nextchr = at( i+1 );
|
---|
4533 |
|
---|
4534 | // we flush at end of document
|
---|
4535 | bool flush = (i == length()-1);
|
---|
4536 | bool ignoreSoftHyphen = FALSE;
|
---|
4537 | if ( !flush ) {
|
---|
4538 | // we flush at end of line
|
---|
4539 | flush |= nextchr->lineStart;
|
---|
4540 | // we flush on format changes
|
---|
4541 | flush |= ( nextchr->format() != chr->format() );
|
---|
4542 | // we flush on link changes
|
---|
4543 | flush |= ( nextchr->isLink() != chr->isLink() );
|
---|
4544 | // we flush on start of run
|
---|
4545 | flush |= ( nextchr->bidiLevel != chr->bidiLevel );
|
---|
4546 | // we flush on bidi changes
|
---|
4547 | flush |= ( nextchr->rightToLeft != chr->rightToLeft );
|
---|
4548 | // we flush before and after tabs
|
---|
4549 | flush |= ( chr->c == '\t' || nextchr->c == '\t' );
|
---|
4550 | // we flush on soft hypens
|
---|
4551 | if (chr->c.unicode() == 0xad) {
|
---|
4552 | flush = TRUE;
|
---|
4553 | if (!nextchr->lineStart)
|
---|
4554 | ignoreSoftHyphen = TRUE;
|
---|
4555 | }
|
---|
4556 | // we flush on custom items
|
---|
4557 | flush |= chr->isCustom();
|
---|
4558 | // we flush before custom items
|
---|
4559 | flush |= nextchr->isCustom();
|
---|
4560 | // when painting justified, we flush on spaces
|
---|
4561 | if ((alignment() & Qt::AlignJustify) == Qt::AlignJustify )
|
---|
4562 | flush |= chr->whiteSpace;
|
---|
4563 | }
|
---|
4564 |
|
---|
4565 | // init a new line
|
---|
4566 | if ( chr->lineStart ) {
|
---|
4567 | ++line;
|
---|
4568 | paintStart = i;
|
---|
4569 | lineInfo( line, y, h, baseLine );
|
---|
4570 | if ( clipy != -1 && cliph != 0 && y + r.y() - h > clipy + cliph ) { // outside clip area, leave
|
---|
4571 | break;
|
---|
4572 | }
|
---|
4573 |
|
---|
4574 | // if this is the first line and we are a list item, draw the the bullet label
|
---|
4575 | if ( line == 0 && isListItem() ) {
|
---|
4576 | int x = chr->x;
|
---|
4577 | if (str->isBidi()) {
|
---|
4578 | if (str->isRightToLeft()) {
|
---|
4579 | x = chr->x + str->width(0);
|
---|
4580 | for (int k = 1; k < length(); ++k) {
|
---|
4581 | if (str->at(k).lineStart)
|
---|
4582 | break;
|
---|
4583 | x = QMAX(x, str->at(k).x + str->width(k));
|
---|
4584 | }
|
---|
4585 | } else {
|
---|
4586 | x = chr->x;
|
---|
4587 | for (int k = 1; k < length(); ++k) {
|
---|
4588 | if (str->at(k).lineStart)
|
---|
4589 | break;
|
---|
4590 | x = QMIN(x, str->at(k).x);
|
---|
4591 | }
|
---|
4592 | }
|
---|
4593 | }
|
---|
4594 | drawLabel( &painter, x, y, 0, 0, baseLine, cg );
|
---|
4595 | }
|
---|
4596 | }
|
---|
4597 |
|
---|
4598 | // check for cursor mark
|
---|
4599 | if ( cursor && this == cursor->paragraph() && i == cursor->index() ) {
|
---|
4600 | QTextStringChar *c = i == 0 ? chr : chr - 1;
|
---|
4601 | cursorRect.setRect( cursor->x() , y + baseLine - c->format()->ascent(),
|
---|
4602 | 1, c->format()->height() );
|
---|
4603 | }
|
---|
4604 |
|
---|
4605 | if ( flush ) { // something changed, draw what we have so far
|
---|
4606 | if ( chr->rightToLeft ) {
|
---|
4607 | xstart = chr->x;
|
---|
4608 | xend = at( paintStart )->x + str->width( paintStart );
|
---|
4609 | } else {
|
---|
4610 | xstart = at( paintStart )->x;
|
---|
4611 | xend = chr->x;
|
---|
4612 | if ( i < length() - 1 ) {
|
---|
4613 | if ( !str->at( i + 1 ).lineStart &&
|
---|
4614 | str->at( i + 1 ).rightToLeft == chr->rightToLeft )
|
---|
4615 | xend = str->at( i + 1 ).x;
|
---|
4616 | else
|
---|
4617 | xend += str->width( i );
|
---|
4618 | }
|
---|
4619 | }
|
---|
4620 |
|
---|
4621 | if ( (clipx == -1 || clipw <= 0 || (xend >= clipx && xstart <= clipx + clipw)) &&
|
---|
4622 | ( clipy == -1 || clipy < y+r.y()+h ) ) {
|
---|
4623 | if ( !chr->isCustom() )
|
---|
4624 | drawString( painter, qstr, paintStart, i - paintStart + (ignoreSoftHyphen ? 0 : 1), xstart, y,
|
---|
4625 | baseLine, xend-xstart, h, drawSelections, fullSelectionWidth,
|
---|
4626 | chr, cg, chr->rightToLeft );
|
---|
4627 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
4628 | else if ( chr->customItem()->placement() == QTextCustomItem::PlaceInline ) {
|
---|
4629 | bool inSelection = FALSE;
|
---|
4630 | if (drawSelections) {
|
---|
4631 | QMap<int, QTextParagraphSelection>::ConstIterator it = mSelections->find( QTextDocument::Standard );
|
---|
4632 | inSelection = (it != mSelections->end() && (*it).start <= i && (*it).end > i);
|
---|
4633 | }
|
---|
4634 | chr->customItem()->draw( &painter, chr->x, y,
|
---|
4635 | clipx == -1 ? clipx : (clipx - r.x()),
|
---|
4636 | clipy == -1 ? clipy : (clipy - r.y()),
|
---|
4637 | clipw, cliph, cg, inSelection );
|
---|
4638 | }
|
---|
4639 | #endif
|
---|
4640 | }
|
---|
4641 | paintStart = i+1;
|
---|
4642 | }
|
---|
4643 |
|
---|
4644 | }
|
---|
4645 |
|
---|
4646 | // time to draw the cursor
|
---|
4647 | const int cursor_extent = 4;
|
---|
4648 | if ( !cursorRect.isNull() && cursor &&
|
---|
4649 | ((clipx == -1 || clipw == -1) || (cursorRect.right()+cursor_extent >= clipx && cursorRect.left()-cursor_extent <= clipx + clipw)) ) {
|
---|
4650 | painter.fillRect( cursorRect, cg.color( QColorGroup::Text ) );
|
---|
4651 | painter.save();
|
---|
4652 | if ( string()->isBidi() ) {
|
---|
4653 | if ( at( cursor->index() )->rightToLeft ) {
|
---|
4654 | painter.setPen( Qt::black );
|
---|
4655 | painter.drawLine( cursorRect.x(), cursorRect.y(), cursorRect.x() - cursor_extent / 2, cursorRect.y() + cursor_extent / 2 );
|
---|
4656 | painter.drawLine( cursorRect.x(), cursorRect.y() + cursor_extent, cursorRect.x() - cursor_extent / 2, cursorRect.y() + cursor_extent / 2 );
|
---|
4657 | } else {
|
---|
4658 | painter.setPen( Qt::black );
|
---|
4659 | painter.drawLine( cursorRect.x(), cursorRect.y(), cursorRect.x() + cursor_extent / 2, cursorRect.y() + cursor_extent / 2 );
|
---|
4660 | painter.drawLine( cursorRect.x(), cursorRect.y() + cursor_extent, cursorRect.x() + cursor_extent / 2, cursorRect.y() + cursor_extent / 2 );
|
---|
4661 | }
|
---|
4662 | }
|
---|
4663 | painter.restore();
|
---|
4664 | }
|
---|
4665 | }
|
---|
4666 |
|
---|
4667 | //#define BIDI_DEBUG
|
---|
4668 |
|
---|
4669 | void QTextParagraph::setColorForSelection( QColor &color, QPainter &painter,
|
---|
4670 | const QColorGroup& cg, int selection )
|
---|
4671 | {
|
---|
4672 | if (selection < 0)
|
---|
4673 | return;
|
---|
4674 | color = ( hasdoc && selection != QTextDocument::Standard ) ?
|
---|
4675 | document()->selectionColor( selection ) :
|
---|
4676 | cg.color( QColorGroup::Highlight );
|
---|
4677 | if ( selection == QTextDocument::IMCompositionText ) {
|
---|
4678 | int h1, s1, v1, h2, s2, v2;
|
---|
4679 | cg.color( QColorGroup::Base ).hsv( &h1, &s1, &v1 );
|
---|
4680 | cg.color( QColorGroup::Background ).hsv( &h2, &s2, &v2 );
|
---|
4681 | color.setHsv( h1, s1, ( v1 + v2 ) / 2 );
|
---|
4682 | painter.setPen( cg.color( QColorGroup::Text ) );
|
---|
4683 | } else if ( selection == QTextDocument::IMSelectionText ) {
|
---|
4684 | color = cg.color( QColorGroup::Dark );
|
---|
4685 | painter.setPen( cg.color( QColorGroup::BrightText ) );
|
---|
4686 | } else if ( !hasdoc || document()->invertSelectionText( selection ) ) {
|
---|
4687 | painter.setPen( cg.color( QColorGroup::HighlightedText ) );
|
---|
4688 | }
|
---|
4689 | }
|
---|
4690 |
|
---|
4691 | void QTextParagraph::drawString( QPainter &painter, const QString &str, int start, int len, int xstart,
|
---|
4692 | int y, int baseLine, int w, int h, bool drawSelections, int fullSelectionWidth,
|
---|
4693 | QTextStringChar *formatChar, const QColorGroup& cg,
|
---|
4694 | bool rightToLeft )
|
---|
4695 | {
|
---|
4696 | bool plainText = hasdoc ? document()->textFormat() == Qt::PlainText : FALSE;
|
---|
4697 | QTextFormat* format = formatChar->format();
|
---|
4698 |
|
---|
4699 | if ( !plainText || hasdoc && format->color() != document()->formatCollection()->defaultFormat()->color() )
|
---|
4700 | painter.setPen( QPen( format->color() ) );
|
---|
4701 | else
|
---|
4702 | painter.setPen( cg.text() );
|
---|
4703 | painter.setFont( format->font() );
|
---|
4704 |
|
---|
4705 | if ( hasdoc && formatChar->isAnchor() && !formatChar->anchorHref().isEmpty() ) {
|
---|
4706 | if ( format->useLinkColor() )
|
---|
4707 | painter.setPen(document()->linkColor.isValid() ? document()->linkColor : cg.link());
|
---|
4708 | if ( document()->underlineLinks() ) {
|
---|
4709 | QFont fn = format->font();
|
---|
4710 | fn.setUnderline( TRUE );
|
---|
4711 | painter.setFont( fn );
|
---|
4712 | }
|
---|
4713 | }
|
---|
4714 |
|
---|
4715 | QPainter::TextDirection dir = rightToLeft ? QPainter::RTL : QPainter::LTR;
|
---|
4716 |
|
---|
4717 | int real_length = len;
|
---|
4718 | if (len && dir != QPainter::RTL && start + len == length() ) // don't draw the last character (trailing space)
|
---|
4719 | len--;
|
---|
4720 | if (len && str.unicode()[start+len-1] == QChar_linesep)
|
---|
4721 | len--;
|
---|
4722 |
|
---|
4723 |
|
---|
4724 | QTextFormat::VerticalAlignment vAlign = format->vAlign();
|
---|
4725 | if ( vAlign != QTextFormat::AlignNormal ) {
|
---|
4726 | // sub or superscript
|
---|
4727 | QFont f( painter.font() );
|
---|
4728 | if ( format->fontSizesInPixels() )
|
---|
4729 | f.setPixelSize( ( f.pixelSize() * 2 ) / 3 );
|
---|
4730 | else
|
---|
4731 | f.setPointSize( ( f.pointSize() * 2 ) / 3 );
|
---|
4732 | painter.setFont( f );
|
---|
4733 | int h = painter.fontMetrics().height();
|
---|
4734 | baseLine += (vAlign == QTextFormat::AlignSubScript) ? h/6 : -h/2;
|
---|
4735 | }
|
---|
4736 |
|
---|
4737 | bool allSelected = FALSE;
|
---|
4738 | if (drawSelections) {
|
---|
4739 | QMap<int, QTextParagraphSelection>::ConstIterator it = mSelections->find( QTextDocument::Standard );
|
---|
4740 | allSelected = (it != mSelections->end() && (*it).start <= start && (*it).end >= start+len);
|
---|
4741 | }
|
---|
4742 | if (!allSelected)
|
---|
4743 | painter.drawText(xstart, y + baseLine, str, start, len, dir);
|
---|
4744 |
|
---|
4745 | #ifdef BIDI_DEBUG
|
---|
4746 | painter.save();
|
---|
4747 | painter.setPen ( Qt::red );
|
---|
4748 | painter.drawLine( xstart, y, xstart, y + baseLine );
|
---|
4749 | painter.drawLine( xstart, y + baseLine/2, xstart + 10, y + baseLine/2 );
|
---|
4750 | int w = 0;
|
---|
4751 | int i = 0;
|
---|
4752 | while( i < len )
|
---|
4753 | w += painter.fontMetrics().charWidth( str, start + i++ );
|
---|
4754 | painter.setPen ( Qt::blue );
|
---|
4755 | painter.drawLine( xstart + w - 1, y, xstart + w - 1, y + baseLine );
|
---|
4756 | painter.drawLine( xstart + w - 1, y + baseLine/2, xstart + w - 1 - 10, y + baseLine/2 );
|
---|
4757 | painter.restore();
|
---|
4758 | #endif
|
---|
4759 |
|
---|
4760 | // check if we are in a selection and draw it
|
---|
4761 | if (drawSelections) {
|
---|
4762 | QMap<int, QTextParagraphSelection>::ConstIterator it = mSelections->end();
|
---|
4763 | while ( it != mSelections->begin() ) {
|
---|
4764 | --it;
|
---|
4765 | int selStart = (*it).start;
|
---|
4766 | int selEnd = (*it).end;
|
---|
4767 | int tmpw = w;
|
---|
4768 |
|
---|
4769 | selStart = QMAX(selStart, start);
|
---|
4770 | int real_selEnd = QMIN(selEnd, start+real_length);
|
---|
4771 | selEnd = QMIN(selEnd, start+len);
|
---|
4772 | bool extendRight = FALSE;
|
---|
4773 | bool extendLeft = FALSE;
|
---|
4774 | bool selWrap = (real_selEnd == length()-1 && n && n->hasSelection(it.key()));
|
---|
4775 | if (selWrap || this->str->at(real_selEnd).lineStart) {
|
---|
4776 | extendRight = (fullSelectionWidth != 0);
|
---|
4777 | if (!extendRight && !rightToLeft)
|
---|
4778 | tmpw += painter.fontMetrics().width(' ');
|
---|
4779 | }
|
---|
4780 | if (fullSelectionWidth && (selStart == 0 || this->str->at(selStart).lineStart)) {
|
---|
4781 | extendLeft = TRUE;
|
---|
4782 | }
|
---|
4783 | if (this->str->isRightToLeft() != rightToLeft)
|
---|
4784 | extendLeft = extendRight = FALSE;
|
---|
4785 |
|
---|
4786 | if (this->str->isRightToLeft()) {
|
---|
4787 | bool tmp = extendLeft;
|
---|
4788 | extendLeft = extendRight;
|
---|
4789 | extendRight = tmp;
|
---|
4790 | }
|
---|
4791 |
|
---|
4792 | if (selStart < real_selEnd ||
|
---|
4793 | selWrap && fullSelectionWidth && extendRight &&
|
---|
4794 | // don't draw the standard selection on a printer=
|
---|
4795 | (it.key() != QTextDocument::Standard || !is_printer( &painter))) {
|
---|
4796 | int selection = it.key();
|
---|
4797 | QColor color;
|
---|
4798 | setColorForSelection( color, painter, cg, selection );
|
---|
4799 | if (selStart != start || selEnd != start + len || selWrap) {
|
---|
4800 | // have to clip
|
---|
4801 | painter.save();
|
---|
4802 | int cs, ce;
|
---|
4803 | if (rightToLeft) {
|
---|
4804 | cs = (selEnd != start + len) ?
|
---|
4805 | this->str->at(this->str->previousCursorPosition(selEnd)).x : xstart;
|
---|
4806 | ce = (selStart != start) ?
|
---|
4807 | this->str->at(this->str->previousCursorPosition(selStart)).x : xstart+tmpw;
|
---|
4808 | } else {
|
---|
4809 | cs = (selStart != start) ? this->str->at(selStart).x : xstart;
|
---|
4810 | ce = (selEnd != start + len) ? this->str->at(selEnd).x : xstart+tmpw;
|
---|
4811 | }
|
---|
4812 | QRect r(cs, y, ce-cs, h);
|
---|
4813 | if (extendLeft)
|
---|
4814 | r.setLeft(0);
|
---|
4815 | if (extendRight)
|
---|
4816 | r.setRight(fullSelectionWidth);
|
---|
4817 | QRegion reg(r);
|
---|
4818 | if ( painter.hasClipping() )
|
---|
4819 | reg &= painter.clipRegion(QPainter::CoordPainter);
|
---|
4820 | painter.setClipRegion(reg, QPainter::CoordPainter);
|
---|
4821 | }
|
---|
4822 | int xleft = xstart;
|
---|
4823 | if ( extendLeft ) {
|
---|
4824 | tmpw += xstart;
|
---|
4825 | xleft = 0;
|
---|
4826 | }
|
---|
4827 | if ( extendRight )
|
---|
4828 | tmpw = fullSelectionWidth - xleft;
|
---|
4829 | painter.fillRect( xleft, y, tmpw, h, color );
|
---|
4830 | painter.drawText( xstart, y + baseLine, str, start, len, dir );
|
---|
4831 | if (selStart != start || selEnd != start + len || selWrap)
|
---|
4832 | painter.restore();
|
---|
4833 | }
|
---|
4834 | }
|
---|
4835 | }
|
---|
4836 |
|
---|
4837 | if ( format->isMisspelled() ) {
|
---|
4838 | painter.save();
|
---|
4839 | painter.setPen( QPen( Qt::red, 1, Qt::DotLine ) );
|
---|
4840 | painter.drawLine( xstart, y + baseLine + 1, xstart + w, y + baseLine + 1 );
|
---|
4841 | painter.restore();
|
---|
4842 | }
|
---|
4843 |
|
---|
4844 | if ( hasdoc && formatChar->isAnchor() && !formatChar->anchorHref().isEmpty() &&
|
---|
4845 | document()->focusIndicator.parag == this &&
|
---|
4846 | ( document()->focusIndicator.start >= start &&
|
---|
4847 | document()->focusIndicator.start + document()->focusIndicator.len <= start + len ||
|
---|
4848 | document()->focusIndicator.start <= start &&
|
---|
4849 | document()->focusIndicator.start + document()->focusIndicator.len >= start + len ) )
|
---|
4850 | painter.drawWinFocusRect( QRect( xstart, y, w, h ) );
|
---|
4851 | }
|
---|
4852 |
|
---|
4853 | void QTextParagraph::drawLabel( QPainter* p, int x, int y, int w, int h, int base, const QColorGroup& cg )
|
---|
4854 | {
|
---|
4855 | QRect r ( x, y, w, h );
|
---|
4856 | QStyleSheetItem::ListStyle s = listStyle();
|
---|
4857 |
|
---|
4858 | p->save();
|
---|
4859 | QTextFormat *format = at( 0 )->format();
|
---|
4860 | if ( format ) {
|
---|
4861 | p->setPen( format->color() );
|
---|
4862 | p->setFont( format->font() );
|
---|
4863 | }
|
---|
4864 | QFontMetrics fm( p->fontMetrics() );
|
---|
4865 | int size = fm.lineSpacing() / 3;
|
---|
4866 |
|
---|
4867 | bool rtl = str->isRightToLeft();
|
---|
4868 |
|
---|
4869 | switch ( s ) {
|
---|
4870 | case QStyleSheetItem::ListDecimal:
|
---|
4871 | case QStyleSheetItem::ListLowerAlpha:
|
---|
4872 | case QStyleSheetItem::ListUpperAlpha:
|
---|
4873 | {
|
---|
4874 | if ( list_val == -1 ) { // uninitialised list value, calcluate the right one
|
---|
4875 | int depth = listDepth();
|
---|
4876 | list_val--;
|
---|
4877 | // ### evil, square and expensive. This needs to be done when formatting, not when painting
|
---|
4878 | QTextParagraph* s = prev();
|
---|
4879 | int depth_s;
|
---|
4880 | while ( s && (depth_s = s->listDepth()) >= depth ) {
|
---|
4881 | if ( depth_s == depth && s->isListItem() )
|
---|
4882 | list_val--;
|
---|
4883 | s = s->prev();
|
---|
4884 | }
|
---|
4885 | }
|
---|
4886 |
|
---|
4887 | int n = list_val;
|
---|
4888 | if ( n < -1 )
|
---|
4889 | n = -n - 1;
|
---|
4890 | QString l;
|
---|
4891 | switch ( s ) {
|
---|
4892 | case QStyleSheetItem::ListLowerAlpha:
|
---|
4893 | if ( n < 27 ) {
|
---|
4894 | l = QChar( ('a' + (char) (n-1)));
|
---|
4895 | break;
|
---|
4896 | }
|
---|
4897 | case QStyleSheetItem::ListUpperAlpha:
|
---|
4898 | if ( n < 27 ) {
|
---|
4899 | l = QChar( ('A' + (char) (n-1)));
|
---|
4900 | break;
|
---|
4901 | }
|
---|
4902 | break;
|
---|
4903 | default: //QStyleSheetItem::ListDecimal:
|
---|
4904 | l.setNum( n );
|
---|
4905 | break;
|
---|
4906 | }
|
---|
4907 | if (rtl)
|
---|
4908 | l.prepend(" .");
|
---|
4909 | else
|
---|
4910 | l += QString::fromLatin1(". ");
|
---|
4911 | int x = ( rtl ? r.left() : r.right() - fm.width(l));
|
---|
4912 | p->drawText( x, r.top() + base, l );
|
---|
4913 | }
|
---|
4914 | break;
|
---|
4915 | case QStyleSheetItem::ListSquare:
|
---|
4916 | {
|
---|
4917 | int x = rtl ? r.left() + size : r.right() - size*2;
|
---|
4918 | QRect er( x, r.top() + fm.height() / 2 - size / 2, size, size );
|
---|
4919 | p->fillRect( er , cg.brush( QColorGroup::Text ) );
|
---|
4920 | }
|
---|
4921 | break;
|
---|
4922 | case QStyleSheetItem::ListCircle:
|
---|
4923 | {
|
---|
4924 | int x = rtl ? r.left() + size : r.right() - size*2;
|
---|
4925 | QRect er( x, r.top() + fm.height() / 2 - size / 2, size, size);
|
---|
4926 | p->drawEllipse( er );
|
---|
4927 | }
|
---|
4928 | break;
|
---|
4929 | case QStyleSheetItem::ListDisc:
|
---|
4930 | default:
|
---|
4931 | {
|
---|
4932 | p->setBrush( cg.brush( QColorGroup::Text ));
|
---|
4933 | int x = rtl ? r.left() + size : r.right() - size*2;
|
---|
4934 | QRect er( x, r.top() + fm.height() / 2 - size / 2, size, size);
|
---|
4935 | p->drawEllipse( er );
|
---|
4936 | p->setBrush( Qt::NoBrush );
|
---|
4937 | }
|
---|
4938 | break;
|
---|
4939 | }
|
---|
4940 |
|
---|
4941 | p->restore();
|
---|
4942 | }
|
---|
4943 |
|
---|
4944 | #ifndef QT_NO_DATASTREAM
|
---|
4945 | void QTextParagraph::readStyleInformation( QDataStream& stream )
|
---|
4946 | {
|
---|
4947 | int int_align, int_lstyle;
|
---|
4948 | uchar uchar_litem, uchar_rtext, uchar_dir;
|
---|
4949 | stream >> int_align >> int_lstyle >> utm >> ubm >> ulm >> urm >> uflm
|
---|
4950 | >> ulinespacing >> ldepth >> uchar_litem >> uchar_rtext >> uchar_dir;
|
---|
4951 | align = int_align; lstyle = (QStyleSheetItem::ListStyle) int_lstyle;
|
---|
4952 | litem = uchar_litem; rtext = uchar_rtext; str->setDirection( (QChar::Direction)uchar_dir );
|
---|
4953 | QTextParagraph* s = prev() ? prev() : this;
|
---|
4954 | while ( s ) {
|
---|
4955 | s->invalidate( 0 );
|
---|
4956 | s = s->next();
|
---|
4957 | }
|
---|
4958 | }
|
---|
4959 |
|
---|
4960 | void QTextParagraph::writeStyleInformation( QDataStream& stream ) const
|
---|
4961 | {
|
---|
4962 | stream << (int) align << (int) lstyle << utm << ubm << ulm << urm << uflm << ulinespacing << ldepth << (uchar)litem << (uchar)rtext << (uchar)str->direction();
|
---|
4963 | }
|
---|
4964 | #endif
|
---|
4965 |
|
---|
4966 |
|
---|
4967 | void QTextParagraph::setListItem( bool li )
|
---|
4968 | {
|
---|
4969 | if ( (bool)litem == li )
|
---|
4970 | return;
|
---|
4971 | litem = li;
|
---|
4972 | changed = TRUE;
|
---|
4973 | QTextParagraph* s = prev() ? prev() : this;
|
---|
4974 | while ( s ) {
|
---|
4975 | s->invalidate( 0 );
|
---|
4976 | s = s->next();
|
---|
4977 | }
|
---|
4978 | }
|
---|
4979 |
|
---|
4980 | void QTextParagraph::setListDepth( int depth ) {
|
---|
4981 | if ( !hasdoc || depth == ldepth )
|
---|
4982 | return;
|
---|
4983 | ldepth = depth;
|
---|
4984 | QTextParagraph* s = prev() ? prev() : this;
|
---|
4985 | while ( s ) {
|
---|
4986 | s->invalidate( 0 );
|
---|
4987 | s = s->next();
|
---|
4988 | }
|
---|
4989 | }
|
---|
4990 |
|
---|
4991 | int *QTextParagraph::tabArray() const
|
---|
4992 | {
|
---|
4993 | int *ta = tArray;
|
---|
4994 | if ( !ta && hasdoc )
|
---|
4995 | ta = document()->tabArray();
|
---|
4996 | return ta;
|
---|
4997 | }
|
---|
4998 |
|
---|
4999 | int QTextParagraph::nextTab( int, int x )
|
---|
5000 | {
|
---|
5001 | int *ta = tArray;
|
---|
5002 | if ( hasdoc ) {
|
---|
5003 | if ( !ta )
|
---|
5004 | ta = document()->tabArray();
|
---|
5005 | tabStopWidth = document()->tabStopWidth();
|
---|
5006 | }
|
---|
5007 | if ( ta ) {
|
---|
5008 | int i = 0;
|
---|
5009 | while ( ta[ i ] ) {
|
---|
5010 | if ( ta[ i ] >= x )
|
---|
5011 | return tArray[ i ];
|
---|
5012 | ++i;
|
---|
5013 | }
|
---|
5014 | return tArray[ 0 ];
|
---|
5015 | } else {
|
---|
5016 | int d;
|
---|
5017 | if ( tabStopWidth != 0 )
|
---|
5018 | d = x / tabStopWidth;
|
---|
5019 | else
|
---|
5020 | return x;
|
---|
5021 | return tabStopWidth * ( d + 1 );
|
---|
5022 | }
|
---|
5023 | }
|
---|
5024 |
|
---|
5025 | void QTextParagraph::adjustToPainter( QPainter *p )
|
---|
5026 | {
|
---|
5027 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
5028 | for ( int i = 0; i < length(); ++i ) {
|
---|
5029 | if ( at( i )->isCustom() )
|
---|
5030 | at( i )->customItem()->adjustToPainter( p );
|
---|
5031 | }
|
---|
5032 | #endif
|
---|
5033 | }
|
---|
5034 |
|
---|
5035 | QTextFormatCollection *QTextParagraph::formatCollection() const
|
---|
5036 | {
|
---|
5037 | if ( hasdoc )
|
---|
5038 | return document()->formatCollection();
|
---|
5039 | QTextFormatCollection* fc = &pseudoDocument()->collection;
|
---|
5040 | if ( paintdevice != fc->paintDevice() )
|
---|
5041 | fc->setPaintDevice( paintdevice );
|
---|
5042 | return fc;
|
---|
5043 | }
|
---|
5044 |
|
---|
5045 | QString QTextParagraph::richText() const
|
---|
5046 | {
|
---|
5047 | QString s;
|
---|
5048 | QTextStringChar *formatChar = 0;
|
---|
5049 | QString spaces;
|
---|
5050 | bool doStart = richTextExportStart && richTextExportStart->paragraph() == this;
|
---|
5051 | bool doEnd = richTextExportEnd && richTextExportEnd->paragraph() == this;
|
---|
5052 | int i;
|
---|
5053 | for ( i = 0; i < length()-1; ++i ) {
|
---|
5054 | if ( doStart && i && richTextExportStart->index() == i )
|
---|
5055 | s += "<!--StartFragment-->";
|
---|
5056 | if ( doEnd && richTextExportEnd->index() == i )
|
---|
5057 | s += "<!--EndFragment-->";
|
---|
5058 | QTextStringChar *c = &str->at( i );
|
---|
5059 | if ( c->isAnchor() && !c->anchorName().isEmpty() ) {
|
---|
5060 | if ( c->anchorName().contains( '#' ) ) {
|
---|
5061 | QStringList l = QStringList::split( '#', c->anchorName() );
|
---|
5062 | for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it )
|
---|
5063 | s += "<a name=\"" + *it + "\"></a>";
|
---|
5064 | } else {
|
---|
5065 | s += "<a name=\"" + c->anchorName() + "\"></a>";
|
---|
5066 | }
|
---|
5067 | }
|
---|
5068 | if ( !formatChar ) {
|
---|
5069 | s += c->format()->makeFormatChangeTags( formatCollection()->defaultFormat(),
|
---|
5070 | 0, QString::null, c->anchorHref() );
|
---|
5071 | formatChar = c;
|
---|
5072 | } else if ( ( formatChar->format()->key() != c->format()->key() ) ||
|
---|
5073 | (c->anchorHref() != formatChar->anchorHref() ) ) {
|
---|
5074 | s += c->format()->makeFormatChangeTags( formatCollection()->defaultFormat(),
|
---|
5075 | formatChar->format() , formatChar->anchorHref(), c->anchorHref() );
|
---|
5076 | formatChar = c;
|
---|
5077 | }
|
---|
5078 | if ( c->c == '<' )
|
---|
5079 | s += "<";
|
---|
5080 | else if ( c->c == '>' )
|
---|
5081 | s += ">";
|
---|
5082 | else if ( c->c =='&' )
|
---|
5083 | s += "&";
|
---|
5084 | else if ( c->c =='\"' )
|
---|
5085 | s += """;
|
---|
5086 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
5087 | else if ( c->isCustom() )
|
---|
5088 | s += c->customItem()->richText();
|
---|
5089 | #endif
|
---|
5090 | else if ( c->c == '\n' || c->c == QChar_linesep )
|
---|
5091 | s += "<br />"; // space on purpose for compatibility with Netscape, Lynx & Co.
|
---|
5092 | else
|
---|
5093 | s += c->c;
|
---|
5094 | }
|
---|
5095 | if ( doEnd && richTextExportEnd->index() == i )
|
---|
5096 | s += "<!--EndFragment-->";
|
---|
5097 | if ( formatChar )
|
---|
5098 | s += formatChar->format()->makeFormatEndTags( formatCollection()->defaultFormat(), formatChar->anchorHref() );
|
---|
5099 | return s;
|
---|
5100 | }
|
---|
5101 |
|
---|
5102 | void QTextParagraph::addCommand( QTextCommand *cmd )
|
---|
5103 | {
|
---|
5104 | if ( !hasdoc )
|
---|
5105 | pseudoDocument()->commandHistory->addCommand( cmd );
|
---|
5106 | else
|
---|
5107 | document()->commands()->addCommand( cmd );
|
---|
5108 | }
|
---|
5109 |
|
---|
5110 | QTextCursor *QTextParagraph::undo( QTextCursor *c )
|
---|
5111 | {
|
---|
5112 | if ( !hasdoc )
|
---|
5113 | return pseudoDocument()->commandHistory->undo( c );
|
---|
5114 | return document()->commands()->undo( c );
|
---|
5115 | }
|
---|
5116 |
|
---|
5117 | QTextCursor *QTextParagraph::redo( QTextCursor *c )
|
---|
5118 | {
|
---|
5119 | if ( !hasdoc )
|
---|
5120 | return pseudoDocument()->commandHistory->redo( c );
|
---|
5121 | return document()->commands()->redo( c );
|
---|
5122 | }
|
---|
5123 |
|
---|
5124 | int QTextParagraph::topMargin() const
|
---|
5125 | {
|
---|
5126 | int m = 0;
|
---|
5127 | if ( rtext ) {
|
---|
5128 | m = isListItem() ? (document()->li_tm/QMAX(1,listDepth()*listDepth())) :
|
---|
5129 | ( listDepth() ? 0 : document()->par_tm );
|
---|
5130 | if ( listDepth() == 1 &&( !prev() || prev()->listDepth() < listDepth() ) )
|
---|
5131 | m = QMAX( m, document()->list_tm );
|
---|
5132 | }
|
---|
5133 | m += utm;
|
---|
5134 | return scale( m, QTextFormat::painter() );
|
---|
5135 | }
|
---|
5136 |
|
---|
5137 | int QTextParagraph::bottomMargin() const
|
---|
5138 | {
|
---|
5139 | int m = 0;
|
---|
5140 | if ( rtext ) {
|
---|
5141 | m = isListItem() ? (document()->li_bm/QMAX(1,listDepth()*listDepth())) :
|
---|
5142 | ( listDepth() ? 0 : document()->par_bm );
|
---|
5143 | if ( listDepth() == 1 &&( !next() || next()->listDepth() < listDepth() ) )
|
---|
5144 | m = QMAX( m, document()->list_bm );
|
---|
5145 | }
|
---|
5146 | m += ubm;
|
---|
5147 | return scale( m, QTextFormat::painter() );
|
---|
5148 | }
|
---|
5149 |
|
---|
5150 | int QTextParagraph::leftMargin() const
|
---|
5151 | {
|
---|
5152 | int m = ulm;
|
---|
5153 | if ( listDepth() && !string()->isRightToLeft() )
|
---|
5154 | m += listDepth() * document()->list_lm;
|
---|
5155 | return scale( m, QTextFormat::painter() );
|
---|
5156 | }
|
---|
5157 |
|
---|
5158 | int QTextParagraph::firstLineMargin() const
|
---|
5159 | {
|
---|
5160 | int m = uflm;
|
---|
5161 | return scale( m, QTextFormat::painter() );
|
---|
5162 | }
|
---|
5163 |
|
---|
5164 | int QTextParagraph::rightMargin() const
|
---|
5165 | {
|
---|
5166 | int m = urm;
|
---|
5167 | if ( listDepth() && string()->isRightToLeft() )
|
---|
5168 | m += listDepth() * document()->list_lm;
|
---|
5169 | return scale( m, QTextFormat::painter() );
|
---|
5170 | }
|
---|
5171 |
|
---|
5172 | int QTextParagraph::lineSpacing() const
|
---|
5173 | {
|
---|
5174 | int l = ulinespacing;
|
---|
5175 | l = scale( l, QTextFormat::painter() );
|
---|
5176 | return l;
|
---|
5177 | }
|
---|
5178 |
|
---|
5179 | void QTextParagraph::copyParagData( QTextParagraph *parag )
|
---|
5180 | {
|
---|
5181 | rtext = parag->rtext;
|
---|
5182 | lstyle = parag->lstyle;
|
---|
5183 | ldepth = parag->ldepth;
|
---|
5184 | litem = parag->litem;
|
---|
5185 | align = parag->align;
|
---|
5186 | utm = parag->utm;
|
---|
5187 | ubm = parag->ubm;
|
---|
5188 | urm = parag->urm;
|
---|
5189 | ulm = parag->ulm;
|
---|
5190 | uflm = parag->uflm;
|
---|
5191 | ulinespacing = parag->ulinespacing;
|
---|
5192 | QColor *c = parag->backgroundColor();
|
---|
5193 | if ( c )
|
---|
5194 | setBackgroundColor( *c );
|
---|
5195 | str->setDirection( parag->str->direction() );
|
---|
5196 | }
|
---|
5197 |
|
---|
5198 | void QTextParagraph::show()
|
---|
5199 | {
|
---|
5200 | if ( visible || !hasdoc )
|
---|
5201 | return;
|
---|
5202 | visible = TRUE;
|
---|
5203 | }
|
---|
5204 |
|
---|
5205 | void QTextParagraph::hide()
|
---|
5206 | {
|
---|
5207 | if ( !visible || !hasdoc )
|
---|
5208 | return;
|
---|
5209 | visible = FALSE;
|
---|
5210 | }
|
---|
5211 |
|
---|
5212 | void QTextParagraph::setDirection( QChar::Direction d )
|
---|
5213 | {
|
---|
5214 | if ( str && str->direction() != d ) {
|
---|
5215 | str->setDirection( d );
|
---|
5216 | invalidate( 0 );
|
---|
5217 | }
|
---|
5218 | }
|
---|
5219 |
|
---|
5220 | QChar::Direction QTextParagraph::direction() const
|
---|
5221 | {
|
---|
5222 | return (str ? str->direction() : QChar::DirON );
|
---|
5223 | }
|
---|
5224 |
|
---|
5225 | void QTextParagraph::setChanged( bool b, bool recursive )
|
---|
5226 | {
|
---|
5227 | changed = b;
|
---|
5228 | if ( recursive ) {
|
---|
5229 | if ( document() && document()->parentParagraph() )
|
---|
5230 | document()->parentParagraph()->setChanged( b, recursive );
|
---|
5231 | }
|
---|
5232 | }
|
---|
5233 |
|
---|
5234 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
5235 |
|
---|
5236 |
|
---|
5237 | QTextPreProcessor::QTextPreProcessor()
|
---|
5238 | {
|
---|
5239 | }
|
---|
5240 |
|
---|
5241 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
5242 |
|
---|
5243 | QTextFormatter::QTextFormatter()
|
---|
5244 | : thisminw(0), thiswused(0), wrapEnabled( TRUE ), wrapColumn( -1 ), biw( FALSE )
|
---|
5245 | {
|
---|
5246 | }
|
---|
5247 |
|
---|
5248 | QTextLineStart *QTextFormatter::formatLine( QTextParagraph *parag, QTextString *string, QTextLineStart *line,
|
---|
5249 | QTextStringChar *startChar, QTextStringChar *lastChar, int align, int space )
|
---|
5250 | {
|
---|
5251 | if ( lastChar < startChar )
|
---|
5252 | return new QTextLineStart;
|
---|
5253 | #ifndef QT_NO_COMPLEXTEXT
|
---|
5254 | if( string->isBidi() )
|
---|
5255 | return bidiReorderLine( parag, string, line, startChar, lastChar, align, space );
|
---|
5256 | #endif
|
---|
5257 | int start = (startChar - &string->at(0));
|
---|
5258 | int last = (lastChar - &string->at(0) );
|
---|
5259 |
|
---|
5260 | // ignore white space at the end of the line.
|
---|
5261 | QTextStringChar *ch = lastChar;
|
---|
5262 | while ( ch > startChar && ch->whiteSpace ) {
|
---|
5263 | space += ch->format()->width( ' ' );
|
---|
5264 | --ch;
|
---|
5265 | }
|
---|
5266 |
|
---|
5267 | if (space < 0)
|
---|
5268 | space = 0;
|
---|
5269 |
|
---|
5270 | // do alignment Auto == Left in this case
|
---|
5271 | if ( align & Qt::AlignHCenter || align & Qt::AlignRight ) {
|
---|
5272 | if ( align & Qt::AlignHCenter )
|
---|
5273 | space /= 2;
|
---|
5274 | for ( int j = start; j <= last; ++j )
|
---|
5275 | string->at( j ).x += space;
|
---|
5276 | } else if ( align & Qt::AlignJustify ) {
|
---|
5277 | int numSpaces = 0;
|
---|
5278 | // End at "last-1", the last space ends up with a width of 0
|
---|
5279 | for ( int j = last-1; j >= start; --j ) {
|
---|
5280 | // Start at last tab, if any.
|
---|
5281 | QTextStringChar &ch = string->at( j );
|
---|
5282 | if ( ch.c == '\t' ) {
|
---|
5283 | start = j+1;
|
---|
5284 | break;
|
---|
5285 | }
|
---|
5286 | if(ch.whiteSpace)
|
---|
5287 | numSpaces++;
|
---|
5288 | }
|
---|
5289 | int toAdd = 0;
|
---|
5290 | for ( int k = start + 1; k <= last; ++k ) {
|
---|
5291 | QTextStringChar &ch = string->at( k );
|
---|
5292 | if( numSpaces && ch.whiteSpace ) {
|
---|
5293 | int s = space / numSpaces;
|
---|
5294 | toAdd += s;
|
---|
5295 | space -= s;
|
---|
5296 | numSpaces--;
|
---|
5297 | }
|
---|
5298 | string->at( k ).x += toAdd;
|
---|
5299 | }
|
---|
5300 | }
|
---|
5301 |
|
---|
5302 | if ( last >= 0 && last < string->length() )
|
---|
5303 | line->w = string->at( last ).x + string->width( last );
|
---|
5304 | else
|
---|
5305 | line->w = 0;
|
---|
5306 |
|
---|
5307 | return new QTextLineStart;
|
---|
5308 | }
|
---|
5309 |
|
---|
5310 | #ifndef QT_NO_COMPLEXTEXT
|
---|
5311 |
|
---|
5312 | #ifdef BIDI_DEBUG
|
---|
5313 | #include <iostream>
|
---|
5314 | #endif
|
---|
5315 |
|
---|
5316 | // collects one line of the paragraph and transforms it to visual order
|
---|
5317 | QTextLineStart *QTextFormatter::bidiReorderLine( QTextParagraph * /*parag*/, QTextString *text, QTextLineStart *line,
|
---|
5318 | QTextStringChar *startChar, QTextStringChar *lastChar, int align, int space )
|
---|
5319 | {
|
---|
5320 | // ignore white space at the end of the line.
|
---|
5321 | int endSpaces = 0;
|
---|
5322 | while ( lastChar > startChar && lastChar->whiteSpace ) {
|
---|
5323 | space += lastChar->format()->width( ' ' );
|
---|
5324 | --lastChar;
|
---|
5325 | ++endSpaces;
|
---|
5326 | }
|
---|
5327 |
|
---|
5328 | int start = (startChar - &text->at(0));
|
---|
5329 | int last = (lastChar - &text->at(0) );
|
---|
5330 |
|
---|
5331 | int length = lastChar - startChar + 1;
|
---|
5332 |
|
---|
5333 |
|
---|
5334 | int x = startChar->x;
|
---|
5335 |
|
---|
5336 | unsigned char _levels[256];
|
---|
5337 | int _visual[256];
|
---|
5338 |
|
---|
5339 | unsigned char *levels = _levels;
|
---|
5340 | int *visual = _visual;
|
---|
5341 |
|
---|
5342 | if ( length > 255 ) {
|
---|
5343 | levels = (unsigned char *)malloc( length*sizeof( unsigned char ) );
|
---|
5344 | visual = (int *)malloc( length*sizeof( int ) );
|
---|
5345 | }
|
---|
5346 |
|
---|
5347 | //qDebug("bidiReorderLine: length=%d (%d-%d)", length, start, last );
|
---|
5348 |
|
---|
5349 | QTextStringChar *ch = startChar;
|
---|
5350 | unsigned char *l = levels;
|
---|
5351 | while ( ch <= lastChar ) {
|
---|
5352 | //qDebug( " level: %d", ch->bidiLevel );
|
---|
5353 | *(l++) = (ch++)->bidiLevel;
|
---|
5354 | }
|
---|
5355 |
|
---|
5356 | QTextEngine::bidiReorder( length, levels, visual );
|
---|
5357 |
|
---|
5358 | // now construct the reordered string out of the runs...
|
---|
5359 |
|
---|
5360 | int numSpaces = 0;
|
---|
5361 | // set the correct alignment. This is a bit messy....
|
---|
5362 | if( align == Qt::AlignAuto ) {
|
---|
5363 | // align according to directionality of the paragraph...
|
---|
5364 | if ( text->isRightToLeft() )
|
---|
5365 | align = Qt::AlignRight;
|
---|
5366 | }
|
---|
5367 |
|
---|
5368 | // This is not really correct, but as we can't make the scrollbar move to the left of the origin,
|
---|
5369 | // this ensures all text can be scrolled to and read.
|
---|
5370 | if (space < 0)
|
---|
5371 | space = 0;
|
---|
5372 |
|
---|
5373 | if ( align & Qt::AlignHCenter )
|
---|
5374 | x += space/2;
|
---|
5375 | else if ( align & Qt::AlignRight )
|
---|
5376 | x += space;
|
---|
5377 | else if ( align & Qt::AlignJustify ) {
|
---|
5378 | // End at "last-1", the last space ends up with a width of 0
|
---|
5379 | for ( int j = last-1; j >= start; --j ) {
|
---|
5380 | // Start at last tab, if any.
|
---|
5381 | QTextStringChar &ch = text->at( j );
|
---|
5382 | if ( ch.c == '\t' ) {
|
---|
5383 | start = j+1;
|
---|
5384 | break;
|
---|
5385 | }
|
---|
5386 | if(ch.whiteSpace)
|
---|
5387 | numSpaces++;
|
---|
5388 | }
|
---|
5389 | }
|
---|
5390 |
|
---|
5391 | int toAdd = 0;
|
---|
5392 | int xorig = x;
|
---|
5393 | QTextStringChar *lc = startChar + visual[0];
|
---|
5394 | for ( int i = 0; i < length; i++ ) {
|
---|
5395 | QTextStringChar *ch = startChar + visual[i];
|
---|
5396 | if (numSpaces && ch->whiteSpace) {
|
---|
5397 | int s = space / numSpaces;
|
---|
5398 | toAdd += s;
|
---|
5399 | space -= s;
|
---|
5400 | numSpaces--;
|
---|
5401 | }
|
---|
5402 |
|
---|
5403 | if (lc->format() != ch->format() && !ch->c.isSpace()
|
---|
5404 | && lc->format()->font().italic() && !ch->format()->font().italic()) {
|
---|
5405 | int rb = lc->format()->fontMetrics().rightBearing(lc->c);
|
---|
5406 | if (rb < 0)
|
---|
5407 | x -= rb;
|
---|
5408 | }
|
---|
5409 |
|
---|
5410 | ch->x = x + toAdd;
|
---|
5411 | //qDebug("visual: %d (%p) placed at %d rightToLeft=%d", visual[i], ch, x +toAdd, ch->rightToLeft );
|
---|
5412 | int ww = 0;
|
---|
5413 | if ( ch->c.unicode() >= 32 || ch->c == '\t' || ch->c == '\n' || ch->isCustom() ) {
|
---|
5414 | ww = text->width( start+visual[i] );
|
---|
5415 | } else {
|
---|
5416 | ww = ch->format()->width( ' ' );
|
---|
5417 | }
|
---|
5418 | x += ww;
|
---|
5419 | lc = ch;
|
---|
5420 | }
|
---|
5421 | x += toAdd;
|
---|
5422 |
|
---|
5423 | while ( endSpaces-- ) {
|
---|
5424 | ++lastChar;
|
---|
5425 | int sw = lastChar->format()->width( ' ' );
|
---|
5426 | if ( lastChar->rightToLeft ) {
|
---|
5427 | xorig -= sw;
|
---|
5428 | lastChar->x = xorig;
|
---|
5429 | } else {
|
---|
5430 | lastChar->x = x;
|
---|
5431 | x += sw;
|
---|
5432 | }
|
---|
5433 | }
|
---|
5434 |
|
---|
5435 | line->w = x;
|
---|
5436 |
|
---|
5437 | if ( length > 255 ) {
|
---|
5438 | free( levels );
|
---|
5439 | free( visual );
|
---|
5440 | }
|
---|
5441 |
|
---|
5442 | return new QTextLineStart;
|
---|
5443 | }
|
---|
5444 | #endif
|
---|
5445 |
|
---|
5446 |
|
---|
5447 | void QTextFormatter::insertLineStart( QTextParagraph *parag, int index, QTextLineStart *ls )
|
---|
5448 | {
|
---|
5449 | QMap<int, QTextLineStart*>::Iterator it;
|
---|
5450 | if ( ( it = parag->lineStartList().find( index ) ) == parag->lineStartList().end() ) {
|
---|
5451 | parag->lineStartList().insert( index, ls );
|
---|
5452 | } else {
|
---|
5453 | delete *it;
|
---|
5454 | parag->lineStartList().remove( it );
|
---|
5455 | parag->lineStartList().insert( index, ls );
|
---|
5456 | }
|
---|
5457 | }
|
---|
5458 |
|
---|
5459 |
|
---|
5460 | /* Standard pagebreak algorithm using QTextFlow::adjustFlow. Returns
|
---|
5461 | the shift of the paragraphs bottom line.
|
---|
5462 | */
|
---|
5463 | int QTextFormatter::formatVertically( QTextDocument* doc, QTextParagraph* parag )
|
---|
5464 | {
|
---|
5465 | int oldHeight = parag->rect().height();
|
---|
5466 | QMap<int, QTextLineStart*>& lineStarts = parag->lineStartList();
|
---|
5467 | QMap<int, QTextLineStart*>::Iterator it = lineStarts.begin();
|
---|
5468 | int h = parag->prev() ? QMAX(parag->prev()->bottomMargin(),parag->topMargin() ) / 2: 0;
|
---|
5469 | for ( ; it != lineStarts.end() ; ++it ) {
|
---|
5470 | QTextLineStart * ls = it.data();
|
---|
5471 | ls->y = h;
|
---|
5472 | QTextStringChar *c = ¶g->string()->at(it.key());
|
---|
5473 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
5474 | if ( c && c->customItem() && c->customItem()->ownLine() ) {
|
---|
5475 | int h = c->customItem()->height;
|
---|
5476 | c->customItem()->pageBreak( parag->rect().y() + ls->y + ls->baseLine - h, doc->flow() );
|
---|
5477 | int delta = c->customItem()->height - h;
|
---|
5478 | ls->h += delta;
|
---|
5479 | if ( delta )
|
---|
5480 | parag->setMovedDown( TRUE );
|
---|
5481 | } else
|
---|
5482 | #endif
|
---|
5483 | {
|
---|
5484 |
|
---|
5485 | int shift = doc->flow()->adjustFlow( parag->rect().y() + ls->y, ls->w, ls->h );
|
---|
5486 | ls->y += shift;
|
---|
5487 | if ( shift )
|
---|
5488 | parag->setMovedDown( TRUE );
|
---|
5489 | }
|
---|
5490 | h = ls->y + ls->h;
|
---|
5491 | }
|
---|
5492 | int m = parag->bottomMargin();
|
---|
5493 | if ( !parag->next() )
|
---|
5494 | m = 0;
|
---|
5495 | else
|
---|
5496 | m = QMAX(m, parag->next()->topMargin() ) / 2;
|
---|
5497 | h += m;
|
---|
5498 | parag->setHeight( h );
|
---|
5499 | return h - oldHeight;
|
---|
5500 | }
|
---|
5501 |
|
---|
5502 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
5503 |
|
---|
5504 | QTextFormatterBreakInWords::QTextFormatterBreakInWords()
|
---|
5505 | {
|
---|
5506 | }
|
---|
5507 |
|
---|
5508 | #define SPACE(s) s
|
---|
5509 |
|
---|
5510 | int QTextFormatterBreakInWords::format( QTextDocument *doc,QTextParagraph *parag,
|
---|
5511 | int start, const QMap<int, QTextLineStart*> & )
|
---|
5512 | {
|
---|
5513 | // make sure bidi information is correct.
|
---|
5514 | (void )parag->string()->isBidi();
|
---|
5515 |
|
---|
5516 | QTextStringChar *c = 0;
|
---|
5517 | QTextStringChar *firstChar = 0;
|
---|
5518 | int left = doc ? parag->leftMargin() + doc->leftMargin() : 0;
|
---|
5519 | int x = left + ( doc ? parag->firstLineMargin() : 0 );
|
---|
5520 | int dw = parag->documentVisibleWidth() - ( doc ? doc->rightMargin() : 0 );
|
---|
5521 | int y = parag->prev() ? QMAX(parag->prev()->bottomMargin(),parag->topMargin()) / 2: 0;
|
---|
5522 | int h = y;
|
---|
5523 | int len = parag->length();
|
---|
5524 | if ( doc )
|
---|
5525 | x = doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), x, 4 );
|
---|
5526 | int rm = parag->rightMargin();
|
---|
5527 | int w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
|
---|
5528 | bool fullWidth = TRUE;
|
---|
5529 | int minw = 0;
|
---|
5530 | int wused = 0;
|
---|
5531 | bool wrapEnabled = isWrapEnabled( parag );
|
---|
5532 |
|
---|
5533 | start = 0; //######### what is the point with start?! (Matthias)
|
---|
5534 | if ( start == 0 )
|
---|
5535 | c = ¶g->string()->at( 0 );
|
---|
5536 |
|
---|
5537 | int i = start;
|
---|
5538 | QTextLineStart *lineStart = new QTextLineStart( y, y, 0 );
|
---|
5539 | insertLineStart( parag, 0, lineStart );
|
---|
5540 |
|
---|
5541 | QPainter *painter = QTextFormat::painter();
|
---|
5542 |
|
---|
5543 | int col = 0;
|
---|
5544 | int ww = 0;
|
---|
5545 | QChar lastChr;
|
---|
5546 | for ( ; i < len; ++i, ++col ) {
|
---|
5547 | if ( c )
|
---|
5548 | lastChr = c->c;
|
---|
5549 | c = ¶g->string()->at( i );
|
---|
5550 | // ### the lines below should not be needed
|
---|
5551 | if ( painter )
|
---|
5552 | c->format()->setPainter( painter );
|
---|
5553 | if ( i > 0 ) {
|
---|
5554 | c->lineStart = 0;
|
---|
5555 | } else {
|
---|
5556 | c->lineStart = 1;
|
---|
5557 | firstChar = c;
|
---|
5558 | }
|
---|
5559 | if ( c->c.unicode() >= 32 || c->isCustom() ) {
|
---|
5560 | ww = parag->string()->width( i );
|
---|
5561 | } else if ( c->c == '\t' ) {
|
---|
5562 | int nx = parag->nextTab( i, x - left ) + left;
|
---|
5563 | if ( nx < x )
|
---|
5564 | ww = w - x;
|
---|
5565 | else
|
---|
5566 | ww = nx - x;
|
---|
5567 | } else {
|
---|
5568 | ww = c->format()->width( ' ' );
|
---|
5569 | }
|
---|
5570 |
|
---|
5571 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
5572 | if ( c->isCustom() && c->customItem()->ownLine() ) {
|
---|
5573 | x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
|
---|
5574 | w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
|
---|
5575 | c->customItem()->resize( w - x );
|
---|
5576 | w = dw;
|
---|
5577 | y += h;
|
---|
5578 | h = c->height();
|
---|
5579 | lineStart = new QTextLineStart( y, h, h );
|
---|
5580 | insertLineStart( parag, i, lineStart );
|
---|
5581 | c->lineStart = 1;
|
---|
5582 | firstChar = c;
|
---|
5583 | x = 0xffffff;
|
---|
5584 | continue;
|
---|
5585 | }
|
---|
5586 | #endif
|
---|
5587 |
|
---|
5588 | if ( wrapEnabled &&
|
---|
5589 | ( wrapAtColumn() == -1 && x + ww > w ||
|
---|
5590 | wrapAtColumn() != -1 && col >= wrapAtColumn() ) ) {
|
---|
5591 | x = doc ? parag->document()->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
|
---|
5592 | w = dw;
|
---|
5593 | y += h;
|
---|
5594 | h = c->height();
|
---|
5595 | lineStart = formatLine( parag, parag->string(), lineStart, firstChar, c-1 );
|
---|
5596 | lineStart->y = y;
|
---|
5597 | insertLineStart( parag, i, lineStart );
|
---|
5598 | lineStart->baseLine = c->ascent();
|
---|
5599 | lineStart->h = c->height();
|
---|
5600 | c->lineStart = 1;
|
---|
5601 | firstChar = c;
|
---|
5602 | col = 0;
|
---|
5603 | if ( wrapAtColumn() != -1 )
|
---|
5604 | minw = QMAX( minw, w );
|
---|
5605 | } else if ( lineStart ) {
|
---|
5606 | lineStart->baseLine = QMAX( lineStart->baseLine, c->ascent() );
|
---|
5607 | h = QMAX( h, c->height() );
|
---|
5608 | lineStart->h = h;
|
---|
5609 | }
|
---|
5610 |
|
---|
5611 | c->x = x;
|
---|
5612 | x += ww;
|
---|
5613 | wused = QMAX( wused, x );
|
---|
5614 | }
|
---|
5615 |
|
---|
5616 | int m = parag->bottomMargin();
|
---|
5617 | if ( !parag->next() )
|
---|
5618 | m = 0;
|
---|
5619 | else
|
---|
5620 | m = QMAX(m, parag->next()->topMargin() ) / 2;
|
---|
5621 | parag->setFullWidth( fullWidth );
|
---|
5622 | y += h + m;
|
---|
5623 | if ( doc )
|
---|
5624 | minw += doc->rightMargin();
|
---|
5625 | if ( !wrapEnabled )
|
---|
5626 | minw = QMAX(minw, wused);
|
---|
5627 |
|
---|
5628 | thisminw = minw;
|
---|
5629 | thiswused = wused;
|
---|
5630 | return y;
|
---|
5631 | }
|
---|
5632 |
|
---|
5633 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
5634 |
|
---|
5635 | QTextFormatterBreakWords::QTextFormatterBreakWords()
|
---|
5636 | {
|
---|
5637 | }
|
---|
5638 |
|
---|
5639 | #define DO_FLOW( lineStart ) do{ if ( doc && doc->isPageBreakEnabled() ) { \
|
---|
5640 | int yflow = lineStart->y + parag->rect().y();\
|
---|
5641 | int shift = doc->flow()->adjustFlow( yflow, dw, lineStart->h ); \
|
---|
5642 | lineStart->y += shift;\
|
---|
5643 | y += shift;\
|
---|
5644 | }}while(FALSE)
|
---|
5645 |
|
---|
5646 | int QTextFormatterBreakWords::format( QTextDocument *doc, QTextParagraph *parag,
|
---|
5647 | int start, const QMap<int, QTextLineStart*> & )
|
---|
5648 | {
|
---|
5649 | // make sure bidi information is correct.
|
---|
5650 | (void )parag->string()->isBidi();
|
---|
5651 |
|
---|
5652 | QTextStringChar *c = 0;
|
---|
5653 | QTextStringChar *firstChar = 0;
|
---|
5654 | QTextString *string = parag->string();
|
---|
5655 | int left = doc ? parag->leftMargin() + doc->leftMargin() : 0;
|
---|
5656 | int x = left + ( doc ? parag->firstLineMargin() : 0 );
|
---|
5657 | int y = parag->prev() ? QMAX(parag->prev()->bottomMargin(),parag->topMargin()) / 2: 0;
|
---|
5658 | int h = y;
|
---|
5659 | int len = parag->length();
|
---|
5660 | if ( doc )
|
---|
5661 | x = doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), x, 0 );
|
---|
5662 | int dw = parag->documentVisibleWidth() - ( doc ? ( left != x ? 0 : doc->rightMargin() ) : 0 );
|
---|
5663 |
|
---|
5664 | int curLeft = x;
|
---|
5665 | int rm = parag->rightMargin();
|
---|
5666 | int rdiff = doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 0 ) : 0;
|
---|
5667 | int w = dw - rdiff;
|
---|
5668 | bool fullWidth = TRUE;
|
---|
5669 | int marg = left + rdiff;
|
---|
5670 | int minw = 0;
|
---|
5671 | int wused = 0;
|
---|
5672 | int tminw = marg;
|
---|
5673 | int linespacing = doc ? parag->lineSpacing() : 0;
|
---|
5674 | bool wrapEnabled = isWrapEnabled( parag );
|
---|
5675 |
|
---|
5676 | start = 0;
|
---|
5677 |
|
---|
5678 | int i = start;
|
---|
5679 | QTextLineStart *lineStart = new QTextLineStart( y, y, 0 );
|
---|
5680 | insertLineStart( parag, 0, lineStart );
|
---|
5681 | int lastBreak = -1;
|
---|
5682 | int tmpBaseLine = 0, tmph = 0;
|
---|
5683 | bool lastWasNonInlineCustom = FALSE;
|
---|
5684 |
|
---|
5685 | int align = parag->alignment();
|
---|
5686 | if ( align == Qt::AlignAuto && doc && doc->alignment() != Qt::AlignAuto )
|
---|
5687 | align = doc->alignment();
|
---|
5688 |
|
---|
5689 | align &= Qt::AlignHorizontal_Mask;
|
---|
5690 |
|
---|
5691 | // ### hack. The last char in the paragraph is always invisible,
|
---|
5692 | // ### and somehow sometimes has a wrong format. It changes
|
---|
5693 | // ### between // layouting and printing. This corrects some
|
---|
5694 | // ### layouting errors in BiDi mode due to this.
|
---|
5695 | if ( len > 1 ) {
|
---|
5696 | c = ¶g->string()->at(len - 1);
|
---|
5697 | if (!c->isAnchor()) {
|
---|
5698 | c->format()->removeRef();
|
---|
5699 | c->setFormat( string->at( len - 2 ).format() );
|
---|
5700 | c->format()->addRef();
|
---|
5701 | }
|
---|
5702 | }
|
---|
5703 |
|
---|
5704 | c = ¶g->string()->at( 0 );
|
---|
5705 |
|
---|
5706 | QPainter *painter = QTextFormat::painter();
|
---|
5707 | int col = 0;
|
---|
5708 | int ww = 0;
|
---|
5709 | QChar lastChr = c->c;
|
---|
5710 | QTextFormat *lastFormat = c->format();
|
---|
5711 | for ( ; i < len; ++i, ++col ) {
|
---|
5712 | if ( i ) {
|
---|
5713 | c = ¶g->string()->at(i-1);
|
---|
5714 | lastChr = c->c;
|
---|
5715 | lastFormat = c->format();
|
---|
5716 | }
|
---|
5717 | bool lastWasOwnLineCustomItem = lastBreak == -2;
|
---|
5718 | bool hadBreakableChar = lastBreak != -1;
|
---|
5719 | bool lastWasHardBreak = lastChr == QChar_linesep;
|
---|
5720 |
|
---|
5721 | // ### next line should not be needed
|
---|
5722 | if ( painter )
|
---|
5723 | c->format()->setPainter( painter );
|
---|
5724 | c = &string->at( i );
|
---|
5725 |
|
---|
5726 | if (lastFormat != c->format() && !c->c.isSpace()
|
---|
5727 | && lastFormat->font().italic() && !c->format()->font().italic()) {
|
---|
5728 | int rb = lastFormat->fontMetrics().rightBearing(lastChr);
|
---|
5729 | if (rb < 0)
|
---|
5730 | x -= rb;
|
---|
5731 | }
|
---|
5732 |
|
---|
5733 | if ( i > 0 && (x > curLeft || ww == 0) || lastWasNonInlineCustom ) {
|
---|
5734 | c->lineStart = 0;
|
---|
5735 | } else {
|
---|
5736 | c->lineStart = 1;
|
---|
5737 | firstChar = c;
|
---|
5738 | }
|
---|
5739 |
|
---|
5740 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
5741 | lastWasNonInlineCustom = ( c->isCustom() && c->customItem()->placement() != QTextCustomItem::PlaceInline );
|
---|
5742 | #endif
|
---|
5743 |
|
---|
5744 | if ( c->c.unicode() >= 32 || c->isCustom() ) {
|
---|
5745 | ww = string->width( i );
|
---|
5746 | } else if ( c->c == '\t' ) {
|
---|
5747 | if ( align == Qt::AlignRight || align == Qt::AlignCenter ) {
|
---|
5748 | // we can not (yet) do tabs
|
---|
5749 | ww = c->format()->width(' ' );
|
---|
5750 | } else {
|
---|
5751 | int tabx = lastWasHardBreak ? (left + ( doc ? parag->firstLineMargin() : 0 )) : x;
|
---|
5752 | int nx = parag->nextTab( i, tabx - left ) + left;
|
---|
5753 | if ( nx < tabx ) // strrrange...
|
---|
5754 | ww = 0;
|
---|
5755 | else
|
---|
5756 | ww = nx - tabx;
|
---|
5757 | }
|
---|
5758 | } else {
|
---|
5759 | ww = c->format()->width( ' ' );
|
---|
5760 | }
|
---|
5761 |
|
---|
5762 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
5763 | QTextCustomItem* ci = c->customItem();
|
---|
5764 | if ( c->isCustom() && ci->ownLine() ) {
|
---|
5765 | QTextLineStart *lineStart2 = formatLine( parag, string, lineStart, firstChar, c-1, align, SPACE(w - x - ww) );
|
---|
5766 | x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
|
---|
5767 | w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
|
---|
5768 | ci->resize(w - x);
|
---|
5769 | if ( ci->width < w - x ) {
|
---|
5770 | if ( align & Qt::AlignHCenter )
|
---|
5771 | x = ( w - ci->width ) / 2;
|
---|
5772 | else if ( align & Qt::AlignRight ) {
|
---|
5773 | x = w - ci->width;
|
---|
5774 | }
|
---|
5775 | }
|
---|
5776 | c->x = x;
|
---|
5777 | curLeft = x;
|
---|
5778 | if ( i == 0 || !isBreakable(string, i-1) ||
|
---|
5779 | string->at( i - 1 ).lineStart == 0 ) {
|
---|
5780 | y += QMAX( h, QMAX( tmph, linespacing ) );
|
---|
5781 | tmph = c->height();
|
---|
5782 | h = tmph;
|
---|
5783 | lineStart = lineStart2;
|
---|
5784 | lineStart->y = y;
|
---|
5785 | insertLineStart( parag, i, lineStart );
|
---|
5786 | c->lineStart = 1;
|
---|
5787 | firstChar = c;
|
---|
5788 | } else {
|
---|
5789 | tmph = c->height();
|
---|
5790 | h = tmph;
|
---|
5791 | delete lineStart2;
|
---|
5792 | }
|
---|
5793 | lineStart->h = h;
|
---|
5794 | lineStart->baseLine = h;
|
---|
5795 | tmpBaseLine = lineStart->baseLine;
|
---|
5796 | lastBreak = -2;
|
---|
5797 | x = w;
|
---|
5798 | minw = QMAX( minw, tminw );
|
---|
5799 |
|
---|
5800 | int tw = ci->minimumWidth() + ( doc ? doc->leftMargin() : 0 );
|
---|
5801 | if ( tw < QWIDGETSIZE_MAX )
|
---|
5802 | tminw = tw;
|
---|
5803 | else
|
---|
5804 | tminw = marg;
|
---|
5805 | wused = QMAX( wused, ci->width );
|
---|
5806 | continue;
|
---|
5807 | } else if ( c->isCustom() && ci->placement() != QTextCustomItem::PlaceInline ) {
|
---|
5808 | int tw = ci->minimumWidth();
|
---|
5809 | if ( tw < QWIDGETSIZE_MAX )
|
---|
5810 | minw = QMAX( minw, tw );
|
---|
5811 | }
|
---|
5812 | #endif
|
---|
5813 | // we break if
|
---|
5814 | // 1. the last character was a hard break (QChar_linesep) or
|
---|
5815 | // 2. the last charater was a own-line custom item (eg. table or ruler) or
|
---|
5816 | // 3. wrapping was enabled, it was not a space and following
|
---|
5817 | // condition is true: We either had a breakable character
|
---|
5818 | // previously or we ar allowed to break in words and - either
|
---|
5819 | // we break at w pixels and the current char would exceed that
|
---|
5820 | // or - we break at a column and the current character would
|
---|
5821 | // exceed that.
|
---|
5822 | if ( lastWasHardBreak || lastWasOwnLineCustomItem ||
|
---|
5823 | ( wrapEnabled &&
|
---|
5824 | ( (!c->c.isSpace() && (hadBreakableChar || allowBreakInWords()) &&
|
---|
5825 | ( (wrapAtColumn() == -1 && x + ww > w) ||
|
---|
5826 | (wrapAtColumn() != -1 && col >= wrapAtColumn()) ) ) )
|
---|
5827 | )
|
---|
5828 | ) {
|
---|
5829 | if ( wrapAtColumn() != -1 )
|
---|
5830 | minw = QMAX( minw, x + ww );
|
---|
5831 | // if a break was forced (no breakable char, hard break or own line custom item), break immediately....
|
---|
5832 | if ( !hadBreakableChar || lastWasHardBreak || lastWasOwnLineCustomItem ) {
|
---|
5833 | if ( lineStart ) {
|
---|
5834 | lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
|
---|
5835 | h = QMAX( h, tmph );
|
---|
5836 | lineStart->h = h;
|
---|
5837 | DO_FLOW( lineStart );
|
---|
5838 | }
|
---|
5839 | lineStart = formatLine( parag, string, lineStart, firstChar, c-1, align, SPACE(w - x) );
|
---|
5840 | x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
|
---|
5841 | w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
|
---|
5842 | if ( !doc && c->c == '\t' ) { // qt_format_text tab handling
|
---|
5843 | int nx = parag->nextTab( i, x - left ) + left;
|
---|
5844 | if ( nx < x )
|
---|
5845 | ww = w - x;
|
---|
5846 | else
|
---|
5847 | ww = nx - x;
|
---|
5848 | }
|
---|
5849 | curLeft = x;
|
---|
5850 | y += QMAX( h, linespacing );
|
---|
5851 | tmph = c->height();
|
---|
5852 | h = 0;
|
---|
5853 | lineStart->y = y;
|
---|
5854 | insertLineStart( parag, i, lineStart );
|
---|
5855 | lineStart->baseLine = c->ascent();
|
---|
5856 | lineStart->h = c->height();
|
---|
5857 | c->lineStart = 1;
|
---|
5858 | firstChar = c;
|
---|
5859 | tmpBaseLine = lineStart->baseLine;
|
---|
5860 | lastBreak = -1;
|
---|
5861 | col = 0;
|
---|
5862 | if ( allowBreakInWords() || lastWasHardBreak ) {
|
---|
5863 | minw = QMAX(minw, tminw);
|
---|
5864 | tminw = marg;
|
---|
5865 | }
|
---|
5866 | } else { // ... otherwise if we had a breakable char, break there
|
---|
5867 | DO_FLOW( lineStart );
|
---|
5868 | c->x = x;
|
---|
5869 | i = lastBreak;
|
---|
5870 | lineStart = formatLine( parag, string, lineStart, firstChar, parag->at( lastBreak ),align, SPACE(w - string->at( i+1 ).x) );
|
---|
5871 | x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left;
|
---|
5872 | w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 );
|
---|
5873 | if ( !doc && c->c == '\t' ) { // qt_format_text tab handling
|
---|
5874 | int nx = parag->nextTab( i, x - left ) + left;
|
---|
5875 | if ( nx < x )
|
---|
5876 | ww = w - x;
|
---|
5877 | else
|
---|
5878 | ww = nx - x;
|
---|
5879 | }
|
---|
5880 | curLeft = x;
|
---|
5881 | y += QMAX( h, linespacing );
|
---|
5882 | tmph = c->height();
|
---|
5883 | h = tmph;
|
---|
5884 | lineStart->y = y;
|
---|
5885 | insertLineStart( parag, i + 1, lineStart );
|
---|
5886 | lineStart->baseLine = c->ascent();
|
---|
5887 | lineStart->h = c->height();
|
---|
5888 | c->lineStart = 1;
|
---|
5889 | firstChar = c;
|
---|
5890 | tmpBaseLine = lineStart->baseLine;
|
---|
5891 | lastBreak = -1;
|
---|
5892 | col = 0;
|
---|
5893 | minw = QMAX(minw, tminw);
|
---|
5894 | tminw = marg;
|
---|
5895 | continue;
|
---|
5896 | }
|
---|
5897 | } else if (lineStart && isBreakable(string, i)) {
|
---|
5898 | if ( len <= 2 || i < len - 1 ) {
|
---|
5899 | tmpBaseLine = QMAX( tmpBaseLine, c->ascent() );
|
---|
5900 | tmph = QMAX( tmph, c->height() );
|
---|
5901 | }
|
---|
5902 | minw = QMAX( minw, tminw );
|
---|
5903 |
|
---|
5904 | tminw = marg + ww;
|
---|
5905 | lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
|
---|
5906 | h = QMAX( h, tmph );
|
---|
5907 | lineStart->h = h;
|
---|
5908 | if ( i < len - 2 || c->c != ' ' )
|
---|
5909 | lastBreak = i;
|
---|
5910 | } else {
|
---|
5911 | tminw += ww;
|
---|
5912 | int cascent = c->ascent();
|
---|
5913 | int cheight = c->height();
|
---|
5914 | int belowBaseLine = QMAX( tmph - tmpBaseLine, cheight-cascent );
|
---|
5915 | tmpBaseLine = QMAX( tmpBaseLine, cascent );
|
---|
5916 | tmph = tmpBaseLine + belowBaseLine;
|
---|
5917 | }
|
---|
5918 |
|
---|
5919 | c->x = x;
|
---|
5920 | x += ww;
|
---|
5921 | wused = QMAX( wused, x );
|
---|
5922 | }
|
---|
5923 |
|
---|
5924 | if ( lineStart ) {
|
---|
5925 | lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
|
---|
5926 | h = QMAX( h, tmph );
|
---|
5927 | lineStart->h = h;
|
---|
5928 | // last line in a paragraph is not justified
|
---|
5929 | if ( align == Qt::AlignJustify )
|
---|
5930 | align = Qt::AlignAuto;
|
---|
5931 | DO_FLOW( lineStart );
|
---|
5932 | lineStart = formatLine( parag, string, lineStart, firstChar, c, align, SPACE(w - x) );
|
---|
5933 | delete lineStart;
|
---|
5934 | }
|
---|
5935 |
|
---|
5936 | minw = QMAX( minw, tminw );
|
---|
5937 | if ( doc )
|
---|
5938 | minw += doc->rightMargin();
|
---|
5939 |
|
---|
5940 | int m = parag->bottomMargin();
|
---|
5941 | if ( !parag->next() )
|
---|
5942 | m = 0;
|
---|
5943 | else
|
---|
5944 | m = QMAX(m, parag->next()->topMargin() ) / 2;
|
---|
5945 | parag->setFullWidth( fullWidth );
|
---|
5946 | y += QMAX( h, linespacing ) + m;
|
---|
5947 |
|
---|
5948 | wused += rm;
|
---|
5949 | if ( !wrapEnabled || wrapAtColumn() != -1 )
|
---|
5950 | minw = QMAX(minw, wused);
|
---|
5951 |
|
---|
5952 | // This is the case where we are breaking wherever we darn well please
|
---|
5953 | // in cases like that, the minw should not be the length of the entire
|
---|
5954 | // word, because we necessarily want to show the word on the whole line.
|
---|
5955 | // example: word wrap in iconview
|
---|
5956 | if ( allowBreakInWords() && minw > wused )
|
---|
5957 | minw = wused;
|
---|
5958 |
|
---|
5959 | thisminw = minw;
|
---|
5960 | thiswused = wused;
|
---|
5961 | return y;
|
---|
5962 | }
|
---|
5963 |
|
---|
5964 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
5965 |
|
---|
5966 | QTextIndent::QTextIndent()
|
---|
5967 | {
|
---|
5968 | }
|
---|
5969 |
|
---|
5970 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
5971 |
|
---|
5972 | QTextFormatCollection::QTextFormatCollection()
|
---|
5973 | : cKey( 307 ), paintdevice( 0 )
|
---|
5974 | {
|
---|
5975 | defFormat = new QTextFormat( QApplication::font(),
|
---|
5976 | QApplication::palette().color( QPalette::Active, QColorGroup::Text ) );
|
---|
5977 | lastFormat = cres = 0;
|
---|
5978 | cflags = -1;
|
---|
5979 | cKey.setAutoDelete( TRUE );
|
---|
5980 | cachedFormat = 0;
|
---|
5981 | }
|
---|
5982 |
|
---|
5983 | QTextFormatCollection::~QTextFormatCollection()
|
---|
5984 | {
|
---|
5985 | delete defFormat;
|
---|
5986 | }
|
---|
5987 |
|
---|
5988 | void QTextFormatCollection::setPaintDevice( QPaintDevice *pd )
|
---|
5989 | {
|
---|
5990 | paintdevice = pd;
|
---|
5991 |
|
---|
5992 | #if defined(Q_WS_X11)
|
---|
5993 | int scr = ( paintdevice ) ? paintdevice->x11Screen() : QPaintDevice::x11AppScreen();
|
---|
5994 |
|
---|
5995 | defFormat->fn.x11SetScreen( scr );
|
---|
5996 | defFormat->update();
|
---|
5997 |
|
---|
5998 | QDictIterator<QTextFormat> it( cKey );
|
---|
5999 | QTextFormat *format;
|
---|
6000 | while ( ( format = it.current() ) != 0 ) {
|
---|
6001 | ++it;
|
---|
6002 | format->fn.x11SetScreen( scr );
|
---|
6003 | format->update();
|
---|
6004 | }
|
---|
6005 | #endif // Q_WS_X11
|
---|
6006 | }
|
---|
6007 |
|
---|
6008 | QTextFormat *QTextFormatCollection::format( QTextFormat *f )
|
---|
6009 | {
|
---|
6010 | if ( f->parent() == this || f == defFormat ) {
|
---|
6011 | lastFormat = f;
|
---|
6012 | lastFormat->addRef();
|
---|
6013 | return lastFormat;
|
---|
6014 | }
|
---|
6015 |
|
---|
6016 | if ( f == lastFormat || ( lastFormat && f->key() == lastFormat->key() ) ) {
|
---|
6017 | lastFormat->addRef();
|
---|
6018 | return lastFormat;
|
---|
6019 | }
|
---|
6020 |
|
---|
6021 | QTextFormat *fm = cKey.find( f->key() );
|
---|
6022 | if ( fm ) {
|
---|
6023 | lastFormat = fm;
|
---|
6024 | lastFormat->addRef();
|
---|
6025 | return lastFormat;
|
---|
6026 | }
|
---|
6027 |
|
---|
6028 | if ( f->key() == defFormat->key() )
|
---|
6029 | return defFormat;
|
---|
6030 |
|
---|
6031 | lastFormat = createFormat( *f );
|
---|
6032 | lastFormat->collection = this;
|
---|
6033 | cKey.insert( lastFormat->key(), lastFormat );
|
---|
6034 | return lastFormat;
|
---|
6035 | }
|
---|
6036 |
|
---|
6037 | QTextFormat *QTextFormatCollection::format( QTextFormat *of, QTextFormat *nf, int flags )
|
---|
6038 | {
|
---|
6039 | if ( cres && kof == of->key() && knf == nf->key() && cflags == flags ) {
|
---|
6040 | cres->addRef();
|
---|
6041 | return cres;
|
---|
6042 | }
|
---|
6043 |
|
---|
6044 | cres = createFormat( *of );
|
---|
6045 | kof = of->key();
|
---|
6046 | knf = nf->key();
|
---|
6047 | cflags = flags;
|
---|
6048 | if ( flags & QTextFormat::Bold )
|
---|
6049 | cres->fn.setBold( nf->fn.bold() );
|
---|
6050 | if ( flags & QTextFormat::Italic )
|
---|
6051 | cres->fn.setItalic( nf->fn.italic() );
|
---|
6052 | if ( flags & QTextFormat::Underline )
|
---|
6053 | cres->fn.setUnderline( nf->fn.underline() );
|
---|
6054 | if ( flags & QTextFormat::StrikeOut )
|
---|
6055 | cres->fn.setStrikeOut( nf->fn.strikeOut() );
|
---|
6056 | if ( flags & QTextFormat::Family )
|
---|
6057 | cres->fn.setFamily( nf->fn.family() );
|
---|
6058 | if ( flags & QTextFormat::Size ) {
|
---|
6059 | if ( of->usePixelSizes )
|
---|
6060 | cres->fn.setPixelSize( nf->fn.pixelSize() );
|
---|
6061 | else
|
---|
6062 | cres->fn.setPointSize( nf->fn.pointSize() );
|
---|
6063 | }
|
---|
6064 | if ( flags & QTextFormat::Color )
|
---|
6065 | cres->col = nf->col;
|
---|
6066 | if ( flags & QTextFormat::Misspelled )
|
---|
6067 | cres->missp = nf->missp;
|
---|
6068 | if ( flags & QTextFormat::VAlign )
|
---|
6069 | cres->ha = nf->ha;
|
---|
6070 | cres->update();
|
---|
6071 |
|
---|
6072 | QTextFormat *fm = cKey.find( cres->key() );
|
---|
6073 | if ( !fm ) {
|
---|
6074 | cres->collection = this;
|
---|
6075 | cKey.insert( cres->key(), cres );
|
---|
6076 | } else {
|
---|
6077 | delete cres;
|
---|
6078 | cres = fm;
|
---|
6079 | cres->addRef();
|
---|
6080 | }
|
---|
6081 |
|
---|
6082 | return cres;
|
---|
6083 | }
|
---|
6084 |
|
---|
6085 | QTextFormat *QTextFormatCollection::format( const QFont &f, const QColor &c )
|
---|
6086 | {
|
---|
6087 | if ( cachedFormat && cfont == f && ccol == c ) {
|
---|
6088 | cachedFormat->addRef();
|
---|
6089 | return cachedFormat;
|
---|
6090 | }
|
---|
6091 |
|
---|
6092 | QString key = QTextFormat::getKey( f, c, FALSE, QTextFormat::AlignNormal );
|
---|
6093 | cachedFormat = cKey.find( key );
|
---|
6094 | cfont = f;
|
---|
6095 | ccol = c;
|
---|
6096 |
|
---|
6097 | if ( cachedFormat ) {
|
---|
6098 | cachedFormat->addRef();
|
---|
6099 | return cachedFormat;
|
---|
6100 | }
|
---|
6101 |
|
---|
6102 | if ( key == defFormat->key() )
|
---|
6103 | return defFormat;
|
---|
6104 |
|
---|
6105 | cachedFormat = createFormat( f, c );
|
---|
6106 | cachedFormat->collection = this;
|
---|
6107 | cKey.insert( cachedFormat->key(), cachedFormat );
|
---|
6108 | if ( cachedFormat->key() != key )
|
---|
6109 | qWarning("ASSERT: keys for format not identical: '%s '%s'", cachedFormat->key().latin1(), key.latin1() );
|
---|
6110 | return cachedFormat;
|
---|
6111 | }
|
---|
6112 |
|
---|
6113 | void QTextFormatCollection::remove( QTextFormat *f )
|
---|
6114 | {
|
---|
6115 | if ( lastFormat == f )
|
---|
6116 | lastFormat = 0;
|
---|
6117 | if ( cres == f )
|
---|
6118 | cres = 0;
|
---|
6119 | if ( cachedFormat == f )
|
---|
6120 | cachedFormat = 0;
|
---|
6121 | if (cKey.find(f->key()) == f)
|
---|
6122 | cKey.remove( f->key() );
|
---|
6123 | }
|
---|
6124 |
|
---|
6125 | #define UPDATE( up, lo, rest ) \
|
---|
6126 | if ( font.lo##rest() != defFormat->fn.lo##rest() && fm->fn.lo##rest() == defFormat->fn.lo##rest() ) \
|
---|
6127 | fm->fn.set##up##rest( font.lo##rest() )
|
---|
6128 |
|
---|
6129 | void QTextFormatCollection::updateDefaultFormat( const QFont &font, const QColor &color, QStyleSheet *sheet )
|
---|
6130 | {
|
---|
6131 | QDictIterator<QTextFormat> it( cKey );
|
---|
6132 | QTextFormat *fm;
|
---|
6133 | bool usePixels = font.pointSize() == -1;
|
---|
6134 | bool changeSize = usePixels ? font.pixelSize() != defFormat->fn.pixelSize() :
|
---|
6135 | font.pointSize() != defFormat->fn.pointSize();
|
---|
6136 | int base = usePixels ? font.pixelSize() : font.pointSize();
|
---|
6137 | while ( ( fm = it.current() ) ) {
|
---|
6138 | ++it;
|
---|
6139 | UPDATE( F, f, amily );
|
---|
6140 | UPDATE( W, w, eight );
|
---|
6141 | UPDATE( B, b, old );
|
---|
6142 | UPDATE( I, i, talic );
|
---|
6143 | UPDATE( U, u, nderline );
|
---|
6144 | if ( changeSize ) {
|
---|
6145 | fm->stdSize = base;
|
---|
6146 | fm->usePixelSizes = usePixels;
|
---|
6147 | if ( usePixels )
|
---|
6148 | fm->fn.setPixelSize( fm->stdSize );
|
---|
6149 | else
|
---|
6150 | fm->fn.setPointSize( fm->stdSize );
|
---|
6151 | sheet->scaleFont( fm->fn, fm->logicalFontSize );
|
---|
6152 | }
|
---|
6153 | if ( color.isValid() && color != defFormat->col && fm->col == defFormat->col )
|
---|
6154 | fm->col = color;
|
---|
6155 | fm->update();
|
---|
6156 | }
|
---|
6157 |
|
---|
6158 | defFormat->fn = font;
|
---|
6159 | defFormat->col = color;
|
---|
6160 | defFormat->update();
|
---|
6161 | defFormat->stdSize = base;
|
---|
6162 | defFormat->usePixelSizes = usePixels;
|
---|
6163 |
|
---|
6164 | updateKeys();
|
---|
6165 | }
|
---|
6166 |
|
---|
6167 | // the keys in cKey have changed, rebuild the hashtable
|
---|
6168 | void QTextFormatCollection::updateKeys()
|
---|
6169 | {
|
---|
6170 | if ( cKey.isEmpty() )
|
---|
6171 | return;
|
---|
6172 | cKey.setAutoDelete( FALSE );
|
---|
6173 | QTextFormat** formats = new QTextFormat*[ cKey.count() + 1 ];
|
---|
6174 | QTextFormat **f = formats;
|
---|
6175 | QDictIterator<QTextFormat> it( cKey );
|
---|
6176 | while ( ( *f = it.current() ) ) {
|
---|
6177 | ++it;
|
---|
6178 | ++f;
|
---|
6179 | }
|
---|
6180 | cKey.clear();
|
---|
6181 | for ( f = formats; *f; f++ )
|
---|
6182 | cKey.insert( (*f)->key(), *f );
|
---|
6183 | cKey.setAutoDelete( TRUE );
|
---|
6184 | delete [] formats;
|
---|
6185 | }
|
---|
6186 |
|
---|
6187 |
|
---|
6188 |
|
---|
6189 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
6190 |
|
---|
6191 | void QTextFormat::setBold( bool b )
|
---|
6192 | {
|
---|
6193 | if ( b == fn.bold() )
|
---|
6194 | return;
|
---|
6195 | fn.setBold( b );
|
---|
6196 | update();
|
---|
6197 | }
|
---|
6198 |
|
---|
6199 | void QTextFormat::setMisspelled( bool b )
|
---|
6200 | {
|
---|
6201 | if ( b == (bool)missp )
|
---|
6202 | return;
|
---|
6203 | missp = b;
|
---|
6204 | update();
|
---|
6205 | }
|
---|
6206 |
|
---|
6207 | void QTextFormat::setVAlign( VerticalAlignment a )
|
---|
6208 | {
|
---|
6209 | if ( a == ha )
|
---|
6210 | return;
|
---|
6211 | ha = a;
|
---|
6212 | update();
|
---|
6213 | }
|
---|
6214 |
|
---|
6215 | void QTextFormat::setItalic( bool b )
|
---|
6216 | {
|
---|
6217 | if ( b == fn.italic() )
|
---|
6218 | return;
|
---|
6219 | fn.setItalic( b );
|
---|
6220 | update();
|
---|
6221 | }
|
---|
6222 |
|
---|
6223 | void QTextFormat::setUnderline( bool b )
|
---|
6224 | {
|
---|
6225 | if ( b == fn.underline() )
|
---|
6226 | return;
|
---|
6227 | fn.setUnderline( b );
|
---|
6228 | update();
|
---|
6229 | }
|
---|
6230 |
|
---|
6231 | void QTextFormat::setStrikeOut( bool b )
|
---|
6232 | {
|
---|
6233 | if ( b == fn.strikeOut() )
|
---|
6234 | return;
|
---|
6235 | fn.setStrikeOut( b );
|
---|
6236 | update();
|
---|
6237 | }
|
---|
6238 |
|
---|
6239 | void QTextFormat::setFamily( const QString &f )
|
---|
6240 | {
|
---|
6241 | if ( f == fn.family() )
|
---|
6242 | return;
|
---|
6243 | fn.setFamily( f );
|
---|
6244 | update();
|
---|
6245 | }
|
---|
6246 |
|
---|
6247 | void QTextFormat::setPointSize( int s )
|
---|
6248 | {
|
---|
6249 | if ( s == fn.pointSize() )
|
---|
6250 | return;
|
---|
6251 | fn.setPointSize( s );
|
---|
6252 | usePixelSizes = FALSE;
|
---|
6253 | update();
|
---|
6254 | }
|
---|
6255 |
|
---|
6256 | void QTextFormat::setFont( const QFont &f )
|
---|
6257 | {
|
---|
6258 | if ( f == fn && !k.isEmpty() )
|
---|
6259 | return;
|
---|
6260 | fn = f;
|
---|
6261 | update();
|
---|
6262 | }
|
---|
6263 |
|
---|
6264 | void QTextFormat::setColor( const QColor &c )
|
---|
6265 | {
|
---|
6266 | if ( c == col )
|
---|
6267 | return;
|
---|
6268 | col = c;
|
---|
6269 | update();
|
---|
6270 | }
|
---|
6271 |
|
---|
6272 | QString QTextFormat::makeFormatChangeTags( QTextFormat* defaultFormat, QTextFormat *f,
|
---|
6273 | const QString& oldAnchorHref, const QString& anchorHref ) const
|
---|
6274 | {
|
---|
6275 | QString tag;
|
---|
6276 | if ( f )
|
---|
6277 | tag += f->makeFormatEndTags( defaultFormat, oldAnchorHref );
|
---|
6278 |
|
---|
6279 | if ( !anchorHref.isEmpty() )
|
---|
6280 | tag += "<a href=\"" + anchorHref + "\">";
|
---|
6281 |
|
---|
6282 | if ( font() != defaultFormat->font()
|
---|
6283 | || vAlign() != defaultFormat->vAlign()
|
---|
6284 | || color().rgb() != defaultFormat->color().rgb() ) {
|
---|
6285 | QString s;
|
---|
6286 | if ( font().family() != defaultFormat->font().family() )
|
---|
6287 | s += QString(!!s?";":"") + "font-family:" + fn.family();
|
---|
6288 | if ( font().italic() && font().italic() != defaultFormat->font().italic() )
|
---|
6289 | s += QString(!!s?";":"") + "font-style:" + (font().italic() ? "italic" : "normal");
|
---|
6290 | if ( font().pointSize() != defaultFormat->font().pointSize() )
|
---|
6291 | s += QString(!!s?";":"") + "font-size:" + QString::number( fn.pointSize() ) + "pt";
|
---|
6292 | if ( font().weight() != defaultFormat->font().weight() )
|
---|
6293 | s += QString(!!s?";":"") + "font-weight:" + QString::number( fn.weight() * 8 );
|
---|
6294 | if ( font().underline() != defaultFormat->font().underline() )
|
---|
6295 | s += QString(!!s?";":"") + "text-decoration:" + ( font().underline() ? "underline" : "none");
|
---|
6296 | if ( vAlign() != defaultFormat->vAlign() ) {
|
---|
6297 | s += QString(!!s?";":"") + "vertical-align:";
|
---|
6298 | if ( vAlign() == QTextFormat::AlignSuperScript )
|
---|
6299 | s += "super";
|
---|
6300 | else if ( vAlign() == QTextFormat::AlignSubScript )
|
---|
6301 | s += "sub";
|
---|
6302 | else
|
---|
6303 | s += "normal";
|
---|
6304 | }
|
---|
6305 | if ( color().rgb() != defaultFormat->color().rgb() )
|
---|
6306 | s += QString(!!s?";":"") + "color:" + col.name();
|
---|
6307 | if ( !s.isEmpty() )
|
---|
6308 | tag += "<span style=\"" + s + "\">";
|
---|
6309 | }
|
---|
6310 |
|
---|
6311 | return tag;
|
---|
6312 | }
|
---|
6313 |
|
---|
6314 | QString QTextFormat::makeFormatEndTags( QTextFormat* defaultFormat, const QString& anchorHref ) const
|
---|
6315 | {
|
---|
6316 | QString tag;
|
---|
6317 | if ( font().family() != defaultFormat->font().family()
|
---|
6318 | || font().pointSize() != defaultFormat->font().pointSize()
|
---|
6319 | || font().weight() != defaultFormat->font().weight()
|
---|
6320 | || font().italic() != defaultFormat->font().italic()
|
---|
6321 | || font().underline() != defaultFormat->font().underline()
|
---|
6322 | || font().strikeOut() != defaultFormat->font().strikeOut()
|
---|
6323 | || vAlign() != defaultFormat->vAlign()
|
---|
6324 | || color().rgb() != defaultFormat->color().rgb() )
|
---|
6325 | tag += "</span>";
|
---|
6326 | if ( !anchorHref.isEmpty() )
|
---|
6327 | tag += "</a>";
|
---|
6328 | return tag;
|
---|
6329 | }
|
---|
6330 |
|
---|
6331 | QTextFormat QTextFormat::makeTextFormat( const QStyleSheetItem *style, const QMap<QString,QString>& attr, double scaleFontsFactor ) const
|
---|
6332 | {
|
---|
6333 | QTextFormat format(*this);
|
---|
6334 | if (!style )
|
---|
6335 | return format;
|
---|
6336 |
|
---|
6337 | if ( !style->isAnchor() && style->color().isValid() ) {
|
---|
6338 | // the style is not an anchor and defines a color.
|
---|
6339 | // It might be used inside an anchor and it should
|
---|
6340 | // override the link color.
|
---|
6341 | format.linkColor = FALSE;
|
---|
6342 | }
|
---|
6343 | switch ( style->verticalAlignment() ) {
|
---|
6344 | case QStyleSheetItem::VAlignBaseline:
|
---|
6345 | format.setVAlign( QTextFormat::AlignNormal );
|
---|
6346 | break;
|
---|
6347 | case QStyleSheetItem::VAlignSuper:
|
---|
6348 | format.setVAlign( QTextFormat::AlignSuperScript );
|
---|
6349 | break;
|
---|
6350 | case QStyleSheetItem::VAlignSub:
|
---|
6351 | format.setVAlign( QTextFormat::AlignSubScript );
|
---|
6352 | break;
|
---|
6353 | }
|
---|
6354 |
|
---|
6355 | if ( style->fontWeight() != QStyleSheetItem::Undefined )
|
---|
6356 | format.fn.setWeight( style->fontWeight() );
|
---|
6357 | if ( style->fontSize() != QStyleSheetItem::Undefined ) {
|
---|
6358 | format.fn.setPointSize( style->fontSize() );
|
---|
6359 | } else if ( style->logicalFontSize() != QStyleSheetItem::Undefined ) {
|
---|
6360 | format.logicalFontSize = style->logicalFontSize();
|
---|
6361 | if ( format.usePixelSizes )
|
---|
6362 | format.fn.setPixelSize( format.stdSize );
|
---|
6363 | else
|
---|
6364 | format.fn.setPointSize( format.stdSize );
|
---|
6365 | style->styleSheet()->scaleFont( format.fn, format.logicalFontSize );
|
---|
6366 | } else if ( style->logicalFontSizeStep() ) {
|
---|
6367 | format.logicalFontSize += style->logicalFontSizeStep();
|
---|
6368 | if ( format.usePixelSizes )
|
---|
6369 | format.fn.setPixelSize( format.stdSize );
|
---|
6370 | else
|
---|
6371 | format.fn.setPointSize( format.stdSize );
|
---|
6372 | style->styleSheet()->scaleFont( format.fn, format.logicalFontSize );
|
---|
6373 | }
|
---|
6374 | if ( !style->fontFamily().isEmpty() )
|
---|
6375 | format.fn.setFamily( style->fontFamily() );
|
---|
6376 | if ( style->color().isValid() )
|
---|
6377 | format.col = style->color();
|
---|
6378 | if ( style->definesFontItalic() )
|
---|
6379 | format.fn.setItalic( style->fontItalic() );
|
---|
6380 | if ( style->definesFontUnderline() )
|
---|
6381 | format.fn.setUnderline( style->fontUnderline() );
|
---|
6382 | if ( style->definesFontStrikeOut() )
|
---|
6383 | format.fn.setStrikeOut( style->fontStrikeOut() );
|
---|
6384 |
|
---|
6385 |
|
---|
6386 | if ( style->name() == "font") {
|
---|
6387 | if ( attr.contains("color") ) {
|
---|
6388 | QString s = attr["color"];
|
---|
6389 | if ( !s.isEmpty() ) {
|
---|
6390 | format.col.setNamedColor( s );
|
---|
6391 | format.linkColor = FALSE;
|
---|
6392 | }
|
---|
6393 | }
|
---|
6394 | if ( attr.contains("face") ) {
|
---|
6395 | QString a = attr["face"];
|
---|
6396 | QString family = a.section( ',', 0, 0 );
|
---|
6397 | if ( !!family )
|
---|
6398 | format.fn.setFamily( family );
|
---|
6399 | }
|
---|
6400 | if ( attr.contains("size") ) {
|
---|
6401 | QString a = attr["size"];
|
---|
6402 | int n = a.toInt();
|
---|
6403 | if ( a[0] == '+' || a[0] == '-' )
|
---|
6404 | n += 3;
|
---|
6405 | format.logicalFontSize = n;
|
---|
6406 | if ( format.usePixelSizes )
|
---|
6407 | format.fn.setPixelSize( format.stdSize );
|
---|
6408 | else
|
---|
6409 | format.fn.setPointSize( format.stdSize );
|
---|
6410 | style->styleSheet()->scaleFont( format.fn, format.logicalFontSize );
|
---|
6411 | }
|
---|
6412 | }
|
---|
6413 | if ( attr.contains("style" ) ) {
|
---|
6414 | QString a = attr["style"];
|
---|
6415 | for ( int s = 0; s < a.contains(';')+1; s++ ) {
|
---|
6416 | QString style = a.section( ';', s, s );
|
---|
6417 | if ( style.startsWith("font-size:" ) && style.endsWith("pt") ) {
|
---|
6418 | format.logicalFontSize = 0;
|
---|
6419 | int size = int( scaleFontsFactor * style.mid( 10, style.length() - 12 ).toDouble() );
|
---|
6420 | format.setPointSize( size );
|
---|
6421 | } if ( style.startsWith("font-style:" ) ) {
|
---|
6422 | QString s = style.mid( 11 ).stripWhiteSpace();
|
---|
6423 | if ( s == "normal" )
|
---|
6424 | format.fn.setItalic( FALSE );
|
---|
6425 | else if ( s == "italic" || s == "oblique" )
|
---|
6426 | format.fn.setItalic( TRUE );
|
---|
6427 | } else if ( style.startsWith("font-weight:" ) ) {
|
---|
6428 | QString s = style.mid( 12 );
|
---|
6429 | bool ok = TRUE;
|
---|
6430 | int n = s.toInt( &ok );
|
---|
6431 | if ( ok )
|
---|
6432 | format.fn.setWeight( n/8 );
|
---|
6433 | } else if ( style.startsWith("font-family:" ) ) {
|
---|
6434 | QString family = style.mid(12).section(',',0,0);
|
---|
6435 | family.replace( '\"', ' ' );
|
---|
6436 | family.replace( '\'', ' ' );
|
---|
6437 | family = family.stripWhiteSpace();
|
---|
6438 | format.fn.setFamily( family );
|
---|
6439 | } else if ( style.startsWith("text-decoration:" ) ) {
|
---|
6440 | QString s = style.mid( 16 ).stripWhiteSpace();
|
---|
6441 | format.fn.setUnderline( s == "underline" );
|
---|
6442 | } else if ( style.startsWith("vertical-align:" ) ) {
|
---|
6443 | QString s = style.mid( 15 ).stripWhiteSpace();
|
---|
6444 | if ( s == "sub" )
|
---|
6445 | format.setVAlign( QTextFormat::AlignSubScript );
|
---|
6446 | else if ( s == "super" )
|
---|
6447 | format.setVAlign( QTextFormat::AlignSuperScript );
|
---|
6448 | else
|
---|
6449 | format.setVAlign( QTextFormat::AlignNormal );
|
---|
6450 | } else if ( style.startsWith("color:" ) ) {
|
---|
6451 | format.col.setNamedColor( style.mid(6) );
|
---|
6452 | format.linkColor = FALSE;
|
---|
6453 | }
|
---|
6454 | }
|
---|
6455 | }
|
---|
6456 |
|
---|
6457 | format.update();
|
---|
6458 | return format;
|
---|
6459 | }
|
---|
6460 |
|
---|
6461 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
6462 |
|
---|
6463 | struct QPixmapInt
|
---|
6464 | {
|
---|
6465 | QPixmapInt() : ref( 0 ) {}
|
---|
6466 | QPixmap pm;
|
---|
6467 | int ref;
|
---|
6468 | Q_DUMMY_COMPARISON_OPERATOR(QPixmapInt)
|
---|
6469 | };
|
---|
6470 |
|
---|
6471 | static QMap<QString, QPixmapInt> *pixmap_map = 0;
|
---|
6472 |
|
---|
6473 | QTextImage::QTextImage( QTextDocument *p, const QMap<QString, QString> &attr, const QString& context,
|
---|
6474 | QMimeSourceFactory &factory )
|
---|
6475 | : QTextCustomItem( p )
|
---|
6476 | {
|
---|
6477 | width = height = 0;
|
---|
6478 | if ( attr.contains("width") )
|
---|
6479 | width = attr["width"].toInt();
|
---|
6480 | if ( attr.contains("height") )
|
---|
6481 | height = attr["height"].toInt();
|
---|
6482 |
|
---|
6483 | reg = 0;
|
---|
6484 | QString imageName = attr["src"];
|
---|
6485 |
|
---|
6486 | if (!imageName)
|
---|
6487 | imageName = attr["source"];
|
---|
6488 |
|
---|
6489 | if ( !imageName.isEmpty() ) {
|
---|
6490 | imgId = QString( "%1,%2,%3,%4" ).arg( imageName ).arg( width ).arg( height ).arg( (ulong)&factory );
|
---|
6491 | if ( !pixmap_map )
|
---|
6492 | pixmap_map = new QMap<QString, QPixmapInt>;
|
---|
6493 | if ( pixmap_map->contains( imgId ) ) {
|
---|
6494 | QPixmapInt& pmi = pixmap_map->operator[](imgId);
|
---|
6495 | pm = pmi.pm;
|
---|
6496 | pmi.ref++;
|
---|
6497 | width = pm.width();
|
---|
6498 | height = pm.height();
|
---|
6499 | } else {
|
---|
6500 | QImage img;
|
---|
6501 | const QMimeSource* m =
|
---|
6502 | factory.data( imageName, context );
|
---|
6503 | if ( !m ) {
|
---|
6504 | qWarning("QTextImage: no mimesource for %s", imageName.latin1() );
|
---|
6505 | }
|
---|
6506 | else {
|
---|
6507 | if ( !QImageDrag::decode( m, img ) ) {
|
---|
6508 | qWarning("QTextImage: cannot decode %s", imageName.latin1() );
|
---|
6509 | }
|
---|
6510 | }
|
---|
6511 |
|
---|
6512 | if ( !img.isNull() ) {
|
---|
6513 | if ( width == 0 ) {
|
---|
6514 | width = img.width();
|
---|
6515 | if ( height != 0 ) {
|
---|
6516 | width = img.width() * height / img.height();
|
---|
6517 | }
|
---|
6518 | }
|
---|
6519 | if ( height == 0 ) {
|
---|
6520 | height = img.height();
|
---|
6521 | if ( width != img.width() ) {
|
---|
6522 | height = img.height() * width / img.width();
|
---|
6523 | }
|
---|
6524 | }
|
---|
6525 | if ( img.width() != width || img.height() != height ){
|
---|
6526 | #ifndef QT_NO_IMAGE_SMOOTHSCALE
|
---|
6527 | img = img.smoothScale(width, height);
|
---|
6528 | #endif
|
---|
6529 | width = img.width();
|
---|
6530 | height = img.height();
|
---|
6531 | }
|
---|
6532 | pm.convertFromImage( img );
|
---|
6533 | }
|
---|
6534 | if ( !pm.isNull() ) {
|
---|
6535 | QPixmapInt& pmi = pixmap_map->operator[](imgId);
|
---|
6536 | pmi.pm = pm;
|
---|
6537 | pmi.ref++;
|
---|
6538 | }
|
---|
6539 | }
|
---|
6540 | if ( pm.mask() ) {
|
---|
6541 | QRegion mask( *pm.mask() );
|
---|
6542 | QRegion all( 0, 0, pm.width(), pm.height() );
|
---|
6543 | reg = new QRegion( all.subtract( mask ) );
|
---|
6544 | }
|
---|
6545 | }
|
---|
6546 |
|
---|
6547 | if ( pm.isNull() && (width*height)==0 )
|
---|
6548 | width = height = 50;
|
---|
6549 |
|
---|
6550 | place = PlaceInline;
|
---|
6551 | if ( attr["align"] == "left" )
|
---|
6552 | place = PlaceLeft;
|
---|
6553 | else if ( attr["align"] == "right" )
|
---|
6554 | place = PlaceRight;
|
---|
6555 |
|
---|
6556 | tmpwidth = width;
|
---|
6557 | tmpheight = height;
|
---|
6558 |
|
---|
6559 | attributes = attr;
|
---|
6560 | }
|
---|
6561 |
|
---|
6562 | QTextImage::~QTextImage()
|
---|
6563 | {
|
---|
6564 | if ( pixmap_map && pixmap_map->contains( imgId ) ) {
|
---|
6565 | QPixmapInt& pmi = pixmap_map->operator[](imgId);
|
---|
6566 | pmi.ref--;
|
---|
6567 | if ( !pmi.ref ) {
|
---|
6568 | pixmap_map->remove( imgId );
|
---|
6569 | if ( pixmap_map->isEmpty() ) {
|
---|
6570 | delete pixmap_map;
|
---|
6571 | pixmap_map = 0;
|
---|
6572 | }
|
---|
6573 | }
|
---|
6574 | }
|
---|
6575 | delete reg;
|
---|
6576 | }
|
---|
6577 |
|
---|
6578 | QString QTextImage::richText() const
|
---|
6579 | {
|
---|
6580 | QString s;
|
---|
6581 | s += "<img ";
|
---|
6582 | QMap<QString, QString>::ConstIterator it = attributes.begin();
|
---|
6583 | for ( ; it != attributes.end(); ++it ) {
|
---|
6584 | s += it.key() + "=";
|
---|
6585 | if ( (*it).find( ' ' ) != -1 )
|
---|
6586 | s += "\"" + *it + "\"" + " ";
|
---|
6587 | else
|
---|
6588 | s += *it + " ";
|
---|
6589 | }
|
---|
6590 | s += ">";
|
---|
6591 | return s;
|
---|
6592 | }
|
---|
6593 |
|
---|
6594 | void QTextImage::adjustToPainter( QPainter* p )
|
---|
6595 | {
|
---|
6596 | width = scale( tmpwidth, p );
|
---|
6597 | height = scale( tmpheight, p );
|
---|
6598 | }
|
---|
6599 |
|
---|
6600 | #if !defined(Q_WS_X11)
|
---|
6601 | #include <qbitmap.h>
|
---|
6602 | #include <qcleanuphandler.h>
|
---|
6603 | static QPixmap *qrt_selection = 0;
|
---|
6604 | static QSingleCleanupHandler<QPixmap> qrt_cleanup_pixmap;
|
---|
6605 | static void qrt_createSelectionPixmap( const QColorGroup &cg )
|
---|
6606 | {
|
---|
6607 | qrt_selection = new QPixmap( 2, 2 );
|
---|
6608 | qrt_cleanup_pixmap.set( &qrt_selection );
|
---|
6609 | qrt_selection->fill( Qt::color0 );
|
---|
6610 | QBitmap m( 2, 2 );
|
---|
6611 | m.fill( Qt::color1 );
|
---|
6612 | QPainter p( &m );
|
---|
6613 | p.setPen( Qt::color0 );
|
---|
6614 | for ( int j = 0; j < 2; ++j ) {
|
---|
6615 | p.drawPoint( j % 2, j );
|
---|
6616 | }
|
---|
6617 | p.end();
|
---|
6618 | qrt_selection->setMask( m );
|
---|
6619 | qrt_selection->fill( cg.highlight() );
|
---|
6620 | }
|
---|
6621 | #endif
|
---|
6622 |
|
---|
6623 | void QTextImage::draw( QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected )
|
---|
6624 | {
|
---|
6625 | if ( placement() != PlaceInline ) {
|
---|
6626 | x = xpos;
|
---|
6627 | y = ypos;
|
---|
6628 | }
|
---|
6629 |
|
---|
6630 | if ( pm.isNull() ) {
|
---|
6631 | p->fillRect( x , y, width, height, cg.dark() );
|
---|
6632 | return;
|
---|
6633 | }
|
---|
6634 |
|
---|
6635 | if ( is_printer( p ) ) {
|
---|
6636 | p->drawPixmap( QRect( x, y, width, height ), pm );
|
---|
6637 | return;
|
---|
6638 | }
|
---|
6639 |
|
---|
6640 | if ( placement() != PlaceInline && !QRect( xpos, ypos, width, height ).intersects( QRect( cx, cy, cw, ch ) ) )
|
---|
6641 | return;
|
---|
6642 |
|
---|
6643 | if ( placement() == PlaceInline )
|
---|
6644 | p->drawPixmap( x , y, pm );
|
---|
6645 | else
|
---|
6646 | p->drawPixmap( cx , cy, pm, cx - x, cy - y, cw, ch );
|
---|
6647 |
|
---|
6648 | if ( selected && placement() == PlaceInline && is_printer( p ) ) {
|
---|
6649 | #if defined(Q_WS_X11)
|
---|
6650 | p->fillRect( QRect( QPoint( x, y ), pm.size() ), QBrush( cg.highlight(), QBrush::Dense4Pattern) );
|
---|
6651 | #else // in WIN32 Dense4Pattern doesn't work correctly (transparency problem), so work around it
|
---|
6652 | if ( !qrt_selection )
|
---|
6653 | qrt_createSelectionPixmap( cg );
|
---|
6654 | p->drawTiledPixmap( x, y, pm.width(), pm.height(), *qrt_selection );
|
---|
6655 | #endif
|
---|
6656 | }
|
---|
6657 | }
|
---|
6658 |
|
---|
6659 | void QTextHorizontalLine::adjustToPainter( QPainter* p )
|
---|
6660 | {
|
---|
6661 | height = scale( tmpheight, p );
|
---|
6662 | }
|
---|
6663 |
|
---|
6664 |
|
---|
6665 | QTextHorizontalLine::QTextHorizontalLine( QTextDocument *p, const QMap<QString, QString> &attr,
|
---|
6666 | const QString &,
|
---|
6667 | QMimeSourceFactory & )
|
---|
6668 | : QTextCustomItem( p )
|
---|
6669 | {
|
---|
6670 | height = tmpheight = 8;
|
---|
6671 | if ( attr.find( "color" ) != attr.end() )
|
---|
6672 | color = QColor( *attr.find( "color" ) );
|
---|
6673 | shade = attr.find( "noshade" ) == attr.end();
|
---|
6674 | }
|
---|
6675 |
|
---|
6676 | QTextHorizontalLine::~QTextHorizontalLine()
|
---|
6677 | {
|
---|
6678 | }
|
---|
6679 |
|
---|
6680 | QString QTextHorizontalLine::richText() const
|
---|
6681 | {
|
---|
6682 | return "<hr>";
|
---|
6683 | }
|
---|
6684 |
|
---|
6685 | void QTextHorizontalLine::draw( QPainter* p, int x, int y, int , int , int , int , const QColorGroup& cg, bool selected )
|
---|
6686 | {
|
---|
6687 | QRect r( x, y, width, height);
|
---|
6688 | if ( is_printer( p ) || !shade ) {
|
---|
6689 | QPen oldPen = p->pen();
|
---|
6690 | if ( !color.isValid() )
|
---|
6691 | p->setPen( QPen( cg.text(), is_printer( p ) ? height/8 : QMAX( 2, height/4 ) ) );
|
---|
6692 | else
|
---|
6693 | p->setPen( QPen( color, is_printer( p ) ? height/8 : QMAX( 2, height/4 ) ) );
|
---|
6694 | p->drawLine( r.left()-1, y + height / 2, r.right() + 1, y + height / 2 );
|
---|
6695 | p->setPen( oldPen );
|
---|
6696 | } else {
|
---|
6697 | QColorGroup g( cg );
|
---|
6698 | if ( color.isValid() )
|
---|
6699 | g.setColor( QColorGroup::Dark, color );
|
---|
6700 | if ( selected )
|
---|
6701 | p->fillRect( r, g.highlight() );
|
---|
6702 | qDrawShadeLine( p, r.left() - 1, y + height / 2, r.right() + 1, y + height / 2, g, TRUE, height / 8 );
|
---|
6703 | }
|
---|
6704 | }
|
---|
6705 | #endif //QT_NO_TEXTCUSTOMITEM
|
---|
6706 |
|
---|
6707 | /*****************************************************************/
|
---|
6708 | // Small set of utility functions to make the parser a bit simpler
|
---|
6709 | //
|
---|
6710 |
|
---|
6711 | bool QTextDocument::hasPrefix(const QChar* doc, int length, int pos, QChar c)
|
---|
6712 | {
|
---|
6713 | if ( pos + 1 > length )
|
---|
6714 | return FALSE;
|
---|
6715 | return doc[ pos ].lower() == c.lower();
|
---|
6716 | }
|
---|
6717 |
|
---|
6718 | bool QTextDocument::hasPrefix( const QChar* doc, int length, int pos, const QString& s )
|
---|
6719 | {
|
---|
6720 | if ( pos + (int) s.length() > length )
|
---|
6721 | return FALSE;
|
---|
6722 | for ( int i = 0; i < (int)s.length(); i++ ) {
|
---|
6723 | if ( doc[ pos + i ].lower() != s[ i ].lower() )
|
---|
6724 | return FALSE;
|
---|
6725 | }
|
---|
6726 | return TRUE;
|
---|
6727 | }
|
---|
6728 |
|
---|
6729 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
6730 | static bool qt_is_cell_in_use( QPtrList<QTextTableCell>& cells, int row, int col )
|
---|
6731 | {
|
---|
6732 | for ( QTextTableCell* c = cells.first(); c; c = cells.next() ) {
|
---|
6733 | if ( row >= c->row() && row < c->row() + c->rowspan()
|
---|
6734 | && col >= c->column() && col < c->column() + c->colspan() )
|
---|
6735 | return TRUE;
|
---|
6736 | }
|
---|
6737 | return FALSE;
|
---|
6738 | }
|
---|
6739 |
|
---|
6740 | QTextCustomItem* QTextDocument::parseTable( const QMap<QString, QString> &attr, const QTextFormat &fmt,
|
---|
6741 | const QChar* doc, int length, int& pos, QTextParagraph *curpar )
|
---|
6742 | {
|
---|
6743 |
|
---|
6744 | QTextTable* table = new QTextTable( this, attr );
|
---|
6745 | int row = -1;
|
---|
6746 | int col = -1;
|
---|
6747 |
|
---|
6748 | QString rowbgcolor;
|
---|
6749 | QString rowalign;
|
---|
6750 | QString tablebgcolor = attr["bgcolor"];
|
---|
6751 |
|
---|
6752 | QPtrList<QTextTableCell> multicells;
|
---|
6753 |
|
---|
6754 | QString tagname;
|
---|
6755 | (void) eatSpace(doc, length, pos);
|
---|
6756 | while ( pos < length) {
|
---|
6757 | if (hasPrefix(doc, length, pos, QChar('<')) ){
|
---|
6758 | if (hasPrefix(doc, length, pos+1, QChar('/'))) {
|
---|
6759 | tagname = parseCloseTag( doc, length, pos );
|
---|
6760 | if ( tagname == "table" ) {
|
---|
6761 | return table;
|
---|
6762 | }
|
---|
6763 | } else {
|
---|
6764 | QMap<QString, QString> attr2;
|
---|
6765 | bool emptyTag = FALSE;
|
---|
6766 | tagname = parseOpenTag( doc, length, pos, attr2, emptyTag );
|
---|
6767 | if ( tagname == "tr" ) {
|
---|
6768 | rowbgcolor = attr2["bgcolor"];
|
---|
6769 | rowalign = attr2["align"];
|
---|
6770 | row++;
|
---|
6771 | col = -1;
|
---|
6772 | }
|
---|
6773 | else if ( tagname == "td" || tagname == "th" ) {
|
---|
6774 | col++;
|
---|
6775 | while ( qt_is_cell_in_use( multicells, row, col ) ) {
|
---|
6776 | col++;
|
---|
6777 | }
|
---|
6778 |
|
---|
6779 | if ( row >= 0 && col >= 0 ) {
|
---|
6780 | const QStyleSheetItem* s = sheet_->item(tagname);
|
---|
6781 | if ( !attr2.contains("bgcolor") ) {
|
---|
6782 | if (!rowbgcolor.isEmpty() )
|
---|
6783 | attr2["bgcolor"] = rowbgcolor;
|
---|
6784 | else if (!tablebgcolor.isEmpty() )
|
---|
6785 | attr2["bgcolor"] = tablebgcolor;
|
---|
6786 | }
|
---|
6787 | if ( !attr2.contains("align") ) {
|
---|
6788 | if (!rowalign.isEmpty() )
|
---|
6789 | attr2["align"] = rowalign;
|
---|
6790 | }
|
---|
6791 |
|
---|
6792 | // extract the cell contents
|
---|
6793 | int end = pos;
|
---|
6794 | while ( end < length
|
---|
6795 | && !hasPrefix( doc, length, end, "</td")
|
---|
6796 | && !hasPrefix( doc, length, end, "<td")
|
---|
6797 | && !hasPrefix( doc, length, end, "</th")
|
---|
6798 | && !hasPrefix( doc, length, end, "<th")
|
---|
6799 | && !hasPrefix( doc, length, end, "<td")
|
---|
6800 | && !hasPrefix( doc, length, end, "</tr")
|
---|
6801 | && !hasPrefix( doc, length, end, "<tr")
|
---|
6802 | && !hasPrefix( doc, length, end, "</table") ) {
|
---|
6803 | if ( hasPrefix( doc, length, end, "<table" ) ) { // nested table
|
---|
6804 | int nested = 1;
|
---|
6805 | ++end;
|
---|
6806 | while ( end < length && nested != 0 ) {
|
---|
6807 | if ( hasPrefix( doc, length, end, "</table" ) )
|
---|
6808 | nested--;
|
---|
6809 | if ( hasPrefix( doc, length, end, "<table" ) )
|
---|
6810 | nested++;
|
---|
6811 | end++;
|
---|
6812 | }
|
---|
6813 | }
|
---|
6814 | end++;
|
---|
6815 | }
|
---|
6816 | QTextTableCell* cell = new QTextTableCell( table, row, col,
|
---|
6817 | attr2, s, fmt.makeTextFormat( s, attr2, scaleFontsFactor ),
|
---|
6818 | contxt, *factory_, sheet_,
|
---|
6819 | QConstString( doc + pos, end - pos ).string() );
|
---|
6820 | cell->richText()->parentPar = curpar;
|
---|
6821 | if ( cell->colspan() > 1 || cell->rowspan() > 1 )
|
---|
6822 | multicells.append( cell );
|
---|
6823 | col += cell->colspan()-1;
|
---|
6824 | pos = end;
|
---|
6825 | }
|
---|
6826 | }
|
---|
6827 | }
|
---|
6828 |
|
---|
6829 | } else {
|
---|
6830 | ++pos;
|
---|
6831 | }
|
---|
6832 | }
|
---|
6833 | return table;
|
---|
6834 | }
|
---|
6835 | #endif // QT_NO_TEXTCUSTOMITEM
|
---|
6836 |
|
---|
6837 | bool QTextDocument::eatSpace(const QChar* doc, int length, int& pos, bool includeNbsp )
|
---|
6838 | {
|
---|
6839 | int old_pos = pos;
|
---|
6840 | while (pos < length && doc[pos].isSpace() && ( includeNbsp || (doc[pos] != QChar::nbsp ) ) )
|
---|
6841 | pos++;
|
---|
6842 | return old_pos < pos;
|
---|
6843 | }
|
---|
6844 |
|
---|
6845 | bool QTextDocument::eat(const QChar* doc, int length, int& pos, QChar c)
|
---|
6846 | {
|
---|
6847 | bool ok = pos < length && doc[pos] == c;
|
---|
6848 | if ( ok )
|
---|
6849 | pos++;
|
---|
6850 | return ok;
|
---|
6851 | }
|
---|
6852 | /*****************************************************************/
|
---|
6853 |
|
---|
6854 | struct Entity {
|
---|
6855 | const char * name;
|
---|
6856 | Q_UINT16 code;
|
---|
6857 | };
|
---|
6858 |
|
---|
6859 | static const Entity entitylist [] = {
|
---|
6860 | { "AElig", 0x00c6 },
|
---|
6861 | { "Aacute", 0x00c1 },
|
---|
6862 | { "Acirc", 0x00c2 },
|
---|
6863 | { "Agrave", 0x00c0 },
|
---|
6864 | { "Alpha", 0x0391 },
|
---|
6865 | { "AMP", 38 },
|
---|
6866 | { "Aring", 0x00c5 },
|
---|
6867 | { "Atilde", 0x00c3 },
|
---|
6868 | { "Auml", 0x00c4 },
|
---|
6869 | { "Beta", 0x0392 },
|
---|
6870 | { "Ccedil", 0x00c7 },
|
---|
6871 | { "Chi", 0x03a7 },
|
---|
6872 | { "Dagger", 0x2021 },
|
---|
6873 | { "Delta", 0x0394 },
|
---|
6874 | { "ETH", 0x00d0 },
|
---|
6875 | { "Eacute", 0x00c9 },
|
---|
6876 | { "Ecirc", 0x00ca },
|
---|
6877 | { "Egrave", 0x00c8 },
|
---|
6878 | { "Epsilon", 0x0395 },
|
---|
6879 | { "Eta", 0x0397 },
|
---|
6880 | { "Euml", 0x00cb },
|
---|
6881 | { "Gamma", 0x0393 },
|
---|
6882 | { "GT", 62 },
|
---|
6883 | { "Iacute", 0x00cd },
|
---|
6884 | { "Icirc", 0x00ce },
|
---|
6885 | { "Igrave", 0x00cc },
|
---|
6886 | { "Iota", 0x0399 },
|
---|
6887 | { "Iuml", 0x00cf },
|
---|
6888 | { "Kappa", 0x039a },
|
---|
6889 | { "Lambda", 0x039b },
|
---|
6890 | { "LT", 60 },
|
---|
6891 | { "Mu", 0x039c },
|
---|
6892 | { "Ntilde", 0x00d1 },
|
---|
6893 | { "Nu", 0x039d },
|
---|
6894 | { "OElig", 0x0152 },
|
---|
6895 | { "Oacute", 0x00d3 },
|
---|
6896 | { "Ocirc", 0x00d4 },
|
---|
6897 | { "Ograve", 0x00d2 },
|
---|
6898 | { "Omega", 0x03a9 },
|
---|
6899 | { "Omicron", 0x039f },
|
---|
6900 | { "Oslash", 0x00d8 },
|
---|
6901 | { "Otilde", 0x00d5 },
|
---|
6902 | { "Ouml", 0x00d6 },
|
---|
6903 | { "Phi", 0x03a6 },
|
---|
6904 | { "Pi", 0x03a0 },
|
---|
6905 | { "Prime", 0x2033 },
|
---|
6906 | { "Psi", 0x03a8 },
|
---|
6907 | { "QUOT", 34 },
|
---|
6908 | { "Rho", 0x03a1 },
|
---|
6909 | { "Scaron", 0x0160 },
|
---|
6910 | { "Sigma", 0x03a3 },
|
---|
6911 | { "THORN", 0x00de },
|
---|
6912 | { "Tau", 0x03a4 },
|
---|
6913 | { "Theta", 0x0398 },
|
---|
6914 | { "Uacute", 0x00da },
|
---|
6915 | { "Ucirc", 0x00db },
|
---|
6916 | { "Ugrave", 0x00d9 },
|
---|
6917 | { "Upsilon", 0x03a5 },
|
---|
6918 | { "Uuml", 0x00dc },
|
---|
6919 | { "Xi", 0x039e },
|
---|
6920 | { "Yacute", 0x00dd },
|
---|
6921 | { "Yuml", 0x0178 },
|
---|
6922 | { "Zeta", 0x0396 },
|
---|
6923 | { "aacute", 0x00e1 },
|
---|
6924 | { "acirc", 0x00e2 },
|
---|
6925 | { "acute", 0x00b4 },
|
---|
6926 | { "aelig", 0x00e6 },
|
---|
6927 | { "agrave", 0x00e0 },
|
---|
6928 | { "alefsym", 0x2135 },
|
---|
6929 | { "alpha", 0x03b1 },
|
---|
6930 | { "amp", 38 },
|
---|
6931 | { "and", 0x22a5 },
|
---|
6932 | { "ang", 0x2220 },
|
---|
6933 | { "apos", 0x0027 },
|
---|
6934 | { "aring", 0x00e5 },
|
---|
6935 | { "asymp", 0x2248 },
|
---|
6936 | { "atilde", 0x00e3 },
|
---|
6937 | { "auml", 0x00e4 },
|
---|
6938 | { "bdquo", 0x201e },
|
---|
6939 | { "beta", 0x03b2 },
|
---|
6940 | { "brvbar", 0x00a6 },
|
---|
6941 | { "bull", 0x2022 },
|
---|
6942 | { "cap", 0x2229 },
|
---|
6943 | { "ccedil", 0x00e7 },
|
---|
6944 | { "cedil", 0x00b8 },
|
---|
6945 | { "cent", 0x00a2 },
|
---|
6946 | { "chi", 0x03c7 },
|
---|
6947 | { "circ", 0x02c6 },
|
---|
6948 | { "clubs", 0x2663 },
|
---|
6949 | { "cong", 0x2245 },
|
---|
6950 | { "copy", 0x00a9 },
|
---|
6951 | { "crarr", 0x21b5 },
|
---|
6952 | { "cup", 0x222a },
|
---|
6953 | { "curren", 0x00a4 },
|
---|
6954 | { "dArr", 0x21d3 },
|
---|
6955 | { "dagger", 0x2020 },
|
---|
6956 | { "darr", 0x2193 },
|
---|
6957 | { "deg", 0x00b0 },
|
---|
6958 | { "delta", 0x03b4 },
|
---|
6959 | { "diams", 0x2666 },
|
---|
6960 | { "divide", 0x00f7 },
|
---|
6961 | { "eacute", 0x00e9 },
|
---|
6962 | { "ecirc", 0x00ea },
|
---|
6963 | { "egrave", 0x00e8 },
|
---|
6964 | { "empty", 0x2205 },
|
---|
6965 | { "emsp", 0x2003 },
|
---|
6966 | { "ensp", 0x2002 },
|
---|
6967 | { "epsilon", 0x03b5 },
|
---|
6968 | { "equiv", 0x2261 },
|
---|
6969 | { "eta", 0x03b7 },
|
---|
6970 | { "eth", 0x00f0 },
|
---|
6971 | { "euml", 0x00eb },
|
---|
6972 | { "euro", 0x20ac },
|
---|
6973 | { "exist", 0x2203 },
|
---|
6974 | { "fnof", 0x0192 },
|
---|
6975 | { "forall", 0x2200 },
|
---|
6976 | { "frac12", 0x00bd },
|
---|
6977 | { "frac14", 0x00bc },
|
---|
6978 | { "frac34", 0x00be },
|
---|
6979 | { "frasl", 0x2044 },
|
---|
6980 | { "gamma", 0x03b3 },
|
---|
6981 | { "ge", 0x2265 },
|
---|
6982 | { "gt", 62 },
|
---|
6983 | { "hArr", 0x21d4 },
|
---|
6984 | { "harr", 0x2194 },
|
---|
6985 | { "hearts", 0x2665 },
|
---|
6986 | { "hellip", 0x2026 },
|
---|
6987 | { "iacute", 0x00ed },
|
---|
6988 | { "icirc", 0x00ee },
|
---|
6989 | { "iexcl", 0x00a1 },
|
---|
6990 | { "igrave", 0x00ec },
|
---|
6991 | { "image", 0x2111 },
|
---|
6992 | { "infin", 0x221e },
|
---|
6993 | { "int", 0x222b },
|
---|
6994 | { "iota", 0x03b9 },
|
---|
6995 | { "iquest", 0x00bf },
|
---|
6996 | { "isin", 0x2208 },
|
---|
6997 | { "iuml", 0x00ef },
|
---|
6998 | { "kappa", 0x03ba },
|
---|
6999 | { "lArr", 0x21d0 },
|
---|
7000 | { "lambda", 0x03bb },
|
---|
7001 | { "lang", 0x2329 },
|
---|
7002 | { "laquo", 0x00ab },
|
---|
7003 | { "larr", 0x2190 },
|
---|
7004 | { "lceil", 0x2308 },
|
---|
7005 | { "ldquo", 0x201c },
|
---|
7006 | { "le", 0x2264 },
|
---|
7007 | { "lfloor", 0x230a },
|
---|
7008 | { "lowast", 0x2217 },
|
---|
7009 | { "loz", 0x25ca },
|
---|
7010 | { "lrm", 0x200e },
|
---|
7011 | { "lsaquo", 0x2039 },
|
---|
7012 | { "lsquo", 0x2018 },
|
---|
7013 | { "lt", 60 },
|
---|
7014 | { "macr", 0x00af },
|
---|
7015 | { "mdash", 0x2014 },
|
---|
7016 | { "micro", 0x00b5 },
|
---|
7017 | { "middot", 0x00b7 },
|
---|
7018 | { "minus", 0x2212 },
|
---|
7019 | { "mu", 0x03bc },
|
---|
7020 | { "nabla", 0x2207 },
|
---|
7021 | { "nbsp", 0x00a0 },
|
---|
7022 | { "ndash", 0x2013 },
|
---|
7023 | { "ne", 0x2260 },
|
---|
7024 | { "ni", 0x220b },
|
---|
7025 | { "not", 0x00ac },
|
---|
7026 | { "notin", 0x2209 },
|
---|
7027 | { "nsub", 0x2284 },
|
---|
7028 | { "ntilde", 0x00f1 },
|
---|
7029 | { "nu", 0x03bd },
|
---|
7030 | { "oacute", 0x00f3 },
|
---|
7031 | { "ocirc", 0x00f4 },
|
---|
7032 | { "oelig", 0x0153 },
|
---|
7033 | { "ograve", 0x00f2 },
|
---|
7034 | { "oline", 0x203e },
|
---|
7035 | { "omega", 0x03c9 },
|
---|
7036 | { "omicron", 0x03bf },
|
---|
7037 | { "oplus", 0x2295 },
|
---|
7038 | { "or", 0x22a6 },
|
---|
7039 | { "ordf", 0x00aa },
|
---|
7040 | { "ordm", 0x00ba },
|
---|
7041 | { "oslash", 0x00f8 },
|
---|
7042 | { "otilde", 0x00f5 },
|
---|
7043 | { "otimes", 0x2297 },
|
---|
7044 | { "ouml", 0x00f6 },
|
---|
7045 | { "para", 0x00b6 },
|
---|
7046 | { "part", 0x2202 },
|
---|
7047 | { "percnt", 0x0025 },
|
---|
7048 | { "permil", 0x2030 },
|
---|
7049 | { "perp", 0x22a5 },
|
---|
7050 | { "phi", 0x03c6 },
|
---|
7051 | { "pi", 0x03c0 },
|
---|
7052 | { "piv", 0x03d6 },
|
---|
7053 | { "plusmn", 0x00b1 },
|
---|
7054 | { "pound", 0x00a3 },
|
---|
7055 | { "prime", 0x2032 },
|
---|
7056 | { "prod", 0x220f },
|
---|
7057 | { "prop", 0x221d },
|
---|
7058 | { "psi", 0x03c8 },
|
---|
7059 | { "quot", 34 },
|
---|
7060 | { "rArr", 0x21d2 },
|
---|
7061 | { "radic", 0x221a },
|
---|
7062 | { "rang", 0x232a },
|
---|
7063 | { "raquo", 0x00bb },
|
---|
7064 | { "rarr", 0x2192 },
|
---|
7065 | { "rceil", 0x2309 },
|
---|
7066 | { "rdquo", 0x201d },
|
---|
7067 | { "real", 0x211c },
|
---|
7068 | { "reg", 0x00ae },
|
---|
7069 | { "rfloor", 0x230b },
|
---|
7070 | { "rho", 0x03c1 },
|
---|
7071 | { "rlm", 0x200f },
|
---|
7072 | { "rsaquo", 0x203a },
|
---|
7073 | { "rsquo", 0x2019 },
|
---|
7074 | { "sbquo", 0x201a },
|
---|
7075 | { "scaron", 0x0161 },
|
---|
7076 | { "sdot", 0x22c5 },
|
---|
7077 | { "sect", 0x00a7 },
|
---|
7078 | { "shy", 0x00ad },
|
---|
7079 | { "sigma", 0x03c3 },
|
---|
7080 | { "sigmaf", 0x03c2 },
|
---|
7081 | { "sim", 0x223c },
|
---|
7082 | { "spades", 0x2660 },
|
---|
7083 | { "sub", 0x2282 },
|
---|
7084 | { "sube", 0x2286 },
|
---|
7085 | { "sum", 0x2211 },
|
---|
7086 | { "sup1", 0x00b9 },
|
---|
7087 | { "sup2", 0x00b2 },
|
---|
7088 | { "sup3", 0x00b3 },
|
---|
7089 | { "sup", 0x2283 },
|
---|
7090 | { "supe", 0x2287 },
|
---|
7091 | { "szlig", 0x00df },
|
---|
7092 | { "tau", 0x03c4 },
|
---|
7093 | { "there4", 0x2234 },
|
---|
7094 | { "theta", 0x03b8 },
|
---|
7095 | { "thetasym", 0x03d1 },
|
---|
7096 | { "thinsp", 0x2009 },
|
---|
7097 | { "thorn", 0x00fe },
|
---|
7098 | { "tilde", 0x02dc },
|
---|
7099 | { "times", 0x00d7 },
|
---|
7100 | { "trade", 0x2122 },
|
---|
7101 | { "uArr", 0x21d1 },
|
---|
7102 | { "uacute", 0x00fa },
|
---|
7103 | { "uarr", 0x2191 },
|
---|
7104 | { "ucirc", 0x00fb },
|
---|
7105 | { "ugrave", 0x00f9 },
|
---|
7106 | { "uml", 0x00a8 },
|
---|
7107 | { "upsih", 0x03d2 },
|
---|
7108 | { "upsilon", 0x03c5 },
|
---|
7109 | { "uuml", 0x00fc },
|
---|
7110 | { "weierp", 0x2118 },
|
---|
7111 | { "xi", 0x03be },
|
---|
7112 | { "yacute", 0x00fd },
|
---|
7113 | { "yen", 0x00a5 },
|
---|
7114 | { "yuml", 0x00ff },
|
---|
7115 | { "zeta", 0x03b6 },
|
---|
7116 | { "zwj", 0x200d },
|
---|
7117 | { "zwnj", 0x200c },
|
---|
7118 | { "", 0x0000 }
|
---|
7119 | };
|
---|
7120 |
|
---|
7121 |
|
---|
7122 |
|
---|
7123 |
|
---|
7124 |
|
---|
7125 | static QMap<QCString, QChar> *html_map = 0;
|
---|
7126 | static void qt_cleanup_html_map()
|
---|
7127 | {
|
---|
7128 | delete html_map;
|
---|
7129 | html_map = 0;
|
---|
7130 | }
|
---|
7131 |
|
---|
7132 | static QMap<QCString, QChar> *htmlMap()
|
---|
7133 | {
|
---|
7134 | if ( !html_map ) {
|
---|
7135 | html_map = new QMap<QCString, QChar>;
|
---|
7136 | qAddPostRoutine( qt_cleanup_html_map );
|
---|
7137 |
|
---|
7138 | const Entity *ent = entitylist;
|
---|
7139 | while( ent->code ) {
|
---|
7140 | html_map->insert( ent->name, QChar(ent->code) );
|
---|
7141 | ent++;
|
---|
7142 | }
|
---|
7143 | }
|
---|
7144 | return html_map;
|
---|
7145 | }
|
---|
7146 |
|
---|
7147 | QChar QTextDocument::parseHTMLSpecialChar(const QChar* doc, int length, int& pos)
|
---|
7148 | {
|
---|
7149 | QCString s;
|
---|
7150 | pos++;
|
---|
7151 | int recoverpos = pos;
|
---|
7152 | while ( pos < length && doc[pos] != ';' && !doc[pos].isSpace() && pos < recoverpos + 8 ) {
|
---|
7153 | s += doc[pos];
|
---|
7154 | pos++;
|
---|
7155 | }
|
---|
7156 | if (doc[pos] != ';' && !doc[pos].isSpace() ) {
|
---|
7157 | pos = recoverpos;
|
---|
7158 | return '&';
|
---|
7159 | }
|
---|
7160 | pos++;
|
---|
7161 |
|
---|
7162 | if ( s.length() > 1 && s[0] == '#') {
|
---|
7163 | int num = s.mid(1).toInt();
|
---|
7164 | if ( num == 151 ) // ### hack for designer manual
|
---|
7165 | return '-';
|
---|
7166 | return num;
|
---|
7167 | }
|
---|
7168 |
|
---|
7169 | QMap<QCString, QChar>::Iterator it = htmlMap()->find(s);
|
---|
7170 | if ( it != htmlMap()->end() ) {
|
---|
7171 | return *it;
|
---|
7172 | }
|
---|
7173 |
|
---|
7174 | pos = recoverpos;
|
---|
7175 | return '&';
|
---|
7176 | }
|
---|
7177 |
|
---|
7178 | QString QTextDocument::parseWord(const QChar* doc, int length, int& pos, bool lower)
|
---|
7179 | {
|
---|
7180 | QString s;
|
---|
7181 |
|
---|
7182 | if (doc[pos] == '"') {
|
---|
7183 | pos++;
|
---|
7184 | while ( pos < length && doc[pos] != '"' ) {
|
---|
7185 | if ( doc[pos] == '&' ) {
|
---|
7186 | s += parseHTMLSpecialChar( doc, length, pos );
|
---|
7187 | } else {
|
---|
7188 | s += doc[pos];
|
---|
7189 | pos++;
|
---|
7190 | }
|
---|
7191 | }
|
---|
7192 | eat(doc, length, pos, '"');
|
---|
7193 | } else if (doc[pos] == '\'') {
|
---|
7194 | pos++;
|
---|
7195 | while ( pos < length && doc[pos] != '\'' ) {
|
---|
7196 | s += doc[pos];
|
---|
7197 | pos++;
|
---|
7198 | }
|
---|
7199 | eat(doc, length, pos, '\'');
|
---|
7200 | } else {
|
---|
7201 | static QString term = QString::fromLatin1("/>");
|
---|
7202 | while ( pos < length
|
---|
7203 | && doc[pos] != '>'
|
---|
7204 | && !hasPrefix(doc, length, pos, term)
|
---|
7205 | && doc[pos] != '<'
|
---|
7206 | && doc[pos] != '='
|
---|
7207 | && !doc[pos].isSpace() )
|
---|
7208 | {
|
---|
7209 | if ( doc[pos] == '&' ) {
|
---|
7210 | s += parseHTMLSpecialChar( doc, length, pos );
|
---|
7211 | } else {
|
---|
7212 | s += doc[pos];
|
---|
7213 | pos++;
|
---|
7214 | }
|
---|
7215 | }
|
---|
7216 | if (lower)
|
---|
7217 | s = s.lower();
|
---|
7218 | }
|
---|
7219 | return s;
|
---|
7220 | }
|
---|
7221 |
|
---|
7222 | QChar QTextDocument::parseChar(const QChar* doc, int length, int& pos, QStyleSheetItem::WhiteSpaceMode wsm )
|
---|
7223 | {
|
---|
7224 | if ( pos >= length )
|
---|
7225 | return QChar::null;
|
---|
7226 |
|
---|
7227 | QChar c = doc[pos++];
|
---|
7228 |
|
---|
7229 | if (c == '<' )
|
---|
7230 | return QChar::null;
|
---|
7231 |
|
---|
7232 | if ( c.isSpace() && c != QChar::nbsp ) {
|
---|
7233 | if ( wsm == QStyleSheetItem::WhiteSpacePre ) {
|
---|
7234 | if ( c == '\n' )
|
---|
7235 | return QChar_linesep;
|
---|
7236 | else
|
---|
7237 | return c;
|
---|
7238 | } else { // non-pre mode: collapse whitespace except nbsp
|
---|
7239 | while ( pos< length &&
|
---|
7240 | doc[pos].isSpace() && doc[pos] != QChar::nbsp )
|
---|
7241 | pos++;
|
---|
7242 | return ' ';
|
---|
7243 | }
|
---|
7244 | }
|
---|
7245 | else if ( c == '&' )
|
---|
7246 | return parseHTMLSpecialChar( doc, length, --pos );
|
---|
7247 | else
|
---|
7248 | return c;
|
---|
7249 | }
|
---|
7250 |
|
---|
7251 | QString QTextDocument::parseOpenTag(const QChar* doc, int length, int& pos,
|
---|
7252 | QMap<QString, QString> &attr, bool& emptyTag)
|
---|
7253 | {
|
---|
7254 | emptyTag = FALSE;
|
---|
7255 | pos++;
|
---|
7256 | if ( hasPrefix(doc, length, pos, '!') ) {
|
---|
7257 | if ( hasPrefix( doc, length, pos+1, "--")) {
|
---|
7258 | pos += 3;
|
---|
7259 | // eat comments
|
---|
7260 | QString pref = QString::fromLatin1("-->");
|
---|
7261 | while ( !hasPrefix(doc, length, pos, pref ) && pos < length )
|
---|
7262 | pos++;
|
---|
7263 | if ( hasPrefix(doc, length, pos, pref ) ) {
|
---|
7264 | pos += 3;
|
---|
7265 | eatSpace(doc, length, pos, TRUE);
|
---|
7266 | }
|
---|
7267 | emptyTag = TRUE;
|
---|
7268 | return QString::null;
|
---|
7269 | }
|
---|
7270 | else {
|
---|
7271 | // eat strange internal tags
|
---|
7272 | while ( !hasPrefix(doc, length, pos, '>') && pos < length )
|
---|
7273 | pos++;
|
---|
7274 | if ( hasPrefix(doc, length, pos, '>') ) {
|
---|
7275 | pos++;
|
---|
7276 | eatSpace(doc, length, pos, TRUE);
|
---|
7277 | }
|
---|
7278 | return QString::null;
|
---|
7279 | }
|
---|
7280 | }
|
---|
7281 |
|
---|
7282 | QString tag = parseWord(doc, length, pos );
|
---|
7283 | eatSpace(doc, length, pos, TRUE);
|
---|
7284 | static QString term = QString::fromLatin1("/>");
|
---|
7285 | static QString s_TRUE = QString::fromLatin1("TRUE");
|
---|
7286 |
|
---|
7287 | while (doc[pos] != '>' && ! (emptyTag = hasPrefix(doc, length, pos, term) )) {
|
---|
7288 | QString key = parseWord(doc, length, pos );
|
---|
7289 | eatSpace(doc, length, pos, TRUE);
|
---|
7290 | if ( key.isEmpty()) {
|
---|
7291 | // error recovery
|
---|
7292 | while ( pos < length && doc[pos] != '>' )
|
---|
7293 | pos++;
|
---|
7294 | break;
|
---|
7295 | }
|
---|
7296 | QString value;
|
---|
7297 | if (hasPrefix(doc, length, pos, '=') ){
|
---|
7298 | pos++;
|
---|
7299 | eatSpace(doc, length, pos);
|
---|
7300 | value = parseWord(doc, length, pos, FALSE);
|
---|
7301 | }
|
---|
7302 | else
|
---|
7303 | value = s_TRUE;
|
---|
7304 | attr.insert(key.lower(), value );
|
---|
7305 | eatSpace(doc, length, pos, TRUE);
|
---|
7306 | }
|
---|
7307 |
|
---|
7308 | if (emptyTag) {
|
---|
7309 | eat(doc, length, pos, '/');
|
---|
7310 | eat(doc, length, pos, '>');
|
---|
7311 | }
|
---|
7312 | else
|
---|
7313 | eat(doc, length, pos, '>');
|
---|
7314 |
|
---|
7315 | return tag;
|
---|
7316 | }
|
---|
7317 |
|
---|
7318 | QString QTextDocument::parseCloseTag( const QChar* doc, int length, int& pos )
|
---|
7319 | {
|
---|
7320 | pos++;
|
---|
7321 | pos++;
|
---|
7322 | QString tag = parseWord(doc, length, pos );
|
---|
7323 | eatSpace(doc, length, pos, TRUE);
|
---|
7324 | eat(doc, length, pos, '>');
|
---|
7325 | return tag;
|
---|
7326 | }
|
---|
7327 |
|
---|
7328 | QTextFlow::QTextFlow()
|
---|
7329 | {
|
---|
7330 | w = pagesize = 0;
|
---|
7331 | }
|
---|
7332 |
|
---|
7333 | QTextFlow::~QTextFlow()
|
---|
7334 | {
|
---|
7335 | clear();
|
---|
7336 | }
|
---|
7337 |
|
---|
7338 | void QTextFlow::clear()
|
---|
7339 | {
|
---|
7340 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
7341 | leftItems.setAutoDelete( TRUE );
|
---|
7342 | rightItems.setAutoDelete( TRUE );
|
---|
7343 | leftItems.clear();
|
---|
7344 | rightItems.clear();
|
---|
7345 | leftItems.setAutoDelete( FALSE );
|
---|
7346 | rightItems.setAutoDelete( FALSE );
|
---|
7347 | #endif
|
---|
7348 | }
|
---|
7349 |
|
---|
7350 | void QTextFlow::setWidth( int width )
|
---|
7351 | {
|
---|
7352 | w = width;
|
---|
7353 | }
|
---|
7354 |
|
---|
7355 | int QTextFlow::adjustLMargin( int yp, int, int margin, int space )
|
---|
7356 | {
|
---|
7357 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
7358 | for ( QTextCustomItem* item = leftItems.first(); item; item = leftItems.next() ) {
|
---|
7359 | if ( item->ypos == -1 )
|
---|
7360 | continue;
|
---|
7361 | if ( yp >= item->ypos && yp < item->ypos + item->height )
|
---|
7362 | margin = QMAX( margin, item->xpos + item->width + space );
|
---|
7363 | }
|
---|
7364 | #endif
|
---|
7365 | return margin;
|
---|
7366 | }
|
---|
7367 |
|
---|
7368 | int QTextFlow::adjustRMargin( int yp, int, int margin, int space )
|
---|
7369 | {
|
---|
7370 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
7371 | for ( QTextCustomItem* item = rightItems.first(); item; item = rightItems.next() ) {
|
---|
7372 | if ( item->ypos == -1 )
|
---|
7373 | continue;
|
---|
7374 | if ( yp >= item->ypos && yp < item->ypos + item->height )
|
---|
7375 | margin = QMAX( margin, w - item->xpos - space );
|
---|
7376 | }
|
---|
7377 | #endif
|
---|
7378 | return margin;
|
---|
7379 | }
|
---|
7380 |
|
---|
7381 |
|
---|
7382 | int QTextFlow::adjustFlow( int y, int /*w*/, int h )
|
---|
7383 | {
|
---|
7384 | if ( pagesize > 0 ) { // check pages
|
---|
7385 | int yinpage = y % pagesize;
|
---|
7386 | if ( yinpage <= border_tolerance )
|
---|
7387 | return border_tolerance - yinpage;
|
---|
7388 | else
|
---|
7389 | if ( yinpage + h > pagesize - border_tolerance )
|
---|
7390 | return ( pagesize - yinpage ) + border_tolerance;
|
---|
7391 | }
|
---|
7392 | return 0;
|
---|
7393 | }
|
---|
7394 |
|
---|
7395 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
7396 | void QTextFlow::unregisterFloatingItem( QTextCustomItem* item )
|
---|
7397 | {
|
---|
7398 | leftItems.removeRef( item );
|
---|
7399 | rightItems.removeRef( item );
|
---|
7400 | }
|
---|
7401 |
|
---|
7402 | void QTextFlow::registerFloatingItem( QTextCustomItem* item )
|
---|
7403 | {
|
---|
7404 | if ( item->placement() == QTextCustomItem::PlaceRight ) {
|
---|
7405 | if ( !rightItems.contains( item ) )
|
---|
7406 | rightItems.append( item );
|
---|
7407 | } else if ( item->placement() == QTextCustomItem::PlaceLeft &&
|
---|
7408 | !leftItems.contains( item ) ) {
|
---|
7409 | leftItems.append( item );
|
---|
7410 | }
|
---|
7411 | }
|
---|
7412 | #endif // QT_NO_TEXTCUSTOMITEM
|
---|
7413 |
|
---|
7414 | QRect QTextFlow::boundingRect() const
|
---|
7415 | {
|
---|
7416 | QRect br;
|
---|
7417 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
7418 | QPtrListIterator<QTextCustomItem> l( leftItems );
|
---|
7419 | while( l.current() ) {
|
---|
7420 | br = br.unite( l.current()->geometry() );
|
---|
7421 | ++l;
|
---|
7422 | }
|
---|
7423 | QPtrListIterator<QTextCustomItem> r( rightItems );
|
---|
7424 | while( r.current() ) {
|
---|
7425 | br = br.unite( r.current()->geometry() );
|
---|
7426 | ++r;
|
---|
7427 | }
|
---|
7428 | #endif
|
---|
7429 | return br;
|
---|
7430 | }
|
---|
7431 |
|
---|
7432 |
|
---|
7433 | void QTextFlow::drawFloatingItems( QPainter* p, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected )
|
---|
7434 | {
|
---|
7435 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
7436 | QTextCustomItem *item;
|
---|
7437 | for ( item = leftItems.first(); item; item = leftItems.next() ) {
|
---|
7438 | if ( item->xpos == -1 || item->ypos == -1 )
|
---|
7439 | continue;
|
---|
7440 | item->draw( p, item->xpos, item->ypos, cx, cy, cw, ch, cg, selected );
|
---|
7441 | }
|
---|
7442 |
|
---|
7443 | for ( item = rightItems.first(); item; item = rightItems.next() ) {
|
---|
7444 | if ( item->xpos == -1 || item->ypos == -1 )
|
---|
7445 | continue;
|
---|
7446 | item->draw( p, item->xpos, item->ypos, cx, cy, cw, ch, cg, selected );
|
---|
7447 | }
|
---|
7448 | #endif
|
---|
7449 | }
|
---|
7450 |
|
---|
7451 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
---|
7452 |
|
---|
7453 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
7454 | void QTextCustomItem::pageBreak( int /*y*/ , QTextFlow* /*flow*/ )
|
---|
7455 | {
|
---|
7456 | }
|
---|
7457 | #endif
|
---|
7458 |
|
---|
7459 | #ifndef QT_NO_TEXTCUSTOMITEM
|
---|
7460 | QTextTable::QTextTable( QTextDocument *p, const QMap<QString, QString> & attr )
|
---|
7461 | : QTextCustomItem( p )
|
---|
7462 | {
|
---|
7463 | cells.setAutoDelete( FALSE );
|
---|
7464 | cellspacing = 2;
|
---|
7465 | if ( attr.contains("cellspacing") )
|
---|
7466 | cellspacing = attr["cellspacing"].toInt();
|
---|
7467 | cellpadding = 1;
|
---|
7468 | if ( attr.contains("cellpadding") )
|
---|
7469 | cellpadding = attr["cellpadding"].toInt();
|
---|
7470 | border = innerborder = 0;
|
---|
7471 | if ( attr.contains("border" ) ) {
|
---|
7472 | QString s( attr["border"] );
|
---|
7473 | if ( s == "TRUE" )
|
---|
7474 | border = 1;
|
---|
7475 | else
|
---|
7476 | border = attr["border"].toInt();
|
---|
7477 | }
|
---|
7478 | us_b = border;
|
---|
7479 |
|
---|
7480 | innerborder = us_ib = border ? 1 : 0;
|
---|
7481 |
|
---|
7482 | if ( border )
|
---|
7483 | cellspacing += 2;
|
---|
7484 |
|
---|
7485 | us_ib = innerborder;
|
---|
7486 | us_cs = cellspacing;
|
---|
7487 | us_cp = cellpadding;
|
---|
7488 | outerborder = cellspacing + border;
|
---|
7489 | us_ob = outerborder;
|
---|
7490 | layout = new QGridLayout( 1, 1, cellspacing );
|
---|
7491 |
|
---|
7492 | fixwidth = 0;
|
---|
7493 | stretch = 0;
|
---|
7494 | if ( attr.contains("width") ) {
|
---|
7495 | bool b;
|
---|
7496 | QString s( attr["width"] );
|
---|
7497 | int w = s.toInt( &b );
|
---|
7498 | if ( b ) {
|
---|
7499 | fixwidth = w;
|
---|
7500 | } else {
|
---|
7501 | s = s.stripWhiteSpace();
|
---|
7502 | if ( s.length() > 1 && s[ (int)s.length()-1 ] == '%' )
|
---|
7503 | stretch = s.left( s.length()-1).toInt();
|
---|
7504 | }
|
---|
7505 | }
|
---|
7506 |
|
---|
7507 | place = PlaceInline;
|
---|
7508 | if ( attr["align"] == "left" )
|
---|
7509 | place = PlaceLeft;
|
---|
7510 | else if ( attr["align"] == "right" )
|
---|
7511 | place = PlaceRight;
|
---|
7512 | cachewidth = 0;
|
---|
7513 | attributes = attr;
|
---|
7514 | pageBreakFor = -1;
|
---|
7515 | }
|
---|
7516 |
|
---|
7517 | QTextTable::~QTextTable()
|
---|
7518 | {
|
---|
7519 | delete layout;
|
---|
7520 | }
|
---|
7521 |
|
---|
7522 | QString QTextTable::richText() const
|
---|
7523 | {
|
---|
7524 | QString s;
|
---|
7525 | s = "<table ";
|
---|
7526 | QMap<QString, QString>::ConstIterator it = attributes.begin();
|
---|
7527 | for ( ; it != attributes.end(); ++it )
|
---|
7528 | s += it.key() + "=" + *it + " ";
|
---|
7529 | s += ">\n";
|
---|
7530 |
|
---|
7531 | int lastRow = -1;
|
---|
7532 | bool needEnd = FALSE;
|
---|
7533 | QPtrListIterator<QTextTableCell> it2( cells );
|
---|
7534 | while ( it2.current() ) {
|
---|
7535 | QTextTableCell *cell = it2.current();
|
---|
7536 | ++it2;
|
---|
7537 | if ( lastRow != cell->row() ) {
|
---|
7538 | if ( lastRow != -1 )
|
---|
7539 | s += "</tr>\n";
|
---|
7540 | s += "<tr>";
|
---|
7541 | lastRow = cell->row();
|
---|
7542 | needEnd = TRUE;
|
---|
7543 | }
|
---|
7544 | s += "<td";
|
---|
7545 | it = cell->attributes.begin();
|
---|
7546 | for ( ; it != cell->attributes.end(); ++it )
|
---|
7547 | s += " " + it.key() + "=" + *it;
|
---|
7548 | s += ">";
|
---|
7549 | s += cell->richText()->richText();
|
---|
7550 | s += "</td>";
|
---|
7551 | }
|
---|
7552 | if ( needEnd )
|
---|
7553 | s += "</tr>\n";
|
---|
7554 | s += "</table>\n";
|
---|
7555 | return s;
|
---|
7556 | }
|
---|
7557 |
|
---|
7558 | void QTextTable::adjustToPainter( QPainter* p )
|
---|
7559 | {
|
---|
7560 | cellspacing = scale( us_cs, p );
|
---|
7561 | cellpadding = scale( us_cp, p );
|
---|
7562 | border = scale( us_b , p );
|
---|
7563 | innerborder = scale( us_ib, p );
|
---|
7564 | outerborder = scale( us_ob ,p );
|
---|
7565 | width = 0;
|
---|
7566 | cachewidth = 0;
|
---|
7567 | for ( QTextTableCell* cell = cells.first(); cell; cell = cells.next() )
|
---|
7568 | cell->adjustToPainter( p );
|
---|
7569 | }
|
---|
7570 |
|
---|
7571 | void QTextTable::adjustCells( int y , int shift )
|
---|
7572 | {
|
---|
7573 | QPtrListIterator<QTextTableCell> it( cells );
|
---|
7574 | QTextTableCell* cell;
|
---|
7575 | bool enlarge = FALSE;
|
---|
7576 | while ( ( cell = it.current() ) ) {
|
---|
7577 | ++it;
|
---|
7578 | QRect r = cell->geometry();
|
---|
7579 | if ( y <= r.top() ) {
|
---|
7580 | r.moveBy(0, shift );
|
---|
7581 | cell->setGeometry( r );
|
---|
7582 | enlarge = TRUE;
|
---|
7583 | } else if ( y <= r.bottom() ) {
|
---|
7584 | r.rBottom() += shift;
|
---|
7585 | cell->setGeometry( r );
|
---|
7586 | enlarge = TRUE;
|
---|
7587 | }
|
---|
7588 | }
|
---|
7589 | if ( enlarge )
|
---|
7590 | height += shift;
|
---|
7591 | }
|
---|
7592 |
|
---|
7593 | void QTextTable::pageBreak( int yt, QTextFlow* flow )
|
---|
7594 | {
|
---|
7595 | if ( flow->pageSize() <= 0 )
|
---|
7596 | return;
|
---|
7597 | if ( layout && pageBreakFor > 0 && pageBreakFor != yt ) {
|
---|
7598 | layout->invalidate();
|
---|
7599 | int h = layout->heightForWidth( width-2*outerborder );
|
---|
7600 | layout->setGeometry( QRect(0, 0, width-2*outerborder, h) );
|
---|
7601 | height = layout->geometry().height()+2*outerborder;
|
---|
7602 | }
|
---|
7603 | pageBreakFor = yt;
|
---|
7604 | QPtrListIterator<QTextTableCell> it( cells );
|
---|
7605 | QTextTableCell* cell;
|
---|
7606 | while ( ( cell = it.current() ) ) {
|
---|
7607 | ++it;
|
---|
7608 | int y = yt + outerborder + cell->geometry().y();
|
---|
7609 | int shift = flow->adjustFlow( y - cellspacing, width, cell->richText()->height() + 2*cellspacing );
|
---|
7610 | adjustCells( y - outerborder - yt, shift );
|
---|
7611 | }
|
---|
7612 | }
|
---|
7613 |
|
---|
7614 |
|
---|
7615 | void QTextTable::draw(QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected )
|
---|
7616 | {
|
---|
7617 | if ( placement() != PlaceInline ) {
|
---|
7618 | x = xpos;
|
---|
7619 | y = ypos;
|
---|
7620 | }
|
---|
7621 |
|
---|
7622 | for (QTextTableCell* cell = cells.first(); cell; cell = cells.next() ) {
|
---|
7623 | if ( cx < 0 && cy < 0 ||
|
---|
7624 | QRect( cx, cy, cw, ch ).intersects( QRect( x + outerborder + cell->geometry().x(),
|
---|
7625 | y + outerborder + cell->geometry().y(),
|
---|
7626 | cell->geometry().width(), cell->geometry().height() ) ) ) {
|
---|
7627 | cell->draw( p, x+outerborder, y+outerborder, cx, cy, cw, ch, cg, selected );
|
---|
7628 | if ( border ) {
|
---|
7629 | QRect r( x+outerborder+cell->geometry().x() - innerborder,
|
---|
7630 | y+outerborder+cell->geometry().y() - innerborder,
|
---|
7631 | cell->geometry().width() + 2 * innerborder,
|
---|
7632 | cell->geometry().height() + 2 * innerborder );
|
---|
7633 | if ( is_printer( p ) ) {
|
---|
7634 | QPen oldPen = p->pen();
|
---|
7635 | QRect r2 = r;
|
---|
7636 | r2.addCoords( innerborder/2, innerborder/2, -innerborder/2, -innerborder/2 );
|
---|
7637 | p->setPen( QPen( cg.text(), innerborder ) );
|
---|
7638 | p->drawRect( r2 );
|
---|
7639 | p->setPen( oldPen );
|
---|
7640 | } else {
|
---|
7641 | int s = QMAX( cellspacing-2*innerborder, 0);
|
---|
7642 | if ( s ) {
|
---|
7643 | p->fillRect( r.left()-s, r.top(), s+1, r.height(), cg.button() );
|
---|
7644 | p->fillRect( r.right(), r.top(), s+1, r.height(), cg.button() );
|
---|
7645 | p->fillRect( r.left()-s, r.top()-s, r.width()+2*s, s, cg.button() );
|
---|
7646 | p->fillRect( r.left()-s, r.bottom(), r.width()+2*s, s, cg.button() );
|
---|
7647 | }
|
---|
7648 | qDrawShadePanel( p, r, cg, TRUE, innerborder );
|
---|
7649 | }
|
---|
7650 | }
|
---|
7651 | }
|
---|
7652 | }
|
---|
7653 | if ( border ) {
|
---|
7654 | QRect r ( x, y, width, height );
|
---|
7655 | if ( is_printer( p ) ) {
|
---|
7656 | QRect r2 = r;
|
---|
7657 | r2.addCoords( border/2, border/2, -border/2, -border/2 );
|
---|
7658 | QPen oldPen = p->pen();
|
---|
7659 | p->setPen( QPen( cg.text(), border ) );
|
---|
7660 | p->drawRect( r2 );
|
---|
7661 | p->setPen( oldPen );
|
---|
7662 | } else {
|
---|
7663 | int s = border+QMAX( cellspacing-2*innerborder, 0);
|
---|
7664 | if ( s ) {
|
---|
7665 | p->fillRect( r.left(), r.top(), s, r.height(), cg.button() );
|
---|
7666 | p->fillRect( r.right()-s, r.top(), s, r.height(), cg.button() );
|
---|
7667 | p->fillRect( r.left(), r.top(), r.width(), s, cg.button() );
|
---|
7668 | p->fillRect( r.left(), r.bottom()-s, r.width(), s, cg.button() );
|
---|
7669 | }
|
---|
7670 | qDrawShadePanel( p, r, cg, FALSE, border );
|
---|
7671 | }
|
---|
7672 | }
|
---|
7673 |
|
---|
7674 | }
|
---|
7675 |
|
---|
7676 | int QTextTable::minimumWidth() const
|
---|
7677 | {
|
---|
7678 | return fixwidth ? fixwidth : ((layout ? layout->minimumSize().width() : 0) + 2 * outerborder);
|
---|
7679 | }
|
---|
7680 |
|
---|
7681 | void QTextTable::resize( int nwidth )
|
---|
7682 | {
|
---|
7683 | if ( fixwidth && cachewidth != 0 )
|
---|
7684 | return;
|
---|
7685 | if ( nwidth == cachewidth )
|
---|
7686 | return;
|
---|
7687 |
|
---|
7688 |
|
---|
7689 | cachewidth = nwidth;
|
---|
7690 | int w = nwidth;
|
---|
7691 |
|
---|
7692 | format( w );
|
---|
7693 |
|
---|
7694 | if ( stretch )
|
---|
7695 | nwidth = nwidth * stretch / 100;
|
---|
7696 |
|
---|
7697 | width = nwidth;
|
---|
7698 | layout->invalidate();
|
---|
7699 | int shw = layout->sizeHint().width() + 2*outerborder;
|
---|
7700 | int mw = layout->minimumSize().width() + 2*outerborder;
|
---|
7701 | if ( stretch )
|
---|
7702 | width = QMAX( mw, nwidth );
|
---|
7703 | else
|
---|
7704 | width = QMAX( mw, QMIN( nwidth, shw ) );
|
---|
7705 |
|
---|
7706 | if ( fixwidth )
|
---|
7707 | width = fixwidth;
|
---|
7708 |
|
---|
7709 | layout->invalidate();
|
---|
7710 | mw = layout->minimumSize().width() + 2*outerborder;
|
---|
7711 | width = QMAX( width, mw );
|
---|
7712 |
|
---|
7713 | int h = layout->heightForWidth( width-2*outerborder );
|
---|
7714 | layout->setGeometry( QRect(0, 0, width-2*outerborder, h) );
|
---|
7715 | height = layout->geometry().height()+2*outerborder;
|
---|
7716 | }
|
---|
7717 |
|
---|
7718 | void QTextTable::format( int w )
|
---|
7719 | {
|
---|
7720 | for ( int i = 0; i < (int)cells.count(); ++i ) {
|
---|
7721 | QTextTableCell *cell = cells.at( i );
|
---|
7722 | QRect r = cell->geometry();
|
---|
7723 | r.setWidth( w - 2*outerborder );
|
---|
7724 | cell->setGeometry( r );
|
---|
7725 | }
|
---|
7726 | }
|
---|
7727 |
|
---|
7728 | void QTextTable::addCell( QTextTableCell* cell )
|
---|
7729 | {
|
---|
7730 | cells.append( cell );
|
---|
7731 | layout->addMultiCell( cell, cell->row(), cell->row() + cell->rowspan()-1,
|
---|
7732 | cell->column(), cell->column() + cell->colspan()-1 );
|
---|
7733 | }
|
---|
7734 |
|
---|
7735 | bool QTextTable::enter( QTextCursor *c, QTextDocument *&doc, QTextParagraph *¶g, int &idx, int &ox, int &oy, bool atEnd )
|
---|
7736 | {
|
---|
7737 | currCell.remove( c );
|
---|
7738 | if ( !atEnd )
|
---|
7739 | return next( c, doc, parag, idx, ox, oy );
|
---|
7740 | currCell.insert( c, cells.count() );
|
---|
7741 | return prev( c, doc, parag, idx, ox, oy );
|
---|
7742 | }
|
---|
7743 |
|
---|
7744 | bool QTextTable::enterAt( QTextCursor *c, QTextDocument *&doc, QTextParagraph *¶g, int &idx, int &ox, int &oy, const QPoint &pos )
|
---|
7745 | {
|
---|
7746 | currCell.remove( c );
|
---|
7747 | int lastCell = -1;
|
---|
7748 | int lastY = -1;
|
---|
7749 | int i;
|
---|
7750 | for ( i = 0; i < (int)cells.count(); ++i ) {
|
---|
7751 | QTextTableCell *cell = cells.at( i );
|
---|
7752 | if ( !cell )
|
---|
7753 | continue;
|
---|
7754 | QRect r( cell->geometry().x(),
|
---|
7755 | cell->geometry().y(),
|
---|
7756 | cell->geometry().width() + 2 * innerborder + 2 * outerborder,
|
---|
7757 | cell->geometry().height() + 2 * innerborder + 2 * outerborder );
|
---|
7758 |
|
---|
7759 | if ( r.left() <= pos.x() && r.right() >= pos.x() ) {
|
---|
7760 | if ( cell->geometry().y() > lastY ) {
|
---|
7761 | lastCell = i;
|
---|
7762 | lastY = cell->geometry().y();
|
---|
7763 | }
|
---|
7764 | if ( r.top() <= pos.y() && r.bottom() >= pos.y() ) {
|
---|
7765 | currCell.insert( c, i );
|
---|
7766 | break;
|
---|
7767 | }
|
---|
7768 | }
|
---|
7769 | }
|
---|
7770 | if ( i == (int) cells.count() )
|
---|
7771 | return FALSE; // no cell found
|
---|
7772 |
|
---|
7773 | if ( currCell.find( c ) == currCell.end() ) {
|
---|
7774 | if ( lastY != -1 )
|
---|
7775 | currCell.insert( c, lastCell );
|
---|
7776 | else
|
---|
7777 | return FALSE;
|
---|
7778 | }
|
---|
7779 |
|
---|
7780 | QTextTableCell *cell = cells.at( *currCell.find( c ) );
|
---|
7781 | if ( !cell )
|
---|
7782 | return FALSE;
|
---|
7783 | doc = cell->richText();
|
---|
7784 | parag = doc->firstParagraph();
|
---|
7785 | idx = 0;
|
---|
7786 | ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
|
---|
7787 | oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
|
---|
7788 | return TRUE;
|
---|
7789 | }
|
---|
7790 |
|
---|
7791 | bool QTextTable::next( QTextCursor *c, QTextDocument *&doc, QTextParagraph *¶g, int &idx, int &ox, int &oy )
|
---|
7792 | {
|
---|
7793 | int cc = -1;
|
---|
7794 | if ( currCell.find( c ) != currCell.end() )
|
---|
7795 | cc = *currCell.find( c );
|
---|
7796 | if ( cc > (int)cells.count() - 1 || cc < 0 )
|
---|
7797 | cc = -1;
|
---|
7798 | currCell.remove( c );
|
---|
7799 | currCell.insert( c, ++cc );
|
---|
7800 | if ( cc >= (int)cells.count() ) {
|
---|
7801 | currCell.insert( c, 0 );
|
---|
7802 | QTextCustomItem::next( c, doc, parag, idx, ox, oy );
|
---|
7803 | QTextTableCell *cell = cells.first();
|
---|
7804 | if ( !cell )
|
---|
7805 | return FALSE;
|
---|
7806 | doc = cell->richText();
|
---|
7807 | idx = -1;
|
---|
7808 | return TRUE;
|
---|
7809 | }
|
---|
7810 |
|
---|
7811 | if ( currCell.find( c ) == currCell.end() )
|
---|
7812 | return FALSE;
|
---|
7813 | QTextTableCell *cell = cells.at( *currCell.find( c ) );
|
---|
7814 | if ( !cell )
|
---|
7815 | return FALSE;
|
---|
7816 | doc = cell->richText();
|
---|
7817 | parag = doc->firstParagraph();
|
---|
7818 | idx = 0;
|
---|
7819 | ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
|
---|
7820 | oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
|
---|
7821 | return TRUE;
|
---|
7822 | }
|
---|
7823 |
|
---|
7824 | bool QTextTable::prev( QTextCursor *c, QTextDocument *&doc, QTextParagraph *¶g, int &idx, int &ox, int &oy )
|
---|
7825 | {
|
---|
7826 | int cc = -1;
|
---|
7827 | if ( currCell.find( c ) != currCell.end() )
|
---|
7828 | cc = *currCell.find( c );
|
---|
7829 | if ( cc > (int)cells.count() - 1 || cc < 0 )
|
---|
7830 | cc = cells.count();
|
---|
7831 | currCell.remove( c );
|
---|
7832 | currCell.insert( c, --cc );
|
---|
7833 | if ( cc < 0 ) {
|
---|
7834 | currCell.insert( c, 0 );
|
---|
7835 | QTextCustomItem::prev( c, doc, parag, idx, ox, oy );
|
---|
7836 | QTextTableCell *cell = cells.first();
|
---|
7837 | if ( !cell )
|
---|
7838 | return FALSE;
|
---|
7839 | doc = cell->richText();
|
---|
7840 | idx = -1;
|
---|
7841 | return TRUE;
|
---|
7842 | }
|
---|
7843 |
|
---|
7844 | if ( currCell.find( c ) == currCell.end() )
|
---|
7845 | return FALSE;
|
---|
7846 | QTextTableCell *cell = cells.at( *currCell.find( c ) );
|
---|
7847 | if ( !cell )
|
---|
7848 | return FALSE;
|
---|
7849 | doc = cell->richText();
|
---|
7850 | parag = doc->lastParagraph();
|
---|
7851 | idx = parag->length() - 1;
|
---|
7852 | ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
|
---|
7853 | oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
|
---|
7854 | return TRUE;
|
---|
7855 | }
|
---|
7856 |
|
---|
7857 | bool QTextTable::down( QTextCursor *c, QTextDocument *&doc, QTextParagraph *¶g, int &idx, int &ox, int &oy )
|
---|
7858 | {
|
---|
7859 | if ( currCell.find( c ) == currCell.end() )
|
---|
7860 | return FALSE;
|
---|
7861 | QTextTableCell *cell = cells.at( *currCell.find( c ) );
|
---|
7862 | if ( cell->row_ == layout->numRows() - 1 ) {
|
---|
7863 | currCell.insert( c, 0 );
|
---|
7864 | QTextCustomItem::down( c, doc, parag, idx, ox, oy );
|
---|
7865 | QTextTableCell *cell = cells.first();
|
---|
7866 | if ( !cell )
|
---|
7867 | return FALSE;
|
---|
7868 | doc = cell->richText();
|
---|
7869 | idx = -1;
|
---|
7870 | return TRUE;
|
---|
7871 | }
|
---|
7872 |
|
---|
7873 | int oldRow = cell->row_;
|
---|
7874 | int oldCol = cell->col_;
|
---|
7875 | if ( currCell.find( c ) == currCell.end() )
|
---|
7876 | return FALSE;
|
---|
7877 | int cc = *currCell.find( c );
|
---|
7878 | for ( int i = cc; i < (int)cells.count(); ++i ) {
|
---|
7879 | cell = cells.at( i );
|
---|
7880 | if ( cell->row_ > oldRow && cell->col_ == oldCol ) {
|
---|
7881 | currCell.insert( c, i );
|
---|
7882 | break;
|
---|
7883 | }
|
---|
7884 | }
|
---|
7885 | doc = cell->richText();
|
---|
7886 | if ( !cell )
|
---|
7887 | return FALSE;
|
---|
7888 | parag = doc->firstParagraph();
|
---|
7889 | idx = 0;
|
---|
7890 | ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
|
---|
7891 | oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
|
---|
7892 | return TRUE;
|
---|
7893 | }
|
---|
7894 |
|
---|
7895 | bool QTextTable::up( QTextCursor *c, QTextDocument *&doc, QTextParagraph *¶g, int &idx, int &ox, int &oy )
|
---|
7896 | {
|
---|
7897 | if ( currCell.find( c ) == currCell.end() )
|
---|
7898 | return FALSE;
|
---|
7899 | QTextTableCell *cell = cells.at( *currCell.find( c ) );
|
---|
7900 | if ( cell->row_ == 0 ) {
|
---|
7901 | currCell.insert( c, 0 );
|
---|
7902 | QTextCustomItem::up( c, doc, parag, idx, ox, oy );
|
---|
7903 | QTextTableCell *cell = cells.first();
|
---|
7904 | if ( !cell )
|
---|
7905 | return FALSE;
|
---|
7906 | doc = cell->richText();
|
---|
7907 | idx = -1;
|
---|
7908 | return TRUE;
|
---|
7909 | }
|
---|
7910 |
|
---|
7911 | int oldRow = cell->row_;
|
---|
7912 | int oldCol = cell->col_;
|
---|
7913 | if ( currCell.find( c ) == currCell.end() )
|
---|
7914 | return FALSE;
|
---|
7915 | int cc = *currCell.find( c );
|
---|
7916 | for ( int i = cc; i >= 0; --i ) {
|
---|
7917 | cell = cells.at( i );
|
---|
7918 | if ( cell->row_ < oldRow && cell->col_ == oldCol ) {
|
---|
7919 | currCell.insert( c, i );
|
---|
7920 | break;
|
---|
7921 | }
|
---|
7922 | }
|
---|
7923 | doc = cell->richText();
|
---|
7924 | if ( !cell )
|
---|
7925 | return FALSE;
|
---|
7926 | parag = doc->lastParagraph();
|
---|
7927 | idx = parag->length() - 1;
|
---|
7928 | ox += cell->geometry().x() + cell->horizontalAlignmentOffset() + outerborder + parent->x();
|
---|
7929 | oy += cell->geometry().y() + cell->verticalAlignmentOffset() + outerborder;
|
---|
7930 | return TRUE;
|
---|
7931 | }
|
---|
7932 |
|
---|
7933 | QTextTableCell::QTextTableCell( QTextTable* table,
|
---|
7934 | int row, int column,
|
---|
7935 | const QMap<QString, QString> &attr,
|
---|
7936 | const QStyleSheetItem* /*style*/, // ### use them
|
---|
7937 | const QTextFormat& fmt, const QString& context,
|
---|
7938 | QMimeSourceFactory &factory, QStyleSheet *sheet,
|
---|
7939 | const QString& doc)
|
---|
7940 | {
|
---|
7941 | cached_width = -1;
|
---|
7942 | cached_sizehint = -1;
|
---|
7943 |
|
---|
7944 | maxw = QWIDGETSIZE_MAX;
|
---|
7945 | minw = 0;
|
---|
7946 |
|
---|
7947 | parent = table;
|
---|
7948 | row_ = row;
|
---|
7949 | col_ = column;
|
---|
7950 | stretch_ = 0;
|
---|
7951 | richtext = new QTextDocument( table->parent );
|
---|
7952 | richtext->formatCollection()->setPaintDevice( table->parent->formatCollection()->paintDevice() );
|
---|
7953 | richtext->bodyText = fmt.color();
|
---|
7954 | richtext->setTableCell( this );
|
---|
7955 | QString a = *attr.find( "align" );
|
---|
7956 | if ( !a.isEmpty() ) {
|
---|
7957 | a = a.lower();
|
---|
7958 | if ( a == "left" )
|
---|
7959 | richtext->setAlignment( Qt::AlignLeft );
|
---|
7960 | else if ( a == "center" )
|
---|
7961 | richtext->setAlignment( Qt::AlignHCenter );
|
---|
7962 | else if ( a == "right" )
|
---|
7963 | richtext->setAlignment( Qt::AlignRight );
|
---|
7964 | }
|
---|
7965 | align = 0;
|
---|
7966 | QString va = *attr.find( "valign" );
|
---|
7967 | if ( !va.isEmpty() ) {
|
---|
7968 | va = va.lower();
|
---|
7969 | if ( va == "center" )
|
---|
7970 | align |= Qt::AlignVCenter;
|
---|
7971 | else if ( va == "bottom" )
|
---|
7972 | align |= Qt::AlignBottom;
|
---|
7973 | }
|
---|
7974 | richtext->setFormatter( table->parent->formatter() );
|
---|
7975 | richtext->setUseFormatCollection( table->parent->useFormatCollection() );
|
---|
7976 | richtext->setMimeSourceFactory( &factory );
|
---|
7977 | richtext->setStyleSheet( sheet );
|
---|
7978 | richtext->setDefaultFormat( fmt.font(), fmt.color() );
|
---|
7979 | richtext->setRichText( doc, context );
|
---|
7980 | rowspan_ = 1;
|
---|
7981 | colspan_ = 1;
|
---|
7982 | if ( attr.contains("colspan") )
|
---|
7983 | colspan_ = attr["colspan"].toInt();
|
---|
7984 | if ( attr.contains("rowspan") )
|
---|
7985 | rowspan_ = attr["rowspan"].toInt();
|
---|
7986 |
|
---|
7987 | background = 0;
|
---|
7988 | if ( attr.contains("bgcolor") ) {
|
---|
7989 | background = new QBrush(QColor( attr["bgcolor"] ));
|
---|
7990 | }
|
---|
7991 |
|
---|
7992 |
|
---|
7993 | hasFixedWidth = FALSE;
|
---|
7994 | if ( attr.contains("width") ) {
|
---|
7995 | bool b;
|
---|
7996 | QString s( attr["width"] );
|
---|
7997 | int w = s.toInt( &b );
|
---|
7998 | if ( b ) {
|
---|
7999 | maxw = w;
|
---|
8000 | minw = maxw;
|
---|
8001 | hasFixedWidth = TRUE;
|
---|
8002 | } else {
|
---|
8003 | s = s.stripWhiteSpace();
|
---|
8004 | if ( s.length() > 1 && s[ (int)s.length()-1 ] == '%' )
|
---|
8005 | stretch_ = s.left( s.length()-1).toInt();
|
---|
8006 | }
|
---|
8007 | }
|
---|
8008 |
|
---|
8009 | attributes = attr;
|
---|
8010 |
|
---|
8011 | parent->addCell( this );
|
---|
8012 | }
|
---|
8013 |
|
---|
8014 | QTextTableCell::~QTextTableCell()
|
---|
8015 | {
|
---|
8016 | delete background;
|
---|
8017 | background = 0;
|
---|
8018 | delete richtext;
|
---|
8019 | richtext = 0;
|
---|
8020 | }
|
---|
8021 |
|
---|
8022 | QSize QTextTableCell::sizeHint() const
|
---|
8023 | {
|
---|
8024 | int extra = 2 * ( parent->innerborder + parent->cellpadding + border_tolerance);
|
---|
8025 | int used = richtext->widthUsed() + extra;
|
---|
8026 |
|
---|
8027 | if (stretch_ ) {
|
---|
8028 | int w = parent->width * stretch_ / 100 - 2*parent->cellspacing - 2*parent->cellpadding;
|
---|
8029 | return QSize( QMIN( w, maxw ), 0 ).expandedTo( minimumSize() );
|
---|
8030 | }
|
---|
8031 |
|
---|
8032 | return QSize( used, 0 ).expandedTo( minimumSize() );
|
---|
8033 | }
|
---|
8034 |
|
---|
8035 | QSize QTextTableCell::minimumSize() const
|
---|
8036 | {
|
---|
8037 | int extra = 2 * ( parent->innerborder + parent->cellpadding + border_tolerance);
|
---|
8038 | return QSize( QMAX( richtext->minimumWidth() + extra, minw), 0 );
|
---|
8039 | }
|
---|
8040 |
|
---|
8041 | QSize QTextTableCell::maximumSize() const
|
---|
8042 | {
|
---|
8043 | return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
|
---|
8044 | }
|
---|
8045 |
|
---|
8046 | QSizePolicy::ExpandData QTextTableCell::expanding() const
|
---|
8047 | {
|
---|
8048 | return QSizePolicy::BothDirections;
|
---|
8049 | }
|
---|
8050 |
|
---|
8051 | bool QTextTableCell::isEmpty() const
|
---|
8052 | {
|
---|
8053 | return FALSE;
|
---|
8054 | }
|
---|
8055 | void QTextTableCell::setGeometry( const QRect& r )
|
---|
8056 | {
|
---|
8057 | int extra = 2 * ( parent->innerborder + parent->cellpadding );
|
---|
8058 | if ( r.width() != cached_width )
|
---|
8059 | richtext->doLayout( QTextFormat::painter(), r.width() - extra );
|
---|
8060 | cached_width = r.width();
|
---|
8061 | geom = r;
|
---|
8062 | }
|
---|
8063 |
|
---|
8064 | QRect QTextTableCell::geometry() const
|
---|
8065 | {
|
---|
8066 | return geom;
|
---|
8067 | }
|
---|
8068 |
|
---|
8069 | bool QTextTableCell::hasHeightForWidth() const
|
---|
8070 | {
|
---|
8071 | return TRUE;
|
---|
8072 | }
|
---|
8073 |
|
---|
8074 | int QTextTableCell::heightForWidth( int w ) const
|
---|
8075 | {
|
---|
8076 | int extra = 2 * ( parent->innerborder + parent->cellpadding );
|
---|
8077 | w = QMAX( minw, w );
|
---|
8078 |
|
---|
8079 | if ( cached_width != w ) {
|
---|
8080 | QTextTableCell* that = (QTextTableCell*) this;
|
---|
8081 | that->richtext->doLayout( QTextFormat::painter(), w - extra );
|
---|
8082 | that->cached_width = w;
|
---|
8083 | }
|
---|
8084 | return richtext->height() + extra;
|
---|
8085 | }
|
---|
8086 |
|
---|
8087 | void QTextTableCell::adjustToPainter( QPainter* p )
|
---|
8088 | {
|
---|
8089 | QTextParagraph *parag = richtext->firstParagraph();
|
---|
8090 | while ( parag ) {
|
---|
8091 | parag->adjustToPainter( p );
|
---|
8092 | parag = parag->next();
|
---|
8093 | }
|
---|
8094 | }
|
---|
8095 |
|
---|
8096 | int QTextTableCell::horizontalAlignmentOffset() const
|
---|
8097 | {
|
---|
8098 | return parent->cellpadding;
|
---|
8099 | }
|
---|
8100 |
|
---|
8101 | int QTextTableCell::verticalAlignmentOffset() const
|
---|
8102 | {
|
---|
8103 | if ( (align & Qt::AlignVCenter ) == Qt::AlignVCenter )
|
---|
8104 | return ( geom.height() - richtext->height() ) / 2;
|
---|
8105 | else if ( ( align & Qt::AlignBottom ) == Qt::AlignBottom )
|
---|
8106 | return geom.height() - parent->cellpadding - richtext->height() ;
|
---|
8107 | return parent->cellpadding;
|
---|
8108 | }
|
---|
8109 |
|
---|
8110 | void QTextTableCell::draw( QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool )
|
---|
8111 | {
|
---|
8112 | if ( cached_width != geom.width() ) {
|
---|
8113 | int extra = 2 * ( parent->innerborder + parent->cellpadding );
|
---|
8114 | richtext->doLayout( p, geom.width() - extra );
|
---|
8115 | cached_width = geom.width();
|
---|
8116 | }
|
---|
8117 | QColorGroup g( cg );
|
---|
8118 | if ( background )
|
---|
8119 | g.setBrush( QColorGroup::Base, *background );
|
---|
8120 | else if ( richtext->paper() )
|
---|
8121 | g.setBrush( QColorGroup::Base, *richtext->paper() );
|
---|
8122 |
|
---|
8123 | p->save();
|
---|
8124 | p->translate( x + geom.x(), y + geom.y() );
|
---|
8125 | if ( background )
|
---|
8126 | p->fillRect( 0, 0, geom.width(), geom.height(), *background );
|
---|
8127 | else if ( richtext->paper() )
|
---|
8128 | p->fillRect( 0, 0, geom.width(), geom.height(), *richtext->paper() );
|
---|
8129 |
|
---|
8130 | p->translate( horizontalAlignmentOffset(), verticalAlignmentOffset() );
|
---|
8131 |
|
---|
8132 | QRegion r;
|
---|
8133 | if ( cx >= 0 && cy >= 0 )
|
---|
8134 | richtext->draw( p, cx - ( x + horizontalAlignmentOffset() + geom.x() ),
|
---|
8135 | cy - ( y + geom.y() + verticalAlignmentOffset() ),
|
---|
8136 | cw, ch, g, FALSE, FALSE, 0 );
|
---|
8137 | else
|
---|
8138 | richtext->draw( p, -1, -1, -1, -1, g, FALSE, FALSE, 0 );
|
---|
8139 |
|
---|
8140 | p->restore();
|
---|
8141 | }
|
---|
8142 | #endif
|
---|
8143 |
|
---|
8144 | #endif //QT_NO_RICHTEXT
|
---|