|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtDeclarative module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "private/qdeclarativetextedit_p.h" |
|
43 #include "private/qdeclarativetextedit_p_p.h" |
|
44 |
|
45 #include "private/qdeclarativeevents_p_p.h" |
|
46 #include <private/qdeclarativeglobal_p.h> |
|
47 #include <qdeclarativeinfo.h> |
|
48 |
|
49 #include <QtCore/qmath.h> |
|
50 |
|
51 #include <QTextLayout> |
|
52 #include <QTextLine> |
|
53 #include <QTextDocument> |
|
54 #include <QGraphicsSceneMouseEvent> |
|
55 #include <QDebug> |
|
56 #include <QPainter> |
|
57 |
|
58 #include <private/qtextcontrol_p.h> |
|
59 |
|
60 QT_BEGIN_NAMESPACE |
|
61 |
|
62 /*! |
|
63 \qmlclass TextEdit QDeclarativeTextEdit |
|
64 \since 4.7 |
|
65 \brief The TextEdit item allows you to add editable formatted text to a scene. |
|
66 |
|
67 It can display both plain and rich text. For example: |
|
68 |
|
69 \qml |
|
70 TextEdit { |
|
71 id: edit |
|
72 text: "<b>Hello</b> <i>World!</i>" |
|
73 focus: true |
|
74 font.family: "Helvetica" |
|
75 font.pointSize: 20 |
|
76 color: "blue" |
|
77 width: 240 |
|
78 } |
|
79 \endqml |
|
80 |
|
81 \image declarative-textedit.gif |
|
82 |
|
83 \sa Text |
|
84 */ |
|
85 |
|
86 /*! |
|
87 \internal |
|
88 \class QDeclarativeTextEdit |
|
89 \qmlclass TextEdit |
|
90 |
|
91 \brief The QDeclarativeTextEdit class provides an editable formatted text item that you can add to a QDeclarativeView. |
|
92 |
|
93 It can display both plain and rich text. |
|
94 |
|
95 \image declarative-textedit.png |
|
96 |
|
97 A QDeclarativeTextEdit object can be instantiated in Qml using the tag \c <TextEdit>. |
|
98 */ |
|
99 |
|
100 /*! |
|
101 Constructs a new QDeclarativeTextEdit. |
|
102 */ |
|
103 QDeclarativeTextEdit::QDeclarativeTextEdit(QDeclarativeItem *parent) |
|
104 : QDeclarativePaintedItem(*(new QDeclarativeTextEditPrivate), parent) |
|
105 { |
|
106 Q_D(QDeclarativeTextEdit); |
|
107 d->init(); |
|
108 } |
|
109 |
|
110 QString QDeclarativeTextEdit::text() const |
|
111 { |
|
112 Q_D(const QDeclarativeTextEdit); |
|
113 |
|
114 if (d->richText) |
|
115 return d->document->toHtml(); |
|
116 else |
|
117 return d->document->toPlainText(); |
|
118 } |
|
119 |
|
120 /*! |
|
121 \qmlproperty string TextEdit::font.family |
|
122 |
|
123 Sets the family name of the font. |
|
124 |
|
125 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]". |
|
126 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen. |
|
127 If the family isn't available a family will be set using the font matching algorithm. |
|
128 */ |
|
129 |
|
130 /*! |
|
131 \qmlproperty bool TextEdit::font.bold |
|
132 |
|
133 Sets whether the font weight is bold. |
|
134 */ |
|
135 |
|
136 /*! |
|
137 \qmlproperty enumeration TextEdit::font.weight |
|
138 |
|
139 Sets the font's weight. |
|
140 |
|
141 The weight can be one of: |
|
142 \list |
|
143 \o Font.Light |
|
144 \o Font.Normal - the default |
|
145 \o Font.DemiBold |
|
146 \o Font.Bold |
|
147 \o Font.Black |
|
148 \endlist |
|
149 |
|
150 \qml |
|
151 TextEdit { text: "Hello"; font.weight: Font.DemiBold } |
|
152 \endqml |
|
153 */ |
|
154 |
|
155 /*! |
|
156 \qmlproperty bool TextEdit::font.italic |
|
157 |
|
158 Sets whether the font has an italic style. |
|
159 */ |
|
160 |
|
161 /*! |
|
162 \qmlproperty bool TextEdit::font.underline |
|
163 |
|
164 Sets whether the text is underlined. |
|
165 */ |
|
166 |
|
167 /*! |
|
168 \qmlproperty bool TextEdit::font.outline |
|
169 |
|
170 Sets whether the font has an outline style. |
|
171 */ |
|
172 |
|
173 /*! |
|
174 \qmlproperty bool TextEdit::font.strikeout |
|
175 |
|
176 Sets whether the font has a strikeout style. |
|
177 */ |
|
178 |
|
179 /*! |
|
180 \qmlproperty real TextEdit::font.pointSize |
|
181 |
|
182 Sets the font size in points. The point size must be greater than zero. |
|
183 */ |
|
184 |
|
185 /*! |
|
186 \qmlproperty int TextEdit::font.pixelSize |
|
187 |
|
188 Sets the font size in pixels. |
|
189 |
|
190 Using this function makes the font device dependent. |
|
191 Use \c pointSize to set the size of the font in a device independent manner. |
|
192 */ |
|
193 |
|
194 /*! |
|
195 \qmlproperty real TextEdit::font.letterSpacing |
|
196 |
|
197 Sets the letter spacing for the font. |
|
198 |
|
199 Letter spacing changes the default spacing between individual letters in the font. |
|
200 A value of 100 will keep the spacing unchanged; a value of 200 will enlarge the spacing after a character by |
|
201 the width of the character itself. |
|
202 */ |
|
203 |
|
204 /*! |
|
205 \qmlproperty real TextEdit::font.wordSpacing |
|
206 |
|
207 Sets the word spacing for the font. |
|
208 |
|
209 Word spacing changes the default spacing between individual words. |
|
210 A positive value increases the word spacing by a corresponding amount of pixels, |
|
211 while a negative value decreases the inter-word spacing accordingly. |
|
212 */ |
|
213 |
|
214 /*! |
|
215 \qmlproperty enumeration TextEdit::font.capitalization |
|
216 |
|
217 Sets the capitalization for the text. |
|
218 |
|
219 \list |
|
220 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied. |
|
221 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type. |
|
222 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type. |
|
223 \o Font.SmallCaps - This alters the text to be rendered in small-caps type. |
|
224 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character. |
|
225 \endlist |
|
226 |
|
227 \qml |
|
228 TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase } |
|
229 \endqml |
|
230 */ |
|
231 |
|
232 /*! |
|
233 \qmlproperty string TextEdit::text |
|
234 |
|
235 The text to display. If the text format is AutoText the text edit will |
|
236 automatically determine whether the text should be treated as |
|
237 rich text. This determination is made using Qt::mightBeRichText(). |
|
238 */ |
|
239 void QDeclarativeTextEdit::setText(const QString &text) |
|
240 { |
|
241 Q_D(QDeclarativeTextEdit); |
|
242 if (QDeclarativeTextEdit::text() == text) |
|
243 return; |
|
244 d->text = text; |
|
245 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text)); |
|
246 if (d->richText) { |
|
247 d->control->setHtml(text); |
|
248 } else { |
|
249 d->control->setPlainText(text); |
|
250 } |
|
251 q_textChanged(); |
|
252 } |
|
253 |
|
254 /*! |
|
255 \qmlproperty enumeration TextEdit::textFormat |
|
256 |
|
257 The way the text property should be displayed. |
|
258 |
|
259 \list |
|
260 \o TextEdit.AutoText |
|
261 \o TextEdit.PlainText |
|
262 \o TextEdit.RichText |
|
263 \o TextEdit.StyledText |
|
264 \endlist |
|
265 |
|
266 The default is TextEdit.AutoText. If the text format is TextEdit.AutoText the text edit |
|
267 will automatically determine whether the text should be treated as |
|
268 rich text. This determination is made using Qt::mightBeRichText(). |
|
269 |
|
270 \table |
|
271 \row |
|
272 \o |
|
273 \qml |
|
274 Column { |
|
275 TextEdit { |
|
276 font.pointSize: 24 |
|
277 text: "<b>Hello</b> <i>World!</i>" |
|
278 } |
|
279 TextEdit { |
|
280 font.pointSize: 24 |
|
281 textFormat: TextEdit.RichText |
|
282 text: "<b>Hello</b> <i>World!</i>" |
|
283 } |
|
284 TextEdit { |
|
285 font.pointSize: 24 |
|
286 textFormat: TextEdit.PlainText |
|
287 text: "<b>Hello</b> <i>World!</i>" |
|
288 } |
|
289 } |
|
290 \endqml |
|
291 \o \image declarative-textformat.png |
|
292 \endtable |
|
293 */ |
|
294 QDeclarativeTextEdit::TextFormat QDeclarativeTextEdit::textFormat() const |
|
295 { |
|
296 Q_D(const QDeclarativeTextEdit); |
|
297 return d->format; |
|
298 } |
|
299 |
|
300 void QDeclarativeTextEdit::setTextFormat(TextFormat format) |
|
301 { |
|
302 Q_D(QDeclarativeTextEdit); |
|
303 if (format == d->format) |
|
304 return; |
|
305 bool wasRich = d->richText; |
|
306 d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text)); |
|
307 |
|
308 if (wasRich && !d->richText) { |
|
309 d->control->setPlainText(d->text); |
|
310 updateSize(); |
|
311 } else if (!wasRich && d->richText) { |
|
312 d->control->setHtml(d->text); |
|
313 updateSize(); |
|
314 } |
|
315 d->format = format; |
|
316 emit textFormatChanged(d->format); |
|
317 } |
|
318 |
|
319 QFont QDeclarativeTextEdit::font() const |
|
320 { |
|
321 Q_D(const QDeclarativeTextEdit); |
|
322 return d->font; |
|
323 } |
|
324 |
|
325 void QDeclarativeTextEdit::setFont(const QFont &font) |
|
326 { |
|
327 Q_D(QDeclarativeTextEdit); |
|
328 d->font = font; |
|
329 |
|
330 clearCache(); |
|
331 d->document->setDefaultFont(d->font); |
|
332 if(d->cursor){ |
|
333 d->cursor->setHeight(QFontMetrics(d->font).height()); |
|
334 moveCursorDelegate(); |
|
335 } |
|
336 updateSize(); |
|
337 update(); |
|
338 } |
|
339 |
|
340 /*! |
|
341 \qmlproperty color TextEdit::color |
|
342 |
|
343 The text color. |
|
344 |
|
345 \qml |
|
346 // green text using hexadecimal notation |
|
347 TextEdit { color: "#00FF00"; ... } |
|
348 |
|
349 // steelblue text using SVG color name |
|
350 TextEdit { color: "steelblue"; ... } |
|
351 \endqml |
|
352 */ |
|
353 QColor QDeclarativeTextEdit::color() const |
|
354 { |
|
355 Q_D(const QDeclarativeTextEdit); |
|
356 return d->color; |
|
357 } |
|
358 |
|
359 void QDeclarativeTextEdit::setColor(const QColor &color) |
|
360 { |
|
361 Q_D(QDeclarativeTextEdit); |
|
362 if (d->color == color) |
|
363 return; |
|
364 |
|
365 clearCache(); |
|
366 d->color = color; |
|
367 QPalette pal = d->control->palette(); |
|
368 pal.setColor(QPalette::Text, color); |
|
369 d->control->setPalette(pal); |
|
370 update(); |
|
371 emit colorChanged(d->color); |
|
372 } |
|
373 |
|
374 /*! |
|
375 \qmlproperty color TextEdit::selectionColor |
|
376 |
|
377 The text highlight color, used behind selections. |
|
378 */ |
|
379 QColor QDeclarativeTextEdit::selectionColor() const |
|
380 { |
|
381 Q_D(const QDeclarativeTextEdit); |
|
382 return d->selectionColor; |
|
383 } |
|
384 |
|
385 void QDeclarativeTextEdit::setSelectionColor(const QColor &color) |
|
386 { |
|
387 Q_D(QDeclarativeTextEdit); |
|
388 if (d->selectionColor == color) |
|
389 return; |
|
390 |
|
391 clearCache(); |
|
392 d->selectionColor = color; |
|
393 QPalette pal = d->control->palette(); |
|
394 pal.setColor(QPalette::Highlight, color); |
|
395 d->control->setPalette(pal); |
|
396 update(); |
|
397 emit selectionColorChanged(d->selectionColor); |
|
398 } |
|
399 |
|
400 /*! |
|
401 \qmlproperty color TextEdit::selectedTextColor |
|
402 |
|
403 The selected text color, used in selections. |
|
404 */ |
|
405 QColor QDeclarativeTextEdit::selectedTextColor() const |
|
406 { |
|
407 Q_D(const QDeclarativeTextEdit); |
|
408 return d->selectedTextColor; |
|
409 } |
|
410 |
|
411 void QDeclarativeTextEdit::setSelectedTextColor(const QColor &color) |
|
412 { |
|
413 Q_D(QDeclarativeTextEdit); |
|
414 if (d->selectedTextColor == color) |
|
415 return; |
|
416 |
|
417 clearCache(); |
|
418 d->selectedTextColor = color; |
|
419 QPalette pal = d->control->palette(); |
|
420 pal.setColor(QPalette::HighlightedText, color); |
|
421 d->control->setPalette(pal); |
|
422 update(); |
|
423 emit selectedTextColorChanged(d->selectedTextColor); |
|
424 } |
|
425 |
|
426 /*! |
|
427 \qmlproperty enumeration TextEdit::horizontalAlignment |
|
428 \qmlproperty enumeration TextEdit::verticalAlignment |
|
429 |
|
430 Sets the horizontal and vertical alignment of the text within the TextEdit items |
|
431 width and height. By default, the text is top-left aligned. |
|
432 |
|
433 The valid values for \c horizontalAlignment are \c TextEdit.AlignLeft, \c TextEdit.AlignRight and |
|
434 \c TextEdit.AlignHCenter. The valid values for \c verticalAlignment are \c TextEdit.AlignTop, \c TextEdit.AlignBottom |
|
435 and \c TextEdit.AlignVCenter. |
|
436 */ |
|
437 QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const |
|
438 { |
|
439 Q_D(const QDeclarativeTextEdit); |
|
440 return d->hAlign; |
|
441 } |
|
442 |
|
443 void QDeclarativeTextEdit::setHAlign(QDeclarativeTextEdit::HAlignment alignment) |
|
444 { |
|
445 Q_D(QDeclarativeTextEdit); |
|
446 if (alignment == d->hAlign) |
|
447 return; |
|
448 d->hAlign = alignment; |
|
449 d->updateDefaultTextOption(); |
|
450 updateSize(); |
|
451 emit horizontalAlignmentChanged(d->hAlign); |
|
452 } |
|
453 |
|
454 QDeclarativeTextEdit::VAlignment QDeclarativeTextEdit::vAlign() const |
|
455 { |
|
456 Q_D(const QDeclarativeTextEdit); |
|
457 return d->vAlign; |
|
458 } |
|
459 |
|
460 void QDeclarativeTextEdit::setVAlign(QDeclarativeTextEdit::VAlignment alignment) |
|
461 { |
|
462 Q_D(QDeclarativeTextEdit); |
|
463 if (alignment == d->vAlign) |
|
464 return; |
|
465 d->vAlign = alignment; |
|
466 d->updateDefaultTextOption(); |
|
467 updateSize(); |
|
468 emit verticalAlignmentChanged(d->vAlign); |
|
469 } |
|
470 |
|
471 /*! |
|
472 \qmlproperty enumeration TextEdit::wrapMode |
|
473 |
|
474 Set this property to wrap the text to the TextEdit item's width. |
|
475 The text will only wrap if an explicit width has been set. |
|
476 |
|
477 \list |
|
478 \o TextEdit.NoWrap - no wrapping will be performed. |
|
479 \o TextEdit.WordWrap - wrapping is done on word boundaries. |
|
480 \o TextEdit.WrapAnywhere - Text can be wrapped at any point on a line, even if it occurs in the middle of a word. |
|
481 \o TextEdit.WrapAtWordBoundaryOrAnywhere - If possible, wrapping occurs at a word boundary; otherwise it |
|
482 will occur at the appropriate point on the line, even in the middle of a word. |
|
483 \endlist |
|
484 |
|
485 The default is TextEdit.NoWrap. |
|
486 */ |
|
487 QDeclarativeTextEdit::WrapMode QDeclarativeTextEdit::wrapMode() const |
|
488 { |
|
489 Q_D(const QDeclarativeTextEdit); |
|
490 return d->wrapMode; |
|
491 } |
|
492 |
|
493 void QDeclarativeTextEdit::setWrapMode(WrapMode mode) |
|
494 { |
|
495 Q_D(QDeclarativeTextEdit); |
|
496 if (mode == d->wrapMode) |
|
497 return; |
|
498 d->wrapMode = mode; |
|
499 d->updateDefaultTextOption(); |
|
500 updateSize(); |
|
501 emit wrapModeChanged(); |
|
502 } |
|
503 |
|
504 /*! |
|
505 \qmlproperty bool TextEdit::cursorVisible |
|
506 If true the text edit shows a cursor. |
|
507 |
|
508 This property is set and unset when the text edit gets focus, but it can also |
|
509 be set directly (useful, for example, if a KeyProxy might forward keys to it). |
|
510 */ |
|
511 bool QDeclarativeTextEdit::isCursorVisible() const |
|
512 { |
|
513 Q_D(const QDeclarativeTextEdit); |
|
514 return d->cursorVisible; |
|
515 } |
|
516 |
|
517 void QDeclarativeTextEdit::setCursorVisible(bool on) |
|
518 { |
|
519 Q_D(QDeclarativeTextEdit); |
|
520 if (d->cursorVisible == on) |
|
521 return; |
|
522 d->cursorVisible = on; |
|
523 QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut); |
|
524 if (!on && !d->persistentSelection) |
|
525 d->control->setCursorIsFocusIndicator(true); |
|
526 d->control->processEvent(&focusEvent, QPointF(0, -d->yoff)); |
|
527 emit cursorVisibleChanged(d->cursorVisible); |
|
528 } |
|
529 |
|
530 /*! |
|
531 \qmlproperty int TextEdit::cursorPosition |
|
532 The position of the cursor in the TextEdit. |
|
533 */ |
|
534 int QDeclarativeTextEdit::cursorPosition() const |
|
535 { |
|
536 Q_D(const QDeclarativeTextEdit); |
|
537 return d->control->textCursor().position(); |
|
538 } |
|
539 |
|
540 void QDeclarativeTextEdit::setCursorPosition(int pos) |
|
541 { |
|
542 Q_D(QDeclarativeTextEdit); |
|
543 QTextCursor cursor = d->control->textCursor(); |
|
544 if (cursor.position() == pos) |
|
545 return; |
|
546 cursor.setPosition(pos); |
|
547 d->control->setTextCursor(cursor); |
|
548 } |
|
549 |
|
550 /*! |
|
551 \qmlproperty Component TextEdit::cursorDelegate |
|
552 The delegate for the cursor in the TextEdit. |
|
553 |
|
554 If you set a cursorDelegate for a TextEdit, this delegate will be used for |
|
555 drawing the cursor instead of the standard cursor. An instance of the |
|
556 delegate will be created and managed by the text edit when a cursor is |
|
557 needed, and the x and y properties of delegate instance will be set so as |
|
558 to be one pixel before the top left of the current character. |
|
559 |
|
560 Note that the root item of the delegate component must be a QDeclarativeItem or |
|
561 QDeclarativeItem derived item. |
|
562 */ |
|
563 QDeclarativeComponent* QDeclarativeTextEdit::cursorDelegate() const |
|
564 { |
|
565 Q_D(const QDeclarativeTextEdit); |
|
566 return d->cursorComponent; |
|
567 } |
|
568 |
|
569 void QDeclarativeTextEdit::setCursorDelegate(QDeclarativeComponent* c) |
|
570 { |
|
571 Q_D(QDeclarativeTextEdit); |
|
572 if(d->cursorComponent){ |
|
573 if(d->cursor){ |
|
574 disconnect(d->control, SIGNAL(cursorPositionChanged()), |
|
575 this, SLOT(moveCursorDelegate())); |
|
576 d->control->setCursorWidth(-1); |
|
577 dirtyCache(cursorRect()); |
|
578 delete d->cursor; |
|
579 d->cursor = 0; |
|
580 } |
|
581 } |
|
582 d->cursorComponent = c; |
|
583 if(c && c->isReady()){ |
|
584 loadCursorDelegate(); |
|
585 }else{ |
|
586 if(c) |
|
587 connect(c, SIGNAL(statusChanged()), |
|
588 this, SLOT(loadCursorDelegate())); |
|
589 } |
|
590 |
|
591 emit cursorDelegateChanged(); |
|
592 } |
|
593 |
|
594 void QDeclarativeTextEdit::loadCursorDelegate() |
|
595 { |
|
596 Q_D(QDeclarativeTextEdit); |
|
597 if(d->cursorComponent->isLoading()) |
|
598 return; |
|
599 d->cursor = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create(qmlContext(this))); |
|
600 if(d->cursor){ |
|
601 connect(d->control, SIGNAL(cursorPositionChanged()), |
|
602 this, SLOT(moveCursorDelegate())); |
|
603 d->control->setCursorWidth(0); |
|
604 dirtyCache(cursorRect()); |
|
605 QDeclarative_setParent_noEvent(d->cursor, this); |
|
606 d->cursor->setParentItem(this); |
|
607 d->cursor->setHeight(QFontMetrics(d->font).height()); |
|
608 moveCursorDelegate(); |
|
609 }else{ |
|
610 qmlInfo(this) << "Error loading cursor delegate."; |
|
611 } |
|
612 } |
|
613 |
|
614 /*! |
|
615 \qmlproperty int TextEdit::selectionStart |
|
616 |
|
617 The cursor position before the first character in the current selection. |
|
618 Setting this and selectionEnd allows you to specify a selection in the |
|
619 text edit. |
|
620 |
|
621 Note that if selectionStart == selectionEnd then there is no current |
|
622 selection. If you attempt to set selectionStart to a value outside of |
|
623 the current text, selectionStart will not be changed. |
|
624 |
|
625 \sa selectionEnd, cursorPosition, selectedText |
|
626 */ |
|
627 int QDeclarativeTextEdit::selectionStart() const |
|
628 { |
|
629 Q_D(const QDeclarativeTextEdit); |
|
630 return d->control->textCursor().selectionStart(); |
|
631 } |
|
632 |
|
633 void QDeclarativeTextEdit::setSelectionStart(int s) |
|
634 { |
|
635 Q_D(QDeclarativeTextEdit); |
|
636 if(d->lastSelectionStart == s || s < 0 || s > text().length()) |
|
637 return; |
|
638 d->lastSelectionStart = s; |
|
639 d->updateSelection();// Will emit the relevant signals |
|
640 } |
|
641 |
|
642 /*! |
|
643 \qmlproperty int TextEdit::selectionEnd |
|
644 |
|
645 The cursor position after the last character in the current selection. |
|
646 Setting this and selectionStart allows you to specify a selection in the |
|
647 text edit. |
|
648 |
|
649 Note that if selectionStart == selectionEnd then there is no current |
|
650 selection. If you attempt to set selectionEnd to a value outside of |
|
651 the current text, selectionEnd will not be changed. |
|
652 |
|
653 \sa selectionStart, cursorPosition, selectedText |
|
654 */ |
|
655 int QDeclarativeTextEdit::selectionEnd() const |
|
656 { |
|
657 Q_D(const QDeclarativeTextEdit); |
|
658 return d->control->textCursor().selectionEnd(); |
|
659 } |
|
660 |
|
661 void QDeclarativeTextEdit::setSelectionEnd(int s) |
|
662 { |
|
663 Q_D(QDeclarativeTextEdit); |
|
664 if(d->lastSelectionEnd == s || s < 0 || s > text().length()) |
|
665 return; |
|
666 d->lastSelectionEnd = s; |
|
667 d->updateSelection();// Will emit the relevant signals |
|
668 } |
|
669 |
|
670 /*! |
|
671 \qmlproperty string TextEdit::selectedText |
|
672 |
|
673 This read-only property provides the text currently selected in the |
|
674 text edit. |
|
675 |
|
676 It is equivalent to the following snippet, but is faster and easier |
|
677 to use. |
|
678 \code |
|
679 //myTextEdit is the id of the TextEdit |
|
680 myTextEdit.text.toString().substring(myTextEdit.selectionStart, |
|
681 myTextEdit.selectionEnd); |
|
682 \endcode |
|
683 */ |
|
684 QString QDeclarativeTextEdit::selectedText() const |
|
685 { |
|
686 Q_D(const QDeclarativeTextEdit); |
|
687 return d->control->textCursor().selectedText(); |
|
688 } |
|
689 |
|
690 /*! |
|
691 \qmlproperty bool TextEdit::focusOnPress |
|
692 |
|
693 Whether the TextEdit should gain focus on a mouse press. By default this is |
|
694 set to true. |
|
695 */ |
|
696 bool QDeclarativeTextEdit::focusOnPress() const |
|
697 { |
|
698 Q_D(const QDeclarativeTextEdit); |
|
699 return d->focusOnPress; |
|
700 } |
|
701 |
|
702 void QDeclarativeTextEdit::setFocusOnPress(bool on) |
|
703 { |
|
704 Q_D(QDeclarativeTextEdit); |
|
705 if (d->focusOnPress == on) |
|
706 return; |
|
707 d->focusOnPress = on; |
|
708 emit focusOnPressChanged(d->focusOnPress); |
|
709 } |
|
710 |
|
711 /*! |
|
712 \qmlproperty bool TextEdit::persistentSelection |
|
713 |
|
714 Whether the TextEdit should keep the selection visible when it loses focus to another |
|
715 item in the scene. By default this is set to true; |
|
716 */ |
|
717 bool QDeclarativeTextEdit::persistentSelection() const |
|
718 { |
|
719 Q_D(const QDeclarativeTextEdit); |
|
720 return d->persistentSelection; |
|
721 } |
|
722 |
|
723 void QDeclarativeTextEdit::setPersistentSelection(bool on) |
|
724 { |
|
725 Q_D(QDeclarativeTextEdit); |
|
726 if (d->persistentSelection == on) |
|
727 return; |
|
728 d->persistentSelection = on; |
|
729 emit persistentSelectionChanged(d->persistentSelection); |
|
730 } |
|
731 |
|
732 /* |
|
733 \qmlproperty real TextEdit::textMargin |
|
734 |
|
735 The margin, in pixels, around the text in the TextEdit. |
|
736 */ |
|
737 qreal QDeclarativeTextEdit::textMargin() const |
|
738 { |
|
739 Q_D(const QDeclarativeTextEdit); |
|
740 return d->textMargin; |
|
741 } |
|
742 |
|
743 void QDeclarativeTextEdit::setTextMargin(qreal margin) |
|
744 { |
|
745 Q_D(QDeclarativeTextEdit); |
|
746 if (d->textMargin == margin) |
|
747 return; |
|
748 d->textMargin = margin; |
|
749 d->document->setDocumentMargin(d->textMargin); |
|
750 emit textMarginChanged(d->textMargin); |
|
751 } |
|
752 |
|
753 void QDeclarativeTextEdit::geometryChanged(const QRectF &newGeometry, |
|
754 const QRectF &oldGeometry) |
|
755 { |
|
756 if (newGeometry.width() != oldGeometry.width()) |
|
757 updateSize(); |
|
758 QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry); |
|
759 } |
|
760 |
|
761 /*! |
|
762 Ensures any delayed caching or data loading the class |
|
763 needs to performed is complete. |
|
764 */ |
|
765 void QDeclarativeTextEdit::componentComplete() |
|
766 { |
|
767 Q_D(QDeclarativeTextEdit); |
|
768 QDeclarativePaintedItem::componentComplete(); |
|
769 if (d->dirty) { |
|
770 updateSize(); |
|
771 d->dirty = false; |
|
772 } |
|
773 } |
|
774 |
|
775 /*! |
|
776 \qmlproperty string TextEdit::selectByMouse |
|
777 |
|
778 Defaults to false. |
|
779 |
|
780 If true, the user can use the mouse to select text in some |
|
781 platform-specific way. Note that for some platforms this may |
|
782 not be an appropriate interaction (eg. may conflict with how |
|
783 the text needs to behave inside a Flickable. |
|
784 */ |
|
785 bool QDeclarativeTextEdit::selectByMouse() const |
|
786 { |
|
787 Q_D(const QDeclarativeTextEdit); |
|
788 return d->selectByMouse; |
|
789 } |
|
790 |
|
791 void QDeclarativeTextEdit::setSelectByMouse(bool on) |
|
792 { |
|
793 Q_D(QDeclarativeTextEdit); |
|
794 if (d->selectByMouse != on) { |
|
795 d->selectByMouse = on; |
|
796 emit selectByMouseChanged(on); |
|
797 } |
|
798 } |
|
799 |
|
800 |
|
801 |
|
802 /*! |
|
803 \qmlproperty bool TextEdit::readOnly |
|
804 |
|
805 Whether the user an interact with the TextEdit item. If this |
|
806 property is set to true the text cannot be edited by user interaction. |
|
807 |
|
808 By default this property is false. |
|
809 */ |
|
810 void QDeclarativeTextEdit::setReadOnly(bool r) |
|
811 { |
|
812 Q_D(QDeclarativeTextEdit); |
|
813 if (r == isReadOnly()) |
|
814 return; |
|
815 |
|
816 |
|
817 Qt::TextInteractionFlags flags = Qt::NoTextInteraction; |
|
818 if (r) { |
|
819 flags = Qt::TextSelectableByMouse; |
|
820 } else { |
|
821 flags = Qt::TextEditorInteraction; |
|
822 } |
|
823 d->control->setTextInteractionFlags(flags); |
|
824 if (!r) |
|
825 d->control->moveCursor(QTextCursor::End); |
|
826 |
|
827 emit readOnlyChanged(r); |
|
828 } |
|
829 |
|
830 bool QDeclarativeTextEdit::isReadOnly() const |
|
831 { |
|
832 Q_D(const QDeclarativeTextEdit); |
|
833 return !(d->control->textInteractionFlags() & Qt::TextEditable); |
|
834 } |
|
835 |
|
836 /*! |
|
837 Sets how the text edit should interact with user input to the given |
|
838 \a flags. |
|
839 */ |
|
840 void QDeclarativeTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags) |
|
841 { |
|
842 Q_D(QDeclarativeTextEdit); |
|
843 d->control->setTextInteractionFlags(flags); |
|
844 } |
|
845 |
|
846 /*! |
|
847 Returns the flags specifying how the text edit should interact |
|
848 with user input. |
|
849 */ |
|
850 Qt::TextInteractionFlags QDeclarativeTextEdit::textInteractionFlags() const |
|
851 { |
|
852 Q_D(const QDeclarativeTextEdit); |
|
853 return d->control->textInteractionFlags(); |
|
854 } |
|
855 |
|
856 /*! |
|
857 Returns the rectangle where the text cursor is rendered |
|
858 within the text edit. |
|
859 */ |
|
860 QRect QDeclarativeTextEdit::cursorRect() const |
|
861 { |
|
862 Q_D(const QDeclarativeTextEdit); |
|
863 return d->control->cursorRect().toRect().translated(0,-d->yoff); |
|
864 } |
|
865 |
|
866 |
|
867 /*! |
|
868 \overload |
|
869 Handles the given \a event. |
|
870 */ |
|
871 bool QDeclarativeTextEdit::event(QEvent *event) |
|
872 { |
|
873 Q_D(QDeclarativeTextEdit); |
|
874 if (event->type() == QEvent::ShortcutOverride) { |
|
875 d->control->processEvent(event, QPointF(0, -d->yoff)); |
|
876 return event->isAccepted(); |
|
877 } |
|
878 return QDeclarativePaintedItem::event(event); |
|
879 } |
|
880 |
|
881 /*! |
|
882 \overload |
|
883 Handles the given key \a event. |
|
884 */ |
|
885 void QDeclarativeTextEdit::keyPressEvent(QKeyEvent *event) |
|
886 { |
|
887 Q_D(QDeclarativeTextEdit); |
|
888 keyPressPreHandler(event); |
|
889 if (!event->isAccepted()) |
|
890 d->control->processEvent(event, QPointF(0, -d->yoff)); |
|
891 if (!event->isAccepted()) |
|
892 QDeclarativePaintedItem::keyPressEvent(event); |
|
893 } |
|
894 |
|
895 /*! |
|
896 \overload |
|
897 Handles the given key \a event. |
|
898 */ |
|
899 void QDeclarativeTextEdit::keyReleaseEvent(QKeyEvent *event) |
|
900 { |
|
901 Q_D(QDeclarativeTextEdit); |
|
902 keyReleasePreHandler(event); |
|
903 if (!event->isAccepted()) |
|
904 d->control->processEvent(event, QPointF(0, -d->yoff)); |
|
905 if (!event->isAccepted()) |
|
906 QDeclarativePaintedItem::keyReleaseEvent(event); |
|
907 } |
|
908 |
|
909 void QDeclarativeTextEditPrivate::focusChanged(bool hasFocus) |
|
910 { |
|
911 Q_Q(QDeclarativeTextEdit); |
|
912 q->setCursorVisible(hasFocus); |
|
913 QDeclarativeItemPrivate::focusChanged(hasFocus); |
|
914 } |
|
915 |
|
916 /*! |
|
917 Causes all text to be selected. |
|
918 */ |
|
919 void QDeclarativeTextEdit::selectAll() |
|
920 { |
|
921 Q_D(QDeclarativeTextEdit); |
|
922 d->control->selectAll(); |
|
923 } |
|
924 |
|
925 /*! |
|
926 \overload |
|
927 Handles the given mouse \a event. |
|
928 */ |
|
929 void QDeclarativeTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event) |
|
930 { |
|
931 Q_D(QDeclarativeTextEdit); |
|
932 bool hadFocus = hasFocus(); |
|
933 if (d->focusOnPress){ |
|
934 QGraphicsItem *p = parentItem();//###Is there a better way to find my focus scope? |
|
935 while(p) { |
|
936 if (p->flags() & QGraphicsItem::ItemIsFocusScope) |
|
937 p->setFocus(); |
|
938 p = p->parentItem(); |
|
939 } |
|
940 setFocus(true); |
|
941 } |
|
942 if (!hadFocus && hasFocus()) |
|
943 d->clickCausedFocus = true; |
|
944 if (event->type() != QEvent::GraphicsSceneMouseDoubleClick || d->selectByMouse) |
|
945 d->control->processEvent(event, QPointF(0, -d->yoff)); |
|
946 if (!event->isAccepted()) |
|
947 QDeclarativePaintedItem::mousePressEvent(event); |
|
948 } |
|
949 |
|
950 /*! |
|
951 \overload |
|
952 Handles the given mouse \a event. |
|
953 */ |
|
954 void QDeclarativeTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) |
|
955 { |
|
956 Q_D(QDeclarativeTextEdit); |
|
957 QWidget *widget = event->widget(); |
|
958 if (widget && (d->control->textInteractionFlags() & Qt::TextEditable) && boundingRect().contains(event->pos())) |
|
959 qt_widget_private(widget)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus); |
|
960 d->clickCausedFocus = false; |
|
961 |
|
962 d->control->processEvent(event, QPointF(0, -d->yoff)); |
|
963 if (!event->isAccepted()) |
|
964 QDeclarativePaintedItem::mouseReleaseEvent(event); |
|
965 } |
|
966 |
|
967 /*! |
|
968 \overload |
|
969 Handles the given mouse \a event. |
|
970 */ |
|
971 void QDeclarativeTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) |
|
972 { |
|
973 Q_D(QDeclarativeTextEdit); |
|
974 if (d->selectByMouse) { |
|
975 d->control->processEvent(event, QPointF(0, -d->yoff)); |
|
976 if (!event->isAccepted()) |
|
977 QDeclarativePaintedItem::mouseDoubleClickEvent(event); |
|
978 } else { |
|
979 QDeclarativePaintedItem::mouseDoubleClickEvent(event); |
|
980 } |
|
981 } |
|
982 |
|
983 /*! |
|
984 \overload |
|
985 Handles the given mouse \a event. |
|
986 */ |
|
987 void QDeclarativeTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event) |
|
988 { |
|
989 Q_D(QDeclarativeTextEdit); |
|
990 if (d->selectByMouse) { |
|
991 d->control->processEvent(event, QPointF(0, -d->yoff)); |
|
992 if (!event->isAccepted()) |
|
993 QDeclarativePaintedItem::mouseMoveEvent(event); |
|
994 event->setAccepted(true); |
|
995 } else { |
|
996 QDeclarativePaintedItem::mouseMoveEvent(event); |
|
997 } |
|
998 } |
|
999 |
|
1000 /*! |
|
1001 \overload |
|
1002 Handles the given input method \a event. |
|
1003 */ |
|
1004 void QDeclarativeTextEdit::inputMethodEvent(QInputMethodEvent *event) |
|
1005 { |
|
1006 Q_D(QDeclarativeTextEdit); |
|
1007 d->control->processEvent(event, QPointF(0, -d->yoff)); |
|
1008 } |
|
1009 |
|
1010 /*! |
|
1011 \overload |
|
1012 Returns the value of the given \a property. |
|
1013 */ |
|
1014 QVariant QDeclarativeTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const |
|
1015 { |
|
1016 Q_D(const QDeclarativeTextEdit); |
|
1017 return d->control->inputMethodQuery(property); |
|
1018 } |
|
1019 |
|
1020 /*! |
|
1021 Draws the contents of the text edit using the given \a painter within |
|
1022 the given \a bounds. |
|
1023 */ |
|
1024 void QDeclarativeTextEdit::drawContents(QPainter *painter, const QRect &bounds) |
|
1025 { |
|
1026 Q_D(QDeclarativeTextEdit); |
|
1027 |
|
1028 painter->setRenderHint(QPainter::TextAntialiasing, true); |
|
1029 painter->translate(0,d->yoff); |
|
1030 |
|
1031 d->control->drawContents(painter, bounds.translated(0,-d->yoff)); |
|
1032 |
|
1033 painter->translate(0,-d->yoff); |
|
1034 } |
|
1035 |
|
1036 void QDeclarativeTextEdit::updateImgCache(const QRectF &rf) |
|
1037 { |
|
1038 Q_D(const QDeclarativeTextEdit); |
|
1039 QRect r = rf.toRect(); |
|
1040 if (r != QRect(0,0,INT_MAX,INT_MAX)) // Don't translate "everything" |
|
1041 r = r.translated(0,d->yoff); |
|
1042 dirtyCache(r); |
|
1043 emit update(); |
|
1044 } |
|
1045 |
|
1046 /*! |
|
1047 \qmlproperty bool TextEdit::smooth |
|
1048 |
|
1049 This property holds whether the text is smoothly scaled or transformed. |
|
1050 |
|
1051 Smooth filtering gives better visual quality, but is slower. If |
|
1052 the item is displayed at its natural size, this property has no visual or |
|
1053 performance effect. |
|
1054 |
|
1055 \note Generally scaling artifacts are only visible if the item is stationary on |
|
1056 the screen. A common pattern when animating an item is to disable smooth |
|
1057 filtering at the beginning of the animation and reenable it at the conclusion. |
|
1058 */ |
|
1059 |
|
1060 void QDeclarativeTextEditPrivate::init() |
|
1061 { |
|
1062 Q_Q(QDeclarativeTextEdit); |
|
1063 |
|
1064 q->setSmooth(smooth); |
|
1065 q->setAcceptedMouseButtons(Qt::LeftButton); |
|
1066 q->setFlag(QGraphicsItem::ItemHasNoContents, false); |
|
1067 q->setFlag(QGraphicsItem::ItemAcceptsInputMethod); |
|
1068 |
|
1069 control = new QTextControl(q); |
|
1070 control->setIgnoreUnusedNavigationEvents(true); |
|
1071 |
|
1072 QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF))); |
|
1073 |
|
1074 QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged())); |
|
1075 QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged())); |
|
1076 QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers())); |
|
1077 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers())); |
|
1078 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); |
|
1079 |
|
1080 document = control->document(); |
|
1081 document->setDefaultFont(font); |
|
1082 document->setDocumentMargin(textMargin); |
|
1083 document->setUndoRedoEnabled(false); // flush undo buffer. |
|
1084 document->setUndoRedoEnabled(true); |
|
1085 updateDefaultTextOption(); |
|
1086 } |
|
1087 |
|
1088 void QDeclarativeTextEdit::q_textChanged() |
|
1089 { |
|
1090 updateSize(); |
|
1091 emit textChanged(text()); |
|
1092 } |
|
1093 |
|
1094 void QDeclarativeTextEdit::moveCursorDelegate() |
|
1095 { |
|
1096 Q_D(QDeclarativeTextEdit); |
|
1097 if(!d->cursor) |
|
1098 return; |
|
1099 QRectF cursorRect = d->control->cursorRect(); |
|
1100 d->cursor->setX(cursorRect.x()); |
|
1101 d->cursor->setY(cursorRect.y()); |
|
1102 } |
|
1103 |
|
1104 void QDeclarativeTextEditPrivate::updateSelection() |
|
1105 { |
|
1106 Q_Q(QDeclarativeTextEdit); |
|
1107 QTextCursor cursor = control->textCursor(); |
|
1108 bool startChange = (lastSelectionStart != cursor.selectionStart()); |
|
1109 bool endChange = (lastSelectionEnd != cursor.selectionEnd()); |
|
1110 //### Is it worth calculating a more minimal set of movements? |
|
1111 cursor.beginEditBlock(); |
|
1112 cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor); |
|
1113 cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor); |
|
1114 cursor.endEditBlock(); |
|
1115 control->setTextCursor(cursor); |
|
1116 if(startChange) |
|
1117 q->selectionStartChanged(); |
|
1118 if(endChange) |
|
1119 q->selectionEndChanged(); |
|
1120 startChange = (lastSelectionStart != control->textCursor().selectionStart()); |
|
1121 endChange = (lastSelectionEnd != control->textCursor().selectionEnd()); |
|
1122 } |
|
1123 |
|
1124 void QDeclarativeTextEdit::updateSelectionMarkers() |
|
1125 { |
|
1126 Q_D(QDeclarativeTextEdit); |
|
1127 if(d->lastSelectionStart != d->control->textCursor().selectionStart()){ |
|
1128 d->lastSelectionStart = d->control->textCursor().selectionStart(); |
|
1129 emit selectionStartChanged(); |
|
1130 } |
|
1131 if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){ |
|
1132 d->lastSelectionEnd = d->control->textCursor().selectionEnd(); |
|
1133 emit selectionEndChanged(); |
|
1134 } |
|
1135 } |
|
1136 |
|
1137 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't |
|
1138 // need to do all the calculations each time |
|
1139 void QDeclarativeTextEdit::updateSize() |
|
1140 { |
|
1141 Q_D(QDeclarativeTextEdit); |
|
1142 if (isComponentComplete()) { |
|
1143 QFontMetrics fm = QFontMetrics(d->font); |
|
1144 int dy = height(); |
|
1145 // ### assumes that if the width is set, the text will fill to edges |
|
1146 // ### (unless wrap is false, then clipping will occur) |
|
1147 if (widthValid()) |
|
1148 d->document->setTextWidth(width()); |
|
1149 dy -= (int)d->document->size().height(); |
|
1150 |
|
1151 if (heightValid()) { |
|
1152 if (d->vAlign == AlignBottom) |
|
1153 d->yoff = dy; |
|
1154 else if (d->vAlign == AlignVCenter) |
|
1155 d->yoff = dy/2; |
|
1156 } else { |
|
1157 d->yoff = 0; |
|
1158 } |
|
1159 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin); |
|
1160 |
|
1161 //### need to comfirm cost of always setting these |
|
1162 int newWidth = qCeil(d->document->idealWidth()); |
|
1163 if (!widthValid()) |
|
1164 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug) |
|
1165 int cursorWidth = 1; |
|
1166 if(d->cursor) |
|
1167 cursorWidth = d->cursor->width(); |
|
1168 newWidth += cursorWidth; |
|
1169 if(!d->document->isEmpty()) |
|
1170 newWidth += 3;// ### Need a better way of accounting for space between char and cursor |
|
1171 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed. |
|
1172 setImplicitWidth(newWidth); |
|
1173 setImplicitHeight(d->text.isEmpty() ? fm.height() : (int)d->document->size().height()); |
|
1174 |
|
1175 setContentsSize(QSize(width(), height())); |
|
1176 } else { |
|
1177 d->dirty = true; |
|
1178 } |
|
1179 emit update(); |
|
1180 } |
|
1181 |
|
1182 void QDeclarativeTextEditPrivate::updateDefaultTextOption() |
|
1183 { |
|
1184 QTextOption opt = document->defaultTextOption(); |
|
1185 int oldAlignment = opt.alignment(); |
|
1186 opt.setAlignment((Qt::Alignment)(int)(hAlign | vAlign)); |
|
1187 |
|
1188 QTextOption::WrapMode oldWrapMode = opt.wrapMode(); |
|
1189 opt.setWrapMode(QTextOption::WrapMode(wrapMode)); |
|
1190 |
|
1191 if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment()) |
|
1192 return; |
|
1193 document->setDefaultTextOption(opt); |
|
1194 } |
|
1195 |
|
1196 QT_END_NAMESPACE |