source: trunk/src/gui/text/qtextformat.cpp@ 180

Last change on this file since 180 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 77.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qtextformat.h"
43#include "qtextformat_p.h"
44
45#include <qvariant.h>
46#include <qdatastream.h>
47#include <qdebug.h>
48#include <qmap.h>
49#include <qhash.h>
50
51QT_BEGIN_NAMESPACE
52
53/*!
54 \class QTextLength
55 \reentrant
56
57 \brief The QTextLength class encapsulates the different types of length
58 used in a QTextDocument.
59
60 \ingroup text
61
62 When we specify a value for the length of an element in a text document,
63 we often need to provide some other information so that the length is
64 used in the way we expect. For example, when we specify a table width,
65 the value can represent a fixed number of pixels, or it can be a percentage
66 value. This information changes both the meaning of the value and the way
67 it is used.
68
69 Generally, this class is used to specify table widths. These can be
70 specified either as a fixed amount of pixels, as a percentage of the
71 containing frame's width, or by a variable width that allows it to take
72 up just the space it requires.
73
74 \sa QTextTable
75*/
76
77/*!
78 \fn explicit QTextLength::QTextLength()
79
80 Constructs a new length object which represents a variable size.
81*/
82
83/*!
84 \fn QTextLength::QTextLength(Type type, qreal value)
85
86 Constructs a new length object of the given \a type and \a value.
87*/
88
89/*!
90 \fn Type QTextLength::type() const
91
92 Returns the type of length.
93
94 \sa QTextLength::Type
95*/
96
97/*!
98 \fn qreal QTextLength::value(qreal maximumLength) const
99
100 Returns the effective length, constrained by the type of the length object
101 and the specified \a maximumLength.
102
103 \sa type()
104*/
105
106/*!
107 \fn qreal QTextLength::rawValue() const
108
109 Returns the constraint value that is specific for the type of the length.
110 If the length is QTextLength::PercentageLength then the raw value is in
111 percent, in the range of 0 to 100. If the length is QTextLength::FixedLength
112 then that fixed amount is returned. For variable lengths, zero is returned.
113*/
114
115/*!
116 \fn bool QTextLength::operator==(const QTextLength &other) const
117
118 Returns true if this text length is the same as the \a other text
119 length.
120*/
121
122/*!
123 \fn bool QTextLength::operator!=(const QTextLength &other) const
124
125 Returns true if this text length is different from the \a other text
126 length.
127*/
128
129/*!
130 \enum QTextLength::Type
131
132 \value VariableLength
133 \value FixedLength
134 \value PercentageLength
135*/
136
137/*!
138 Returns the text length as a QVariant
139*/
140QTextLength::operator QVariant() const
141{
142 return QVariant(QVariant::TextLength, this);
143}
144
145QDataStream &operator<<(QDataStream &stream, const QTextLength &length)
146{
147 return stream << qint32(length.lengthType) << double(length.fixedValueOrPercentage);
148}
149
150QDataStream &operator>>(QDataStream &stream, QTextLength &length)
151{
152 qint32 type;
153 double fixedValueOrPercentage;
154 stream >> type >> fixedValueOrPercentage;
155 length.fixedValueOrPercentage = fixedValueOrPercentage;
156 length.lengthType = QTextLength::Type(type);
157 return stream;
158}
159
160class QTextFormatPrivate : public QSharedData
161{
162public:
163 QTextFormatPrivate() : hashDirty(true), fontDirty(true), hashValue(0) {}
164
165 struct Property
166 {
167 inline Property(qint32 k, const QVariant &v) : key(k), value(v) {}
168 inline Property() {}
169
170 qint32 key;
171 QVariant value;
172
173 inline bool operator==(const Property &other) const
174 { return key == other.key && value == other.value; }
175 inline bool operator!=(const Property &other) const
176 { return key != other.key || value != other.value; }
177 };
178
179 inline uint hash() const
180 {
181 if (!hashDirty)
182 return hashValue;
183 return recalcHash();
184 }
185
186 inline bool operator==(const QTextFormatPrivate &rhs) const {
187 if (hash() != rhs.hash())
188 return false;
189
190 return props == rhs.props;
191 }
192
193 inline void insertProperty(qint32 key, const QVariant &value)
194 {
195 hashDirty = true;
196 if (key >= QTextFormat::FirstFontProperty && key <= QTextFormat::LastFontProperty)
197 fontDirty = true;
198 for (int i = 0; i < props.count(); ++i)
199 if (props.at(i).key == key) {
200 props[i].value = value;
201 return;
202 }
203 props.append(Property(key, value));
204 }
205
206 inline void clearProperty(qint32 key)
207 {
208 for (int i = 0; i < props.count(); ++i)
209 if (props.at(i).key == key) {
210 hashDirty = true;
211 if (key >= QTextFormat::FirstFontProperty && key <= QTextFormat::LastFontProperty)
212 fontDirty = true;
213 props.remove(i);
214 return;
215 }
216 }
217
218 inline int propertyIndex(qint32 key) const
219 {
220 for (int i = 0; i < props.count(); ++i)
221 if (props.at(i).key == key)
222 return i;
223 return -1;
224 }
225
226 inline QVariant property(qint32 key) const
227 {
228 const int idx = propertyIndex(key);
229 if (idx < 0)
230 return QVariant();
231 return props.at(idx).value;
232 }
233
234 inline bool hasProperty(qint32 key) const
235 { return propertyIndex(key) != -1; }
236
237 void resolveFont(const QFont &defaultFont);
238
239 inline const QFont &font() const {
240 if (fontDirty)
241 recalcFont();
242 return fnt;
243 }
244
245 QVector<Property> props;
246private:
247
248 uint recalcHash() const;
249 void recalcFont() const;
250
251 mutable bool hashDirty;
252 mutable bool fontDirty;
253 mutable uint hashValue;
254 mutable QFont fnt;
255
256 friend QDataStream &operator<<(QDataStream &, const QTextFormat &);
257 friend QDataStream &operator>>(QDataStream &, QTextFormat &);
258};
259
260static uint variantHash(const QVariant &variant)
261{
262 switch (variant.type()) {
263 case QVariant::Invalid: return 0;
264 case QVariant::Bool: return variant.toBool();
265 case QVariant::Int: return variant.toInt();
266 case QVariant::Double: return static_cast<int>(variant.toDouble());
267 case QVariant::String: return qHash(variant.toString());
268 case QVariant::Color: return qHash(qvariant_cast<QColor>(variant).rgb());
269 default: break;
270 }
271 return qHash(variant.typeName());
272}
273
274uint QTextFormatPrivate::recalcHash() const
275{
276 hashValue = 0;
277 for (QVector<Property>::ConstIterator it = props.constBegin(); it != props.constEnd(); ++it)
278 hashValue += (it->key << 16) + variantHash(it->value);
279
280 hashDirty = false;
281
282 return hashValue;
283}
284
285void QTextFormatPrivate::resolveFont(const QFont &defaultFont)
286{
287 recalcFont();
288 const uint oldMask = fnt.resolve();
289 fnt = fnt.resolve(defaultFont);
290
291 if (hasProperty(QTextFormat::FontSizeAdjustment)) {
292 const qreal scaleFactors[7] = {qreal(0.7), qreal(0.8), qreal(1.0), qreal(1.2), qreal(1.5), qreal(2), qreal(2.4)};
293
294 const int htmlFontSize = qBound(0, property(QTextFormat::FontSizeAdjustment).toInt() + 3 - 1, 6);
295
296
297 if (defaultFont.pointSize() <= 0) {
298 qreal pixelSize = scaleFactors[htmlFontSize] * defaultFont.pixelSize();
299 fnt.setPixelSize(qRound(pixelSize));
300 } else {
301 qreal pointSize = scaleFactors[htmlFontSize] * defaultFont.pointSizeF();
302 fnt.setPointSizeF(pointSize);
303 }
304 }
305
306 fnt.resolve(oldMask);
307}
308
309void QTextFormatPrivate::recalcFont() const
310{
311 // update cached font as well
312 QFont f;
313
314 for (int i = 0; i < props.count(); ++i) {
315 switch (props.at(i).key) {
316 case QTextFormat::FontFamily:
317 f.setFamily(props.at(i).value.toString());
318 break;
319 case QTextFormat::FontPointSize:
320 f.setPointSizeF(props.at(i).value.toDouble());
321 break;
322 case QTextFormat::FontPixelSize:
323 f.setPixelSize(props.at(i).value.toInt());
324 break;
325 case QTextFormat::FontWeight: {
326 int weight = props.at(i).value.toInt();
327 if (weight == 0) weight = QFont::Normal;
328 f.setWeight(weight);
329 break; }
330 case QTextFormat::FontItalic:
331 f.setItalic(props.at(i).value.toBool());
332 break;
333 case QTextFormat::FontUnderline:
334 if (! hasProperty(QTextFormat::TextUnderlineStyle)) // don't use the old one if the new one is there.
335 f.setUnderline(props.at(i).value.toBool());
336 break;
337 case QTextFormat::TextUnderlineStyle:
338 f.setUnderline(static_cast<QTextCharFormat::UnderlineStyle>(props.at(i).value.toInt()) == QTextCharFormat::SingleUnderline);
339 break;
340 case QTextFormat::FontOverline:
341 f.setOverline(props.at(i).value.toBool());
342 break;
343 case QTextFormat::FontStrikeOut:
344 f.setStrikeOut(props.at(i).value.toBool());
345 break;
346 case QTextFormat::FontLetterSpacing:
347 f.setLetterSpacing(QFont::PercentageSpacing, props.at(i).value.toDouble());
348 break;
349 case QTextFormat::FontWordSpacing:
350 f.setWordSpacing(props.at(i).value.toDouble());
351 break;
352 case QTextFormat::FontCapitalization:
353 f.setCapitalization(static_cast<QFont::Capitalization> (props.at(i).value.toInt()));
354 break;
355 case QTextFormat::FontFixedPitch: {
356 const bool value = props.at(i).value.toBool();
357 if (f.fixedPitch() != value)
358 f.setFixedPitch(value);
359 break; }
360 case QTextFormat::FontStyleHint:
361 f.setStyleHint(static_cast<QFont::StyleHint>(props.at(i).value.toInt()), f.styleStrategy());
362 break;
363 case QTextFormat::FontStyleStrategy:
364 f.setStyleStrategy(static_cast<QFont::StyleStrategy>(props.at(i).value.toInt()));
365 break;
366 case QTextFormat::FontKerning:
367 f.setKerning(props.at(i).value.toBool());
368 break;
369 default:
370 break;
371 }
372 }
373 fnt = f;
374 fontDirty = false;
375}
376
377Q_GUI_EXPORT QDataStream &operator<<(QDataStream &stream, const QTextFormat &fmt)
378{
379 stream << fmt.format_type << fmt.properties();
380 return stream;
381}
382
383Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt)
384{
385 QMap<qint32, QVariant> properties;
386 stream >> fmt.format_type >> properties;
387
388 // QTextFormat's default constructor doesn't allocate the private structure, so
389 // we have to do this, in case fmt is a default constructed value.
390 if(!fmt.d)
391 fmt.d = new QTextFormatPrivate();
392
393 for (QMap<qint32, QVariant>::ConstIterator it = properties.constBegin();
394 it != properties.constEnd(); ++it)
395 fmt.d->insertProperty(it.key(), it.value());
396
397 return stream;
398}
399
400/*!
401 \class QTextFormat
402 \reentrant
403
404 \brief The QTextFormat class provides formatting information for a
405 QTextDocument.
406
407 \ingroup text
408 \ingroup shared
409
410 A QTextFormat is a generic class used for describing the format of
411 parts of a QTextDocument. The derived classes QTextCharFormat,
412 QTextBlockFormat, QTextListFormat, and QTextTableFormat are usually
413 more useful, and describe the formatting that is applied to
414 specific parts of the document.
415
416 A format has a \c FormatType which specifies the kinds of thing it
417 can format; e.g. a block of text, a list, a table, etc. A format
418 also has various properties (some specific to particular format
419 types), as described by the Property enum. Every property has a
420 corresponding Property.
421
422 The format type is given by type(), and the format can be tested
423 with isCharFormat(), isBlockFormat(), isListFormat(),
424 isTableFormat(), isFrameFormat(), and isImageFormat(). If the
425 type is determined, it can be retrieved with toCharFormat(),
426 toBlockFormat(), toListFormat(), toTableFormat(), toFrameFormat(),
427 and toImageFormat().
428
429 A format's properties can be set with the setProperty() functions,
430 and retrieved with boolProperty(), intProperty(), doubleProperty(),
431 and stringProperty() as appropriate. All the property IDs used in
432 the format can be retrieved with allPropertyIds(). One format can
433 be merged into another using merge().
434
435 A format's object index can be set with setObjectIndex(), and
436 retrieved with objectIndex(). These methods can be used to
437 associate the format with a QTextObject. It is used to represent
438 lists, frames, and tables inside the document.
439
440 \sa {Text Processing Classes}
441*/
442
443/*!
444 \enum QTextFormat::FormatType
445
446 \value InvalidFormat
447 \value BlockFormat
448 \value CharFormat
449 \value ListFormat
450 \value TableFormat
451 \value FrameFormat
452
453 \value UserFormat
454*/
455
456/*!
457 \enum QTextFormat::Property
458
459 \value ObjectIndex
460
461 Paragraph and character properties
462
463 \value CssFloat
464 \value LayoutDirection The layout direction of the text in the document
465 (Qt::LayoutDirection).
466
467 \value OutlinePen
468 \value ForegroundBrush
469 \value BackgroundBrush
470 \value BackgroundImageUrl
471
472 Paragraph properties
473
474 \value BlockAlignment
475 \value BlockTopMargin
476 \value BlockBottomMargin
477 \value BlockLeftMargin
478 \value BlockRightMargin
479 \value TextIndent
480 \value TabPositions Specifies the tab positions. The tab positions are structs of QTextOption::Tab which are stored in
481 a QList (internally, in a QList<QVariant>).
482 \value BlockIndent
483 \value BlockNonBreakableLines
484 \value BlockTrailingHorizontalRulerWidth
485
486 Character properties
487
488 \value FontFamily
489 \value FontPointSize
490 \value FontSizeAdjustment Specifies the change in size given to the fontsize already set using
491 FontPointSize or FontPixelSize.
492 \omitvalue FontSizeIncrement
493 \value FontWeight
494 \value FontItalic
495 \value FontUnderline \e{This property has been deprecated.} Use QTextFormat::TextUnderlineStyle instead.
496 \value FontOverline
497 \value FontStrikeOut
498 \value FontFixedPitch
499 \value FontPixelSize
500 \value FontCapitalization Specifies the capitalization type that is to be applied to the text.
501 \value FontLetterSpacing Changes the default spacing between individual letters in the font. The value is
502 specified in percentage, with 100 as the default value.
503 \value FontWordSpacing Changes the default spacing between individual words. A positive value increases the word spacing
504 by the corresponding pixels; a negative value decreases the spacing.
505 \value FontStyleHint Corresponds to the QFont::StyleHint property
506 \value FontStyleStrategy Corresponds to the QFont::StyleStrategy property
507 \value FontKerning Specifies whether the font has kerning turned on.
508
509 \omitvalue FirstFontProperty
510 \omitvalue LastFontProperty
511
512 \value TextUnderlineColor
513 \value TextVerticalAlignment
514 \value TextOutline
515 \value TextUnderlineStyle
516 \value TextToolTip Specifies the (optional) tool tip to be displayed for a fragment of text.
517
518 \value IsAnchor
519 \value AnchorHref
520 \value AnchorName
521 \value ObjectType
522
523 List properties
524
525 \value ListStyle
526 \value ListIndent
527
528 Table and frame properties
529
530 \value FrameBorder
531 \value FrameBorderBrush
532 \value FrameBorderStyle
533 \value FrameBottomMargin
534 \value FrameHeight
535 \value FrameLeftMargin
536 \value FrameMargin
537 \value FramePadding
538 \value FrameRightMargin
539 \value FrameTopMargin
540 \value FrameWidth
541 \value TableCellSpacing
542 \value TableCellPadding
543 \value TableColumns
544 \value TableColumnWidthConstraints
545 \value TableHeaderRowCount
546
547 Table cell properties
548
549 \value TableCellRowSpan
550 \value TableCellColumnSpan
551 \value TableCellLeftPadding
552 \value TableCellRightPadding
553 \value TableCellTopPadding
554 \value TableCellBottomPadding
555
556 Image properties
557
558 \value ImageName
559 \value ImageWidth
560 \value ImageHeight
561
562 Selection properties
563
564 \value FullWidthSelection When set on the characterFormat of a selection, the whole width of the text will be shown selected
565
566 Page break properties
567
568 \value PageBreakPolicy
569
570 \value UserProperty
571*/
572
573/*!
574 \enum QTextFormat::ObjectTypes
575
576 \value NoObject
577 \value ImageObject
578 \value TableObject
579 \value TableCellObject
580 \value UserObject The first object that can be used for application-specific purposes.
581*/
582
583/*!
584 \enum QTextFormat::PageBreakFlag
585 \since 4.2
586
587 \value PageBreak_Auto The page break is determined automatically depending on the
588 available space on the current page
589 \value PageBreak_AlwaysBefore The page is always broken before the paragraph/table
590 \value PageBreak_AlwaysAfter A new page is always started after the paragraph/table
591*/
592
593/*!
594 \fn bool QTextFormat::isValid() const
595
596 Returns true if the format is valid (i.e. is not
597 InvalidFormat); otherwise returns false.
598*/
599
600/*!
601 \fn bool QTextFormat::isCharFormat() const
602
603 Returns true if this text format is a \c CharFormat; otherwise
604 returns false.
605*/
606
607
608/*!
609 \fn bool QTextFormat::isBlockFormat() const
610
611 Returns true if this text format is a \c BlockFormat; otherwise
612 returns false.
613*/
614
615
616/*!
617 \fn bool QTextFormat::isListFormat() const
618
619 Returns true if this text format is a \c ListFormat; otherwise
620 returns false.
621*/
622
623
624/*!
625 \fn bool QTextFormat::isTableFormat() const
626
627 Returns true if this text format is a \c TableFormat; otherwise
628 returns false.
629*/
630
631
632/*!
633 \fn bool QTextFormat::isFrameFormat() const
634
635 Returns true if this text format is a \c FrameFormat; otherwise
636 returns false.
637*/
638
639
640/*!
641 \fn bool QTextFormat::isImageFormat() const
642
643 Returns true if this text format is an image format; otherwise
644 returns false.
645*/
646
647
648/*!
649 \fn bool QTextFormat::isTableCellFormat() const
650 \since 4.4
651
652 Returns true if this text format is a \c TableCellFormat; otherwise
653 returns false.
654*/
655
656
657/*!
658 Creates a new text format with an \c InvalidFormat.
659
660 \sa FormatType
661*/
662QTextFormat::QTextFormat()
663 : format_type(InvalidFormat)
664{
665}
666
667/*!
668 Creates a new text format of the given \a type.
669
670 \sa FormatType
671*/
672QTextFormat::QTextFormat(int type)
673 : format_type(type)
674{
675}
676
677
678/*!
679 \fn QTextFormat::QTextFormat(const QTextFormat &other)
680
681 Creates a new text format with the same attributes as the \a other
682 text format.
683*/
684QTextFormat::QTextFormat(const QTextFormat &rhs)
685 : d(rhs.d), format_type(rhs.format_type)
686{
687}
688
689/*!
690 \fn QTextFormat &QTextFormat::operator=(const QTextFormat &other)
691
692 Assigns the \a other text format to this text format, and returns a
693 reference to this text format.
694*/
695QTextFormat &QTextFormat::operator=(const QTextFormat &rhs)
696{
697 d = rhs.d;
698 format_type = rhs.format_type;
699 return *this;
700}
701
702/*!
703 Destroys this text format.
704*/
705QTextFormat::~QTextFormat()
706{
707}
708
709
710/*!
711 Returns the text format as a QVariant
712*/
713QTextFormat::operator QVariant() const
714{
715 return QVariant(QVariant::TextFormat, this);
716}
717
718/*!
719 Merges the \a other format with this format; where there are
720 conflicts the \a other format takes precedence.
721*/
722void QTextFormat::merge(const QTextFormat &other)
723{
724 if (format_type != other.format_type)
725 return;
726
727 if (!d) {
728 d = other.d;
729 return;
730 }
731
732 if (!other.d)
733 return;
734
735 QTextFormatPrivate *d = this->d;
736
737 const QVector<QTextFormatPrivate::Property> &otherProps = other.d->props;
738 d->props.reserve(d->props.size() + otherProps.size());
739 for (int i = 0; i < otherProps.count(); ++i) {
740 const QTextFormatPrivate::Property &p = otherProps.at(i);
741 d->insertProperty(p.key, p.value);
742 }
743}
744
745/*!
746 Returns the type of this format.
747
748 \sa FormatType
749*/
750int QTextFormat::type() const
751{
752 return format_type;
753}
754
755/*!
756 Returns this format as a block format.
757*/
758QTextBlockFormat QTextFormat::toBlockFormat() const
759{
760 return QTextBlockFormat(*this);
761}
762
763/*!
764 Returns this format as a character format.
765*/
766QTextCharFormat QTextFormat::toCharFormat() const
767{
768 return QTextCharFormat(*this);
769}
770
771/*!
772 Returns this format as a list format.
773*/
774QTextListFormat QTextFormat::toListFormat() const
775{
776 return QTextListFormat(*this);
777}
778
779/*!
780 Returns this format as a table format.
781*/
782QTextTableFormat QTextFormat::toTableFormat() const
783{
784 return QTextTableFormat(*this);
785}
786
787/*!
788 Returns this format as a frame format.
789*/
790QTextFrameFormat QTextFormat::toFrameFormat() const
791{
792 return QTextFrameFormat(*this);
793}
794
795/*!
796 Returns this format as an image format.
797*/
798QTextImageFormat QTextFormat::toImageFormat() const
799{
800 return QTextImageFormat(*this);
801}
802
803/*!
804 \since 4.4
805
806 Returns this format as a table cell format.
807*/
808QTextTableCellFormat QTextFormat::toTableCellFormat() const
809{
810 return QTextTableCellFormat(*this);
811}