1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2017 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL3$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or later as published by the Free |
28 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
29 | ** the packaging of this file. Please review the following information to |
30 | ** ensure the GNU General Public License version 2.0 requirements will be |
31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
32 | ** |
33 | ** $QT_END_LICENSE$ |
34 | ** |
35 | ****************************************************************************/ |
36 | |
37 | #include "qquicktextarea_p.h" |
38 | #include "qquicktextarea_p_p.h" |
39 | #include "qquickcontrol_p.h" |
40 | #include "qquickcontrol_p_p.h" |
41 | #include "qquickscrollview_p.h" |
42 | #include "qquickdeferredexecute_p_p.h" |
43 | |
44 | #include <QtQml/qqmlinfo.h> |
45 | #include <QtQuick/private/qquickitem_p.h> |
46 | #include <QtQuick/private/qquickclipnode_p.h> |
47 | #include <QtQuick/private/qquickflickable_p.h> |
48 | |
49 | #if QT_CONFIG(accessibility) |
50 | #include <QtQuick/private/qquickaccessibleattached_p.h> |
51 | #endif |
52 | |
53 | QT_BEGIN_NAMESPACE |
54 | |
55 | /*! |
56 | \qmltype TextArea |
57 | \inherits TextEdit |
58 | //! \instantiates QQuickTextArea |
59 | \inqmlmodule QtQuick.Controls |
60 | \since 5.7 |
61 | \ingroup qtquickcontrols2-input |
62 | \brief Multi-line text input area. |
63 | |
64 | TextArea is a multi-line text editor. TextArea extends TextEdit with |
65 | a \l {placeholderText}{placeholder text} functionality, and adds decoration. |
66 | |
67 | \image qtquickcontrols2-textarea.png |
68 | |
69 | \code |
70 | TextArea { |
71 | placeholderText: qsTr("Enter description") |
72 | } |
73 | \endcode |
74 | |
75 | TextArea is not scrollable by itself. Especially on screen-size constrained |
76 | platforms, it is often preferable to make entire application pages scrollable. |
77 | On such a scrollable page, a non-scrollable TextArea might behave better than |
78 | nested scrollable controls. Notice, however, that in such a scenario, the background |
79 | decoration of the TextArea scrolls together with the rest of the scrollable |
80 | content. |
81 | |
82 | \section2 Scrollable TextArea |
83 | |
84 | If you want to make a TextArea scrollable, for example, when it covers |
85 | an entire application page, it can be placed inside a \l ScrollView. |
86 | |
87 | \image qtquickcontrols2-textarea-scrollable.png |
88 | |
89 | \snippet qtquickcontrols2-textarea-scrollable.qml 1 |
90 | |
91 | A TextArea that is placed inside a \l ScrollView does the following: |
92 | |
93 | \list |
94 | \li Sets the content size automatically |
95 | \li Ensures that the background decoration stays in place |
96 | \li Clips the content |
97 | \endlist |
98 | |
99 | \section2 Tab Focus |
100 | |
101 | By default, pressing the tab key while TextArea has |
102 | \l {Item::activeFocus}{active focus} results in a tab character being input |
103 | into the control itself. To make tab pass active focus onto another item, |
104 | use the attached \l KeyNavigation properties: |
105 | |
106 | \code |
107 | TextField { |
108 | id: textField |
109 | } |
110 | |
111 | TextArea { |
112 | KeyNavigation.priority: KeyNavigation.BeforeItem |
113 | KeyNavigation.tab: textField |
114 | } |
115 | \endcode |
116 | |
117 | \sa TextField, {Customizing TextArea}, {Input Controls} |
118 | */ |
119 | |
120 | /*! |
121 | \qmlsignal QtQuick.Controls::TextArea::pressAndHold(MouseEvent event) |
122 | |
123 | This signal is emitted when there is a long press (the delay depends on the platform plugin). |
124 | The \a event parameter provides information about the press, including the x and y |
125 | coordinates of the press, and which button is pressed. |
126 | |
127 | \sa pressed, released |
128 | */ |
129 | |
130 | /*! |
131 | \qmlsignal QtQuick.Controls::TextArea::pressed(MouseEvent event) |
132 | \since QtQuick.Controls 2.1 (Qt 5.8) |
133 | |
134 | This signal is emitted when the text area is pressed by the user. |
135 | The \a event parameter provides information about the press, |
136 | including the x and y coordinates of the press, and which button is pressed. |
137 | |
138 | \sa released, pressAndHold |
139 | */ |
140 | |
141 | /*! |
142 | \qmlsignal QtQuick.Controls::TextArea::released(MouseEvent event) |
143 | \since QtQuick.Controls 2.1 (Qt 5.8) |
144 | |
145 | This signal is emitted when the text area is released by the user. |
146 | The \a event parameter provides information about the release, |
147 | including the x and y coordinates of the press, and which button |
148 | is pressed. |
149 | |
150 | \sa pressed, pressAndHold |
151 | */ |
152 | |
153 | QQuickTextAreaPrivate::QQuickTextAreaPrivate() |
154 | { |
155 | #if QT_CONFIG(accessibility) |
156 | QAccessible::installActivationObserver(this); |
157 | #endif |
158 | } |
159 | |
160 | QQuickTextAreaPrivate::~QQuickTextAreaPrivate() |
161 | { |
162 | #if QT_CONFIG(accessibility) |
163 | QAccessible::removeActivationObserver(this); |
164 | #endif |
165 | } |
166 | |
167 | void QQuickTextAreaPrivate::setTopInset(qreal value, bool reset) |
168 | { |
169 | Q_Q(QQuickTextArea); |
170 | const QMarginsF oldInset = getInset(); |
171 | extra.value().topInset = value; |
172 | extra.value().hasTopInset = !reset; |
173 | if (!qFuzzyCompare(p1: oldInset.top(), p2: value)) { |
174 | emit q->topInsetChanged(); |
175 | q->insetChange(newInset: getInset(), oldInset); |
176 | } |
177 | } |
178 | |
179 | void QQuickTextAreaPrivate::setLeftInset(qreal value, bool reset) |
180 | { |
181 | Q_Q(QQuickTextArea); |
182 | const QMarginsF oldInset = getInset(); |
183 | extra.value().leftInset = value; |
184 | extra.value().hasLeftInset = !reset; |
185 | if (!qFuzzyCompare(p1: oldInset.left(), p2: value)) { |
186 | emit q->leftInsetChanged(); |
187 | q->insetChange(newInset: getInset(), oldInset); |
188 | } |
189 | } |
190 | |
191 | void QQuickTextAreaPrivate::setRightInset(qreal value, bool reset) |
192 | { |
193 | Q_Q(QQuickTextArea); |
194 | const QMarginsF oldInset = getInset(); |
195 | extra.value().rightInset = value; |
196 | extra.value().hasRightInset = !reset; |
197 | if (!qFuzzyCompare(p1: oldInset.right(), p2: value)) { |
198 | emit q->rightInsetChanged(); |
199 | q->insetChange(newInset: getInset(), oldInset); |
200 | } |
201 | } |
202 | |
203 | void QQuickTextAreaPrivate::setBottomInset(qreal value, bool reset) |
204 | { |
205 | Q_Q(QQuickTextArea); |
206 | const QMarginsF oldInset = getInset(); |
207 | extra.value().bottomInset = value; |
208 | extra.value().hasBottomInset = !reset; |
209 | if (!qFuzzyCompare(p1: oldInset.bottom(), p2: value)) { |
210 | emit q->bottomInsetChanged(); |
211 | q->insetChange(newInset: getInset(), oldInset); |
212 | } |
213 | } |
214 | |
215 | void QQuickTextAreaPrivate::resizeBackground() |
216 | { |
217 | if (!background) |
218 | return; |
219 | |
220 | resizingBackground = true; |
221 | |
222 | // When using the attached property TextArea.flickable, we reparent the background out |
223 | // of TextArea and into the Flickable since we don't want the background to move while |
224 | // flicking. This means that the size of the background should also follow the size of |
225 | // the Flickable rather than the size of the TextArea. |
226 | const auto flickable = qobject_cast<QQuickFlickable *>(object: background->parentItem()); |
227 | |
228 | QQuickItemPrivate *p = QQuickItemPrivate::get(item: background); |
229 | if (((!p->widthValid || !extra.isAllocated() || !extra->hasBackgroundWidth) && qFuzzyIsNull(d: background->x())) |
230 | || (extra.isAllocated() && (extra->hasLeftInset || extra->hasRightInset))) { |
231 | const qreal bgWidth = flickable ? flickable->width() : width; |
232 | background->setX(getLeftInset()); |
233 | background->setWidth(bgWidth - getLeftInset() - getRightInset()); |
234 | } |
235 | |
236 | if (((!p->heightValid || !extra.isAllocated() || !extra->hasBackgroundHeight) && qFuzzyIsNull(d: background->y())) |
237 | || (extra.isAllocated() && (extra->hasTopInset || extra->hasBottomInset))) { |
238 | const qreal bgHeight = flickable ? flickable->height() : height; |
239 | background->setY(getTopInset()); |
240 | background->setHeight(bgHeight - getTopInset() - getBottomInset()); |
241 | } |
242 | |
243 | resizingBackground = false; |
244 | } |
245 | |
246 | /*! |
247 | \internal |
248 | |
249 | Determine which font is implicitly imposed on this control by its ancestors |
250 | and QGuiApplication::font, resolve this against its own font (attributes from |
251 | the implicit font are copied over). Then propagate this font to this |
252 | control's children. |
253 | */ |
254 | void QQuickTextAreaPrivate::resolveFont() |
255 | { |
256 | Q_Q(QQuickTextArea); |
257 | inheritFont(font: QQuickControlPrivate::parentFont(item: q)); |
258 | } |
259 | |
260 | void QQuickTextAreaPrivate::inheritFont(const QFont &font) |
261 | { |
262 | QFont parentFont = extra.isAllocated() ? extra->requestedFont.resolve(font) : font; |
263 | parentFont.resolve(mask: extra.isAllocated() ? extra->requestedFont.resolve() | font.resolve() : font.resolve()); |
264 | |
265 | const QFont defaultFont = QQuickTheme::font(scope: QQuickTheme::TextArea); |
266 | QFont resolvedFont = parentFont.resolve(defaultFont); |
267 | // See comment in QQuickControlPrivate::inheritFont |
268 | if (defaultFont.families().isEmpty()) |
269 | resolvedFont.setFamilies(QStringList()); |
270 | |
271 | setFont_helper(resolvedFont); |
272 | } |
273 | |
274 | /*! |
275 | \internal |
276 | |
277 | Assign \a font to this control, and propagate it to all children. |
278 | */ |
279 | void QQuickTextAreaPrivate::updateFont(const QFont &font) |
280 | { |
281 | Q_Q(QQuickTextArea); |
282 | QFont oldFont = sourceFont; |
283 | q->QQuickTextEdit::setFont(font); |
284 | |
285 | QQuickControlPrivate::updateFontRecur(item: q, font); |
286 | |
287 | if (oldFont != font) |
288 | emit q->fontChanged(); |
289 | } |
290 | |
291 | /*! |
292 | \internal |
293 | |
294 | Determine which palette is implicitly imposed on this control by its ancestors |
295 | and QGuiApplication::palette, resolve this against its own palette (attributes from |
296 | the implicit palette are copied over). Then propagate this palette to this |
297 | control's children. |
298 | */ |
299 | void QQuickTextAreaPrivate::resolvePalette() |
300 | { |
301 | Q_Q(QQuickTextArea); |
302 | inheritPalette(palette: QQuickControlPrivate::parentPalette(item: q)); |
303 | } |
304 | |
305 | void QQuickTextAreaPrivate::inheritPalette(const QPalette &palette) |
306 | { |
307 | QPalette parentPalette = extra.isAllocated() ? extra->requestedPalette.resolve(palette) : palette; |
308 | parentPalette.resolve(mask: extra.isAllocated() ? extra->requestedPalette.resolve() | palette.resolve() : palette.resolve()); |
309 | |
310 | const QPalette defaultPalette = QQuickTheme::palette(scope: QQuickTheme::TextArea); |
311 | const QPalette resolvedPalette = parentPalette.resolve(defaultPalette); |
312 | |
313 | setPalette_helper(resolvedPalette); |
314 | } |
315 | |
316 | void QQuickTextAreaPrivate::updatePalette(const QPalette &palette) |
317 | { |
318 | Q_Q(QQuickTextArea); |
319 | QPalette oldPalette = resolvedPalette; |
320 | resolvedPalette = palette; |
321 | |
322 | QQuickControlPrivate::updatePaletteRecur(item: q, palette); |
323 | |
324 | if (oldPalette != palette) |
325 | emit q->paletteChanged(); |
326 | } |
327 | |
328 | #if QT_CONFIG(quicktemplates2_hover) |
329 | void QQuickTextAreaPrivate::updateHoverEnabled(bool enabled, bool xplicit) |
330 | { |
331 | Q_Q(QQuickTextArea); |
332 | if (!xplicit && explicitHoverEnabled) |
333 | return; |
334 | |
335 | bool wasEnabled = q->isHoverEnabled(); |
336 | explicitHoverEnabled = xplicit; |
337 | if (wasEnabled != enabled) { |
338 | q->setAcceptHoverEvents(enabled); |
339 | QQuickControlPrivate::updateHoverEnabledRecur(item: q, enabled); |
340 | emit q->hoverEnabledChanged(); |
341 | } |
342 | } |
343 | #endif |
344 | |
345 | void QQuickTextAreaPrivate::attachFlickable(QQuickFlickable *item) |
346 | { |
347 | Q_Q(QQuickTextArea); |
348 | flickable = item; |
349 | q->setParentItem(flickable->contentItem()); |
350 | |
351 | if (background) |
352 | background->setParentItem(flickable); |
353 | |
354 | QObjectPrivate::connect(sender: q, signal: &QQuickTextArea::contentSizeChanged, receiverPrivate: this, slot: &QQuickTextAreaPrivate::resizeFlickableContent); |
355 | QObjectPrivate::connect(sender: q, signal: &QQuickTextEdit::cursorRectangleChanged, receiverPrivate: this, slot: &QQuickTextAreaPrivate::ensureCursorVisible); |
356 | |
357 | QObject::connect(sender: flickable, signal: &QQuickFlickable::contentXChanged, receiver: q, slot: &QQuickItem::update); |
358 | QObject::connect(sender: flickable, signal: &QQuickFlickable::contentYChanged, receiver: q, slot: &QQuickItem::update); |
359 | |
360 | QQuickItemPrivate::get(item: flickable)->updateOrAddGeometryChangeListener(listener: this, types: QQuickGeometryChange::Size); |
361 | QQuickItemPrivate::get(item: flickable)->addItemChangeListener(listener: this, types: QQuickItemPrivate::Destroyed); |
362 | QObjectPrivate::connect(sender: flickable, signal: &QQuickFlickable::contentWidthChanged, receiverPrivate: this, slot: &QQuickTextAreaPrivate::resizeFlickableControl); |
363 | QObjectPrivate::connect(sender: flickable, signal: &QQuickFlickable::contentHeightChanged, receiverPrivate: this, slot: &QQuickTextAreaPrivate::resizeFlickableControl); |
364 | |
365 | resizeFlickableControl(); |
366 | } |
367 | |
368 | void QQuickTextAreaPrivate::detachFlickable() |
369 | { |
370 | Q_Q(QQuickTextArea); |
371 | q->setParentItem(nullptr); |
372 | if (background && background->parentItem() == flickable) |
373 | background->setParentItem(q); |
374 | |
375 | QObjectPrivate::disconnect(sender: q, signal: &QQuickTextArea::contentSizeChanged, receiverPrivate: this, slot: &QQuickTextAreaPrivate::resizeFlickableContent); |
376 | QObjectPrivate::disconnect(sender: q, signal: &QQuickTextEdit::cursorRectangleChanged, receiverPrivate: this, slot: &QQuickTextAreaPrivate::ensureCursorVisible); |
377 | |
378 | QObject::disconnect(sender: flickable, signal: &QQuickFlickable::contentXChanged, receiver: q, slot: &QQuickItem::update); |
379 | QObject::disconnect(sender: flickable, signal: &QQuickFlickable::contentYChanged, receiver: q, slot: &QQuickItem::update); |
380 | |
381 | QQuickItemPrivate::get(item: flickable)->updateOrRemoveGeometryChangeListener(listener: this, types: QQuickGeometryChange::Nothing); |
382 | QQuickItemPrivate::get(item: flickable)->removeItemChangeListener(this, types: QQuickItemPrivate::Destroyed); |
383 | QObjectPrivate::disconnect(sender: flickable, signal: &QQuickFlickable::contentWidthChanged, receiverPrivate: this, slot: &QQuickTextAreaPrivate::resizeFlickableControl); |
384 | QObjectPrivate::disconnect(sender: flickable, signal: &QQuickFlickable::contentHeightChanged, receiverPrivate: this, slot: &QQuickTextAreaPrivate::resizeFlickableControl); |
385 | |
386 | flickable = nullptr; |
387 | |
388 | resizeBackground(); |
389 | } |
390 | |
391 | void QQuickTextAreaPrivate::ensureCursorVisible() |
392 | { |
393 | Q_Q(QQuickTextArea); |
394 | if (!flickable) |
395 | return; |
396 | |
397 | const qreal cx = flickable->contentX(); |
398 | const qreal cy = flickable->contentY(); |
399 | const qreal w = flickable->width(); |
400 | const qreal h = flickable->height(); |
401 | |
402 | const qreal tp = q->topPadding(); |
403 | const qreal lp = q->leftPadding(); |
404 | const QRectF cr = q->cursorRectangle(); |
405 | |
406 | if (cr.left() <= cx + lp) { |
407 | flickable->setContentX(cr.left() - lp); |
408 | } else { |
409 | // calculate the rectangle of the next character and ensure that |
410 | // it's visible if it's on the same line with the cursor |
411 | const qreal rp = q->rightPadding(); |
412 | const QRectF nr = q->cursorPosition() < q->length() ? q->positionToRectangle(q->cursorPosition() + 1) : QRectF(); |
413 | if (qFuzzyCompare(p1: nr.y(), p2: cr.y()) && nr.right() >= cx + lp + w - rp) |
414 | flickable->setContentX(nr.right() - w + rp); |
415 | else if (cr.right() >= cx + lp + w - rp) |
416 | flickable->setContentX(cr.right() - w + rp); |
417 | } |
418 | |
419 | if (cr.top() <= cy + tp) { |
420 | flickable->setContentY(cr.top() - tp); |
421 | } else { |
422 | const qreal bp = q->bottomPadding(); |
423 | if (cr.bottom() >= cy + tp + h - bp) |
424 | flickable->setContentY(cr.bottom() - h + bp); |
425 | } |
426 | } |
427 | |
428 | void QQuickTextAreaPrivate::resizeFlickableControl() |
429 | { |
430 | Q_Q(QQuickTextArea); |
431 | if (!flickable) |
432 | return; |
433 | |
434 | const qreal w = wrapMode == QQuickTextArea::NoWrap ? qMax(a: flickable->width(), b: flickable->contentWidth()) : flickable->width(); |
435 | const qreal h = qMax(a: flickable->height(), b: flickable->contentHeight()); |
436 | q->setSize(QSizeF(w, h)); |
437 | |
438 | resizeBackground(); |
439 | } |
440 | |
441 | void QQuickTextAreaPrivate::resizeFlickableContent() |
442 | { |
443 | Q_Q(QQuickTextArea); |
444 | if (!flickable) |
445 | return; |
446 | |
447 | flickable->setContentWidth(q->contentWidth() + q->leftPadding() + q->rightPadding()); |
448 | flickable->setContentHeight(q->contentHeight() + q->topPadding() + q->bottomPadding()); |
449 | } |
450 | |
451 | void QQuickTextAreaPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) |
452 | { |
453 | Q_UNUSED(diff); |
454 | if (!resizingBackground && item == background) { |
455 | QQuickItemPrivate *p = QQuickItemPrivate::get(item); |
456 | // Only set hasBackgroundWidth/Height if it was a width/height change, |
457 | // otherwise we're prevented from setting a width/height in the future. |
458 | if (change.widthChange()) |
459 | extra.value().hasBackgroundWidth = p->widthValid; |
460 | if (change.heightChange()) |
461 | extra.value().hasBackgroundHeight = p->heightValid; |
462 | } |
463 | |
464 | if (flickable) |
465 | resizeFlickableControl(); |
466 | else |
467 | resizeBackground(); |
468 | } |
469 | |
470 | qreal QQuickTextAreaPrivate::getImplicitWidth() const |
471 | { |
472 | return QQuickItemPrivate::getImplicitWidth(); |
473 | } |
474 | |
475 | qreal QQuickTextAreaPrivate::getImplicitHeight() const |
476 | { |
477 | return QQuickItemPrivate::getImplicitHeight(); |
478 | } |
479 | |
480 | void QQuickTextAreaPrivate::implicitWidthChanged() |
481 | { |
482 | Q_Q(QQuickTextArea); |
483 | QQuickItemPrivate::implicitWidthChanged(); |
484 | emit q->implicitWidthChanged3(); |
485 | } |
486 | |
487 | void QQuickTextAreaPrivate::implicitHeightChanged() |
488 | { |
489 | Q_Q(QQuickTextArea); |
490 | QQuickItemPrivate::implicitHeightChanged(); |
491 | emit q->implicitHeightChanged3(); |
492 | } |
493 | |
494 | void QQuickTextAreaPrivate::readOnlyChanged(bool isReadOnly) |
495 | { |
496 | Q_UNUSED(isReadOnly); |
497 | #if QT_CONFIG(accessibility) |
498 | if (QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(object: q_func())) |
499 | accessibleAttached->set_readOnly(isReadOnly); |
500 | #endif |
501 | #if QT_CONFIG(cursor) |
502 | q_func()->setCursor(isReadOnly ? Qt::ArrowCursor : Qt::IBeamCursor); |
503 | #endif |
504 | } |
505 | |
506 | #if QT_CONFIG(accessibility) |
507 | void QQuickTextAreaPrivate::accessibilityActiveChanged(bool active) |
508 | { |
509 | if (!active) |
510 | return; |
511 | |
512 | Q_Q(QQuickTextArea); |
513 | QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(object: qmlAttachedPropertiesObject<QQuickAccessibleAttached>(obj: q, create: true)); |
514 | Q_ASSERT(accessibleAttached); |
515 | accessibleAttached->setRole(accessibleRole()); |
516 | accessibleAttached->set_readOnly(q->isReadOnly()); |
517 | accessibleAttached->setDescription(placeholder); |
518 | } |
519 | |
520 | QAccessible::Role QQuickTextAreaPrivate::accessibleRole() const |
521 | { |
522 | return QAccessible::EditableText; |
523 | } |
524 | #endif |
525 | |
526 | static inline QString backgroundName() { return QStringLiteral("background" ); } |
527 | |
528 | void QQuickTextAreaPrivate::cancelBackground() |
529 | { |
530 | Q_Q(QQuickTextArea); |
531 | quickCancelDeferred(object: q, property: backgroundName()); |
532 | } |
533 | |
534 | void QQuickTextAreaPrivate::executeBackground(bool complete) |
535 | { |
536 | Q_Q(QQuickTextArea); |
537 | if (background.wasExecuted()) |
538 | return; |
539 | |
540 | if (!background || complete) |
541 | quickBeginDeferred(object: q, property: backgroundName(), delegate&: background); |
542 | if (complete) |
543 | quickCompleteDeferred(object: q, property: backgroundName(), delegate&: background); |
544 | } |
545 | |
546 | void QQuickTextAreaPrivate::itemImplicitWidthChanged(QQuickItem *item) |
547 | { |
548 | Q_Q(QQuickTextArea); |
549 | if (item == background) |
550 | emit q->implicitBackgroundWidthChanged(); |
551 | } |
552 | |
553 | void QQuickTextAreaPrivate::itemImplicitHeightChanged(QQuickItem *item) |
554 | { |
555 | Q_Q(QQuickTextArea); |
556 | if (item == background) |
557 | emit q->implicitBackgroundHeightChanged(); |
558 | } |
559 | |
560 | void QQuickTextAreaPrivate::itemDestroyed(QQuickItem *item) |
561 | { |
562 | Q_Q(QQuickTextArea); |
563 | if (item == background) { |
564 | background = nullptr; |
565 | emit q->implicitBackgroundWidthChanged(); |
566 | emit q->implicitBackgroundHeightChanged(); |
567 | } else if (item == flickable) { |
568 | detachFlickable(); |
569 | } |
570 | } |
571 | |
572 | QQuickTextArea::QQuickTextArea(QQuickItem *parent) |
573 | : QQuickTextEdit(*(new QQuickTextAreaPrivate), parent) |
574 | { |
575 | Q_D(QQuickTextArea); |
576 | setActiveFocusOnTab(true); |
577 | setAcceptedMouseButtons(Qt::AllButtons); |
578 | d->setImplicitResizeEnabled(false); |
579 | d->pressHandler.control = this; |
580 | #if QT_CONFIG(cursor) |
581 | setCursor(Qt::IBeamCursor); |
582 | #endif |
583 | QObjectPrivate::connect(sender: this, signal: &QQuickTextEdit::readOnlyChanged, |
584 | receiverPrivate: d, slot: &QQuickTextAreaPrivate::readOnlyChanged); |
585 | } |
586 | |
587 | QQuickTextArea::~QQuickTextArea() |
588 | { |
589 | Q_D(QQuickTextArea); |
590 | if (d->flickable) |
591 | d->detachFlickable(); |
592 | QQuickControlPrivate::removeImplicitSizeListener(item: d->background, listener: d, changes: QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry); |
593 | } |
594 | |
595 | QQuickTextAreaAttached *QQuickTextArea::qmlAttachedProperties(QObject *object) |
596 | { |
597 | return new QQuickTextAreaAttached(object); |
598 | } |
599 | |
600 | QFont QQuickTextArea::font() const |
601 | { |
602 | return QQuickTextEdit::font(); |
603 | } |
604 | |
605 | void QQuickTextArea::setFont(const QFont &font) |
606 | { |
607 | Q_D(QQuickTextArea); |
608 | if (d->extra.value().requestedFont.resolve() == font.resolve() && d->extra.value().requestedFont == font) |
609 | return; |
610 | |
611 | d->extra.value().requestedFont = font; |
612 | d->resolveFont(); |
613 | } |
614 | |
615 | /*! |
616 | \qmlproperty Item QtQuick.Controls::TextArea::background |
617 | |
618 | This property holds the background item. |
619 | |
620 | \input qquickcontrol-background.qdocinc notes |
621 | |
622 | \sa {Customizing TextArea} |
623 | */ |
624 | QQuickItem *QQuickTextArea::background() const |
625 | { |
626 | QQuickTextAreaPrivate *d = const_cast<QQuickTextAreaPrivate *>(d_func()); |
627 | if (!d->background) |
628 | d->executeBackground(); |
629 | return d->background; |
630 | } |
631 | |
632 | void QQuickTextArea::setBackground(QQuickItem *background) |
633 | { |
634 | Q_D(QQuickTextArea); |
635 | if (d->background == background) |
636 | return; |
637 | |
638 | if (!d->background.isExecuting()) |
639 | d->cancelBackground(); |
640 | |
641 | const qreal oldImplicitBackgroundWidth = implicitBackgroundWidth(); |
642 | const qreal oldImplicitBackgroundHeight = implicitBackgroundHeight(); |
643 | |
644 | if (d->extra.isAllocated()) { |
645 | d->extra.value().hasBackgroundWidth = false; |
646 | d->extra.value().hasBackgroundHeight = false; |
647 | } |
648 | |
649 | QQuickControlPrivate::removeImplicitSizeListener(item: d->background, listener: d, changes: QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry); |
650 | QQuickControlPrivate::hideOldItem(item: d->background); |
651 | d->background = background; |
652 | |
653 | if (background) { |
654 | QQuickItemPrivate *p = QQuickItemPrivate::get(item: background); |
655 | if (p->widthValid || p->heightValid) { |
656 | d->extra.value().hasBackgroundWidth = p->widthValid; |
657 | d->extra.value().hasBackgroundHeight = p->heightValid; |
658 | } |
659 | if (d->flickable) |
660 | background->setParentItem(d->flickable); |
661 | else |
662 | background->setParentItem(this); |
663 | if (qFuzzyIsNull(d: background->z())) |
664 | background->setZ(-1); |
665 | if (isComponentComplete()) |
666 | d->resizeBackground(); |
667 | QQuickControlPrivate::addImplicitSizeListener(item: background, listener: d, changes: QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry); |
668 | } |
669 | |
670 | if (!qFuzzyCompare(p1: oldImplicitBackgroundWidth, p2: implicitBackgroundWidth())) |
671 | emit implicitBackgroundWidthChanged(); |
672 | if (!qFuzzyCompare(p1: oldImplicitBackgroundHeight, p2: implicitBackgroundHeight())) |
673 | emit implicitBackgroundHeightChanged(); |
674 | if (!d->background.isExecuting()) |
675 | emit backgroundChanged(); |
676 | } |
677 | |
678 | /*! |
679 | \qmlproperty string QtQuick.Controls::TextArea::placeholderText |
680 | |
681 | This property holds the short hint that is displayed in the text area before |
682 | the user enters a value. |
683 | */ |
684 | QString QQuickTextArea::placeholderText() const |
685 | { |
686 | Q_D(const QQuickTextArea); |
687 | return d->placeholder; |
688 | } |
689 | |
690 | void QQuickTextArea::setPlaceholderText(const QString &text) |
691 | { |
692 | Q_D(QQuickTextArea); |
693 | if (d->placeholder == text) |
694 | return; |
695 | |
696 | d->placeholder = text; |
697 | #if QT_CONFIG(accessibility) |
698 | if (QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(object: this)) |
699 | accessibleAttached->setDescription(text); |
700 | #endif |
701 | emit placeholderTextChanged(); |
702 | } |
703 | |
704 | /*! |
705 | \qmlproperty color QtQuick.Controls::TextArea::placeholderTextColor |
706 | \since QtQuick.Controls 2.5 (Qt 5.12) |
707 | |
708 | This property holds the color of placeholderText. |
709 | |
710 | \sa placeholderText |
711 | */ |
712 | QColor QQuickTextArea::placeholderTextColor() const |
713 | { |
714 | Q_D(const QQuickTextArea); |
715 | return d->placeholderColor; |
716 | } |
717 | |
718 | void QQuickTextArea::setPlaceholderTextColor(const QColor &color) |
719 | { |
720 | Q_D(QQuickTextArea); |
721 | if (d->placeholderColor == color) |
722 | return; |
723 | |
724 | d->placeholderColor = color; |
725 | emit placeholderTextColorChanged(); |
726 | } |
727 | |
728 | /*! |
729 | \qmlproperty enumeration QtQuick.Controls::TextArea::focusReason |
730 | |
731 | \include qquickcontrol-focusreason.qdocinc |
732 | */ |
733 | Qt::FocusReason QQuickTextArea::focusReason() const |
734 | { |
735 | Q_D(const QQuickTextArea); |
736 | return d->focusReason; |
737 | } |
738 | |
739 | void QQuickTextArea::setFocusReason(Qt::FocusReason reason) |
740 | { |
741 | Q_D(QQuickTextArea); |
742 | if (d->focusReason == reason) |
743 | return; |
744 | |
745 | d->focusReason = reason; |
746 | emit focusReasonChanged(); |
747 | } |
748 | |
749 | bool QQuickTextArea::contains(const QPointF &point) const |
750 | { |
751 | Q_D(const QQuickTextArea); |
752 | if (d->flickable && !d->flickable->contains(point: d->flickable->mapFromItem(item: this, point))) |
753 | return false; |
754 | return QQuickTextEdit::contains(point); |
755 | } |
756 | |
757 | /*! |
758 | \since QtQuick.Controls 2.1 (Qt 5.8) |
759 | \qmlproperty bool QtQuick.Controls::TextArea::hovered |
760 | \readonly |
761 | |
762 | This property holds whether the text area is hovered. |
763 | |
764 | \sa hoverEnabled |
765 | */ |
766 | bool QQuickTextArea::isHovered() const |
767 | { |
768 | #if QT_CONFIG(quicktemplates2_hover) |
769 | Q_D(const QQuickTextArea); |
770 | return d->hovered; |
771 | #else |
772 | return false; |
773 | #endif |
774 | } |
775 | |
776 | void QQuickTextArea::setHovered(bool hovered) |
777 | { |
778 | #if QT_CONFIG(quicktemplates2_hover) |
779 | Q_D(QQuickTextArea); |
780 | if (hovered == d->hovered) |
781 | return; |
782 | |
783 | d->hovered = hovered; |
784 | emit hoveredChanged(); |
785 | #else |
786 | Q_UNUSED(hovered); |
787 | #endif |
788 | } |
789 | |
790 | /*! |
791 | \since QtQuick.Controls 2.1 (Qt 5.8) |
792 | \qmlproperty bool QtQuick.Controls::TextArea::hoverEnabled |
793 | |
794 | This property determines whether the text area accepts hover events. The default value is \c true. |
795 | |
796 | \sa hovered |
797 | */ |
798 | bool QQuickTextArea::isHoverEnabled() const |
799 | { |
800 | #if QT_CONFIG(quicktemplates2_hover) |
801 | Q_D(const QQuickTextArea); |
802 | return d->hoverEnabled; |
803 | #else |
804 | return false; |
805 | #endif |
806 | } |
807 | |
808 | void QQuickTextArea::setHoverEnabled(bool enabled) |
809 | { |
810 | #if QT_CONFIG(quicktemplates2_hover) |
811 | Q_D(QQuickTextArea); |
812 | if (d->explicitHoverEnabled && enabled == d->hoverEnabled) |
813 | return; |
814 | |
815 | d->updateHoverEnabled(enabled, xplicit: true); // explicit=true |
816 | #else |
817 | Q_UNUSED(enabled); |
818 | #endif |
819 | } |
820 | |
821 | void QQuickTextArea::resetHoverEnabled() |
822 | { |
823 | #if QT_CONFIG(quicktemplates2_hover) |
824 | Q_D(QQuickTextArea); |
825 | if (!d->explicitHoverEnabled) |
826 | return; |
827 | |
828 | d->explicitHoverEnabled = false; |
829 | d->updateHoverEnabled(enabled: QQuickControlPrivate::calcHoverEnabled(item: d->parentItem), xplicit: false); // explicit=false |
830 | #endif |
831 | } |
832 | |
833 | /*! |
834 | \since QtQuick.Controls 2.3 (Qt 5.10) |
835 | \qmlproperty palette QtQuick.Controls::TextArea::palette |
836 | |
837 | This property holds the palette currently set for the text area. |
838 | |
839 | \sa Control::palette |
840 | */ |
841 | QPalette QQuickTextArea::palette() const |
842 | { |
843 | Q_D(const QQuickTextArea); |
844 | QPalette palette = d->resolvedPalette; |
845 | if (!isEnabled()) |
846 | palette.setCurrentColorGroup(QPalette::Disabled); |
847 | return palette; |
848 | } |
849 | |
850 | void QQuickTextArea::setPalette(const QPalette &palette) |
851 | { |
852 | Q_D(QQuickTextArea); |
853 | if (d->extra.value().requestedPalette.resolve() == palette.resolve() && d->extra.value().requestedPalette == palette) |
854 | return; |
855 | |
856 | d->extra.value().requestedPalette = palette; |
857 | d->resolvePalette(); |
858 | } |
859 | |
860 | void QQuickTextArea::resetPalette() |
861 | { |
862 | setPalette(QPalette()); |
863 | } |
864 | |
865 | /*! |
866 | \since QtQuick.Controls 2.5 (Qt 5.12) |
867 | \qmlproperty real QtQuick.Controls::TextArea::implicitBackgroundWidth |
868 | \readonly |
869 | |
870 | This property holds the implicit background width. |
871 | |
872 | The value is equal to \c {background ? background.implicitWidth : 0}. |
873 | |
874 | \sa implicitBackgroundHeight |
875 | */ |
876 | qreal QQuickTextArea::implicitBackgroundWidth() const |
877 | { |
878 | Q_D(const QQuickTextArea); |
879 | if (!d->background) |
880 | return 0; |
881 | return d->background->implicitWidth(); |
882 | } |
883 | |
884 | /*! |
885 | \since QtQuick.Controls 2.5 (Qt 5.12) |
886 | \qmlproperty real QtQuick.Controls::TextArea::implicitBackgroundHeight |
887 | \readonly |
888 | |
889 | This property holds the implicit background height. |
890 | |
891 | The value is equal to \c {background ? background.implicitHeight : 0}. |
892 | |
893 | \sa implicitBackgroundWidth |
894 | */ |
895 | qreal QQuickTextArea::implicitBackgroundHeight() const |
896 | { |
897 | Q_D(const QQuickTextArea); |
898 | if (!d->background) |
899 | return 0; |
900 | return d->background->implicitHeight(); |
901 | } |
902 | |
903 | /*! |
904 | \since QtQuick.Controls 2.5 (Qt 5.12) |
905 | \qmlproperty real QtQuick.Controls::TextArea::topInset |
906 | |
907 | This property holds the top inset for the background. |
908 | |
909 | \sa {Control Layout}, bottomInset |
910 | */ |
911 | qreal QQuickTextArea::topInset() const |
912 | { |
913 | Q_D(const QQuickTextArea); |
914 | return d->getTopInset(); |
915 | } |
916 | |
917 | void QQuickTextArea::setTopInset(qreal inset) |
918 | { |
919 | Q_D(QQuickTextArea); |
920 | d->setTopInset(value: inset); |
921 | } |
922 | |
923 | void QQuickTextArea::resetTopInset() |
924 | { |
925 | Q_D(QQuickTextArea); |
926 | d->setTopInset(value: 0, reset: true); |
927 | } |
928 | |
929 | /*! |
930 | \since QtQuick.Controls 2.5 (Qt 5.12) |
931 | \qmlproperty real QtQuick.Controls::TextArea::leftInset |
932 | |
933 | This property holds the left inset for the background. |
934 | |
935 | \sa {Control Layout}, rightInset |
936 | */ |
937 | qreal QQuickTextArea::leftInset() const |
938 | { |
939 | Q_D(const QQuickTextArea); |
940 | return d->getLeftInset(); |
941 | } |
942 | |
943 | void QQuickTextArea::setLeftInset(qreal inset) |
944 | { |
945 | Q_D(QQuickTextArea); |
946 | d->setLeftInset(value: inset); |
947 | } |
948 | |
949 | void QQuickTextArea::resetLeftInset() |
950 | { |
951 | Q_D(QQuickTextArea); |
952 | d->setLeftInset(value: 0, reset: true); |
953 | } |
954 | |
955 | /*! |
956 | \since QtQuick.Controls 2.5 (Qt 5.12) |
957 | \qmlproperty real QtQuick.Controls::TextArea::rightInset |
958 | |
959 | This property holds the right inset for the background. |
960 | |
961 | \sa {Control Layout}, leftInset |
962 | */ |
963 | qreal QQuickTextArea::rightInset() const |
964 | { |
965 | Q_D(const QQuickTextArea); |
966 | return d->getRightInset(); |
967 | } |
968 | |
969 | void QQuickTextArea::setRightInset(qreal inset) |
970 | { |
971 | Q_D(QQuickTextArea); |
972 | d->setRightInset(value: inset); |
973 | } |
974 | |
975 | void QQuickTextArea::resetRightInset() |
976 | { |
977 | Q_D(QQuickTextArea); |
978 | d->setRightInset(value: 0, reset: true); |
979 | } |
980 | |
981 | /*! |
982 | \since QtQuick.Controls 2.5 (Qt 5.12) |
983 | \qmlproperty real QtQuick.Controls::TextArea::bottomInset |
984 | |
985 | This property holds the bottom inset for the background. |
986 | |
987 | \sa {Control Layout}, topInset |
988 | */ |
989 | qreal QQuickTextArea::bottomInset() const |
990 | { |
991 | Q_D(const QQuickTextArea); |
992 | return d->getBottomInset(); |
993 | } |
994 | |
995 | void QQuickTextArea::setBottomInset(qreal inset) |
996 | { |
997 | Q_D(QQuickTextArea); |
998 | d->setBottomInset(value: inset); |
999 | } |
1000 | |
1001 | void QQuickTextArea::resetBottomInset() |
1002 | { |
1003 | Q_D(QQuickTextArea); |
1004 | d->setBottomInset(value: 0, reset: true); |
1005 | } |
1006 | |
1007 | void QQuickTextArea::classBegin() |
1008 | { |
1009 | Q_D(QQuickTextArea); |
1010 | QQuickTextEdit::classBegin(); |
1011 | d->resolveFont(); |
1012 | d->resolvePalette(); |
1013 | } |
1014 | |
1015 | void QQuickTextArea::componentComplete() |
1016 | { |
1017 | Q_D(QQuickTextArea); |
1018 | d->executeBackground(complete: true); |
1019 | QQuickTextEdit::componentComplete(); |
1020 | d->resizeBackground(); |
1021 | #if QT_CONFIG(quicktemplates2_hover) |
1022 | if (!d->explicitHoverEnabled) |
1023 | setAcceptHoverEvents(QQuickControlPrivate::calcHoverEnabled(item: d->parentItem)); |
1024 | #endif |
1025 | #if QT_CONFIG(accessibility) |
1026 | if (QAccessible::isActive()) |
1027 | d->accessibilityActiveChanged(active: true); |
1028 | #endif |
1029 | } |
1030 | |
1031 | void QQuickTextArea::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) |
1032 | { |
1033 | Q_D(QQuickTextArea); |
1034 | QQuickTextEdit::itemChange(change, value); |
1035 | switch (change) { |
1036 | case ItemEnabledHasChanged: |
1037 | emit paletteChanged(); |
1038 | break; |
1039 | case ItemSceneChange: |
1040 | case ItemParentHasChanged: |
1041 | if ((change == ItemParentHasChanged && value.item) || (change == ItemSceneChange && value.window)) { |
1042 | d->resolveFont(); |
1043 | d->resolvePalette(); |
1044 | #if QT_CONFIG(quicktemplates2_hover) |
1045 | if (!d->explicitHoverEnabled) |
1046 | d->updateHoverEnabled(enabled: QQuickControlPrivate::calcHoverEnabled(item: d->parentItem), xplicit: false); // explicit=false |
1047 | #endif |
1048 | if (change == ItemParentHasChanged) { |
1049 | QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(object: value.item->parentItem()); |
1050 | if (flickable) { |
1051 | QQuickScrollView *scrollView = qobject_cast<QQuickScrollView *>(object: flickable->parentItem()); |
1052 | if (scrollView) |
1053 | d->attachFlickable(item: flickable); |
1054 | } |
1055 | } |
1056 | } |
1057 | break; |
1058 | default: |
1059 | break; |
1060 | } |
1061 | } |
1062 | |
1063 | void QQuickTextArea::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) |
1064 | { |
1065 | Q_D(QQuickTextArea); |
1066 | QQuickTextEdit::geometryChanged(newGeometry, oldGeometry); |
1067 | d->resizeBackground(); |
1068 | } |
1069 | |
1070 | void QQuickTextArea::insetChange(const QMarginsF &newInset, const QMarginsF &oldInset) |
1071 | { |
1072 | Q_D(QQuickTextArea); |
1073 | Q_UNUSED(newInset); |
1074 | Q_UNUSED(oldInset); |
1075 | d->resizeBackground(); |
1076 | } |
1077 | |
1078 | QSGNode *QQuickTextArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) |
1079 | { |
1080 | Q_D(QQuickTextArea); |
1081 | QQuickDefaultClipNode *clipNode = static_cast<QQuickDefaultClipNode *>(oldNode); |
1082 | if (!clipNode) |
1083 | clipNode = new QQuickDefaultClipNode(QRectF()); |
1084 | |
1085 | QQuickItem *clipper = this; |
1086 | if (d->flickable) |
1087 | clipper = d->flickable; |
1088 | |
1089 | const QRectF cr = clipper->clipRect().adjusted(xp1: leftPadding(), yp1: topPadding(), xp2: -rightPadding(), yp2: -bottomPadding()); |
1090 | clipNode->setRect(!d->flickable ? cr : cr.translated(dx: d->flickable->contentX(), dy: d->flickable->contentY())); |
1091 | clipNode->update(); |
1092 | |
1093 | QSGNode *textNode = QQuickTextEdit::updatePaintNode(oldNode: clipNode->firstChild(), updatePaintNodeData: data); |
1094 | if (!textNode->parent()) |
1095 | clipNode->appendChildNode(node: textNode); |
1096 | |
1097 | if (d->cursorItem) { |
1098 | QQuickDefaultClipNode *cursorNode = QQuickItemPrivate::get(item: d->cursorItem)->clipNode(); |
1099 | if (cursorNode) |
1100 | cursorNode->setClipRect(d->cursorItem->mapRectFromItem(item: clipper, rect: cr)); |
1101 | } |
1102 | |
1103 | return clipNode; |
1104 | } |
1105 | |
1106 | void QQuickTextArea::focusInEvent(QFocusEvent *event) |
1107 | { |
1108 | QQuickTextEdit::focusInEvent(event); |
1109 | setFocusReason(event->reason()); |
1110 | } |
1111 | |
1112 | void QQuickTextArea::focusOutEvent(QFocusEvent *event) |
1113 | { |
1114 | QQuickTextEdit::focusOutEvent(event); |
1115 | setFocusReason(event->reason()); |
1116 | } |
1117 | |
1118 | #if QT_CONFIG(quicktemplates2_hover) |
1119 | void QQuickTextArea::hoverEnterEvent(QHoverEvent *event) |
1120 | { |
1121 | Q_D(QQuickTextArea); |
1122 | QQuickTextEdit::hoverEnterEvent(event); |
1123 | setHovered(d->hoverEnabled); |
1124 | event->setAccepted(d->hoverEnabled); |
1125 | } |
1126 | |
1127 | void QQuickTextArea::hoverLeaveEvent(QHoverEvent *event) |
1128 | { |
1129 | Q_D(QQuickTextArea); |
1130 | QQuickTextEdit::hoverLeaveEvent(event); |
1131 | setHovered(false); |
1132 | event->setAccepted(d->hoverEnabled); |
1133 | } |
1134 | #endif |
1135 | |
1136 | void QQuickTextArea::mousePressEvent(QMouseEvent *event) |
1137 | { |
1138 | Q_D(QQuickTextArea); |
1139 | d->pressHandler.mousePressEvent(event); |
1140 | if (d->pressHandler.isActive()) { |
1141 | if (d->pressHandler.delayedMousePressEvent) { |
1142 | QQuickTextEdit::mousePressEvent(event: d->pressHandler.delayedMousePressEvent); |
1143 | d->pressHandler.clearDelayedMouseEvent(); |
1144 | } |
1145 | // Calling the base class implementation will result in QQuickTextControl's |
1146 | // press handler being called, which ignores events that aren't Qt::LeftButton. |
1147 | const bool wasAccepted = event->isAccepted(); |
1148 | QQuickTextEdit::mousePressEvent(event); |
1149 | if (wasAccepted) |
1150 | event->accept(); |
1151 | } |
1152 | } |
1153 | |
1154 | void QQuickTextArea::mouseMoveEvent(QMouseEvent *event) |
1155 | { |
1156 | Q_D(QQuickTextArea); |
1157 | d->pressHandler.mouseMoveEvent(event); |
1158 | if (d->pressHandler.isActive()) { |
1159 | if (d->pressHandler.delayedMousePressEvent) { |
1160 | QQuickTextEdit::mousePressEvent(event: d->pressHandler.delayedMousePressEvent); |
1161 | d->pressHandler.clearDelayedMouseEvent(); |
1162 | } |
1163 | QQuickTextEdit::mouseMoveEvent(event); |
1164 | } |
1165 | } |
1166 | |
1167 | void QQuickTextArea::mouseReleaseEvent(QMouseEvent *event) |
1168 | { |
1169 | Q_D(QQuickTextArea); |
1170 | d->pressHandler.mouseReleaseEvent(event); |
1171 | if (d->pressHandler.isActive()) { |
1172 | if (d->pressHandler.delayedMousePressEvent) { |
1173 | QQuickTextEdit::mousePressEvent(event: d->pressHandler.delayedMousePressEvent); |
1174 | d->pressHandler.clearDelayedMouseEvent(); |
1175 | } |
1176 | QQuickTextEdit::mouseReleaseEvent(event); |
1177 | } |
1178 | } |
1179 | |
1180 | void QQuickTextArea::mouseDoubleClickEvent(QMouseEvent *event) |
1181 | { |
1182 | Q_D(QQuickTextArea); |
1183 | if (d->pressHandler.delayedMousePressEvent) { |
1184 | QQuickTextEdit::mousePressEvent(event: d->pressHandler.delayedMousePressEvent); |
1185 | d->pressHandler.clearDelayedMouseEvent(); |
1186 | } |
1187 | QQuickTextEdit::mouseDoubleClickEvent(event); |
1188 | } |
1189 | |
1190 | void QQuickTextArea::timerEvent(QTimerEvent *event) |
1191 | { |
1192 | Q_D(QQuickTextArea); |
1193 | if (event->timerId() == d->pressHandler.timer.timerId()) |
1194 | d->pressHandler.timerEvent(event); |
1195 | else |
1196 | QQuickTextEdit::timerEvent(event); |
1197 | } |
1198 | |
1199 | class QQuickTextAreaAttachedPrivate : public QObjectPrivate |
1200 | { |
1201 | public: |
1202 | QQuickTextArea *control = nullptr; |
1203 | }; |
1204 | |
1205 | QQuickTextAreaAttached::QQuickTextAreaAttached(QObject *parent) |
1206 | : QObject(*(new QQuickTextAreaAttachedPrivate), parent) |
1207 | { |
1208 | } |
1209 | |
1210 | /*! |
1211 | \qmlattachedproperty TextArea QtQuick.Controls::TextArea::flickable |
1212 | |
1213 | This property attaches a text area to a \l Flickable. |
1214 | |
1215 | \sa ScrollBar, ScrollIndicator, {Scrollable TextArea} |
1216 | */ |
1217 | QQuickTextArea *QQuickTextAreaAttached::flickable() const |
1218 | { |
1219 | Q_D(const QQuickTextAreaAttached); |
1220 | return d->control; |
1221 | } |
1222 | |
1223 | void QQuickTextAreaAttached::setFlickable(QQuickTextArea *control) |
1224 | { |
1225 | Q_D(QQuickTextAreaAttached); |
1226 | QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(object: parent()); |
1227 | if (!flickable) { |
1228 | qmlWarning(me: parent()) << "TextArea must be attached to a Flickable" ; |
1229 | return; |
1230 | } |
1231 | |
1232 | if (d->control == control) |
1233 | return; |
1234 | |
1235 | if (d->control) |
1236 | QQuickTextAreaPrivate::get(item: d->control)->detachFlickable(); |
1237 | |
1238 | d->control = control; |
1239 | |
1240 | if (control) |
1241 | QQuickTextAreaPrivate::get(item: control)->attachFlickable(item: flickable); |
1242 | |
1243 | emit flickableChanged(); |
1244 | } |
1245 | |
1246 | QT_END_NAMESPACE |
1247 | |