$$PWD/qquicktextcontrol_p_p.h \
$$PWD/qquicktextedit_p.h \
$$PWD/qquicktextedit_p_p.h \
+ $$PWD/qquicktextutil_p.h \
$$PWD/qquickimagebase_p.h \
$$PWD/qquickimagebase_p_p.h \
$$PWD/qquickimage_p.h \
$$PWD/qquicktextinput.cpp \
$$PWD/qquicktextcontrol.cpp \
$$PWD/qquicktextedit.cpp \
+ $$PWD/qquicktextutil.cpp \
$$PWD/qquickimagebase.cpp \
$$PWD/qquickimage.cpp \
$$PWD/qquickborderimage.cpp \
#include "qquickevents_p_p.h"
#include "qquickcanvas.h"
#include "qquicktextnode_p.h"
+#include "qquicktextutil_p.h"
#include <QtQuick/qsgsimplerectnode.h>
#include <QtQml/qqmlinfo.h>
#include <private/qtextengine_p.h>
#include <private/qsgadaptationlayer_p.h>
+
QT_BEGIN_NAMESPACE
/*!
if (oldFont != d->font) {
d->document->setDefaultFont(d->font);
- if (d->cursor) {
- d->cursor->setHeight(QFontMetrics(d->font).height());
+ if (d->cursorItem) {
+ d->cursorItem->setHeight(QFontMetrics(d->font).height());
moveCursorDelegate();
}
updateSize();
if (d->cursorVisible == on)
return;
d->cursorVisible = on;
+ if (on && isComponentComplete())
+ QQuickTextUtil::createCursor(d);
if (!on && !d->persistentSelection)
d->control->setCursorIsFocusIndicator(true);
d->control->setCursorVisible(on);
void QQuickTextEdit::setCursorDelegate(QQmlComponent* c)
{
Q_D(QQuickTextEdit);
- if (d->cursorComponent) {
- if (d->cursor) {
- d->control->setCursorWidth(-1);
- updateCursor();
- delete d->cursor;
- d->cursor = 0;
- }
- }
- d->cursorComponent = c;
- if (c && c->isReady()) {
- loadCursorDelegate();
- } else {
- if (c)
- connect(c, SIGNAL(statusChanged()),
- this, SLOT(loadCursorDelegate()));
- }
-
- emit cursorDelegateChanged();
+ QQuickTextUtil::setCursorDelegate(d, c);
}
-void QQuickTextEdit::loadCursorDelegate()
+void QQuickTextEdit::createCursor()
{
Q_D(QQuickTextEdit);
- if (d->cursorComponent->isLoading() || !isComponentComplete())
- return;
- QQmlContext *creationContext = d->cursorComponent->creationContext();
- QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
- d->cursor = qobject_cast<QQuickItem*>(object);
- if (d->cursor) {
- d->control->setCursorWidth(0);
- updateCursor();
- QQml_setParent_noEvent(d->cursor, this);
- d->cursor->setParentItem(this);
- d->cursor->setHeight(QFontMetrics(d->font).height());
- moveCursorDelegate();
- }else{
- delete object;
- qmlInfo(this) << "Error loading cursor delegate.";
- }
+ d->cursorPending = true;
+ QQuickTextUtil::createCursor(d);
}
/*!
updateSize();
d->dirty = false;
}
- if (d->cursorComponent && d->cursorComponent->isReady())
- loadCursorDelegate();
+ if (d->cursorComponent && isCursorVisible())
+ QQuickTextUtil::createCursor(d);
}
/*!
\qmlproperty bool QtQuick2::TextEdit::selectByMouse
d->determineHorizontalAlignment();
updateInputMethod();
emit cursorRectangleChanged();
- if (!d->cursor)
+ if (!d->cursorItem)
return;
QRectF cursorRect = cursorRectangle();
- d->cursor->setX(cursorRect.x());
- d->cursor->setY(cursorRect.y());
+ d->cursorItem->setX(cursorRect.x());
+ d->cursorItem->setY(cursorRect.y());
}
void QQuickTextEdit::updateSelectionMarkers()
Q_D(const QQuickTextEdit);
QRectF r(0, -d->yoff, d->contentSize.width(), d->contentSize.height());
int cursorWidth = 1;
- if (d->cursor)
+ if (d->cursorItem)
cursorWidth = 0;
else if (!d->document->isEmpty())
cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
Q_D(const QQuickTextEdit);
QRectF r = QQuickImplicitSizeItem::clipRect();
int cursorWidth = 1;
- if (d->cursor)
- cursorWidth = d->cursor->width();
+ if (d->cursorItem)
+ cursorWidth = d->cursorItem->width();
if (!d->document->isEmpty())
cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
void q_textChanged();
void updateSelectionMarkers();
void moveCursorDelegate();
- void loadCursorDelegate();
+ void createCursor();
void q_canPasteChanged();
void updateDocument();
void updateCursor();
QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData);
+ friend class QQuickTextUtil;
+
private:
Q_DISABLE_COPY(QQuickTextEdit)
Q_DECLARE_PRIVATE(QQuickTextEdit)
#include "qquicktextedit_p.h"
#include "qquickimplicitsizeitem_p_p.h"
+#include "qquicktextcontrol_p.h"
#include <QtQml/qqml.h>
class QQuickTextControl;
class QQuickTextEditPrivate : public QQuickImplicitSizeItemPrivate
{
+public:
Q_DECLARE_PUBLIC(QQuickTextEdit)
-public:
+ typedef QQuickTextEdit Public;
+
QQuickTextEditPrivate()
: color(QRgb(0xFF000000)), selectionColor(QRgb(0xFF000080)), selectedTextColor(QRgb(0xFFFFFFFF))
- , textMargin(0.0), yoff(0), font(sourceFont), cursorComponent(0), cursor(0), document(0), control(0)
+ , textMargin(0.0), yoff(0), font(sourceFont), cursorComponent(0), cursorItem(0), document(0), control(0)
, lastSelectionStart(0), lastSelectionEnd(0), lineCount(0)
, hAlign(QQuickTextEdit::AlignLeft), vAlign(QQuickTextEdit::AlignTop)
, format(QQuickTextEdit::PlainText), wrapMode(QQuickTextEdit::NoWrap)
, contentDirection(Qt::LayoutDirectionAuto)
, mouseSelectionMode(QQuickTextEdit::SelectCharacters), inputMethodHints(Qt::ImhNone)
, updateType(UpdatePaintNode)
- , documentDirty(true), dirty(false), richText(false), cursorVisible(false)
+ , documentDirty(true), dirty(false), richText(false), cursorVisible(false), cursorPending(false)
, focusOnPress(true), persistentSelection(false), requireImplicitWidth(false)
, selectByMouse(false), canPaste(false), canPasteValid(false), hAlignImplicit(true)
, textCached(false), inLayout(false)
qreal getImplicitWidth() const;
Qt::LayoutDirection textDirection(const QString &text) const;
+ void setNativeCursorEnabled(bool enabled) { control->setCursorWidth(enabled ? 1 : 0); }
+
QColor color;
QColor selectionColor;
QColor selectedTextColor;
QFont font;
QQmlComponent* cursorComponent;
- QQuickItem* cursor;
+ QQuickItem* cursorItem;
QQuickTextDocumentWithImageResources *document;
QQuickTextControl *control;
bool dirty : 1;
bool richText : 1;
bool cursorVisible : 1;
+ bool cursorPending : 1;
bool focusOnPress : 1;
bool persistentSelection : 1;
bool requireImplicitWidth:1;
#include "qquicktextinput_p.h"
#include "qquicktextinput_p_p.h"
#include "qquickcanvas.h"
+#include "qquicktextutil_p.h"
#include <private/qqmlglobal_p.h>
+
#include <QtCore/qcoreapplication.h>
#include <QtQml/qqmlinfo.h>
#include <QtGui/qevent.h>
d->checkIsValid();
d->updateLayout();
updateCursorRectangle();
- if (d->cursorComponent && d->cursorComponent->isReady())
- createCursor();
+ if (d->cursorComponent && isCursorVisible())
+ QQuickTextUtil::createCursor(d);
}
/*!
if (d->cursorVisible == on)
return;
d->cursorVisible = on;
- d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
- d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
- update();
+ if (on && isComponentComplete())
+ QQuickTextUtil::createCursor(d);
+ if (!d->cursorItem) {
+ d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
+ d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
+ update();
+ }
emit cursorVisibleChanged(d->cursorVisible);
}
void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
{
Q_D(QQuickTextInput);
- if (d->cursorComponent == c)
- return;
-
- d->cursorComponent = c;
- if (!c) {
- //note that the components are owned by something else
- delete d->cursorItem;
- d->cursorItem = 0;
- } else {
- d->startCreatingCursor();
- }
-
- emit cursorDelegateChanged();
-}
-
-void QQuickTextInputPrivate::startCreatingCursor()
-{
- Q_Q(QQuickTextInput);
- if (cursorComponent->isReady()) {
- q->createCursor();
- } else if (cursorComponent->isLoading()) {
- q->connect(cursorComponent, SIGNAL(statusChanged(int)),
- q, SLOT(createCursor()));
- } else { // isError
- qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
- }
+ QQuickTextUtil::setCursorDelegate(d, c);
}
void QQuickTextInput::createCursor()
{
Q_D(QQuickTextInput);
- if (!isComponentComplete())
- return;
-
- if (d->cursorComponent->isError()) {
- qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
- return;
- }
-
- if (!d->cursorComponent->isReady())
- return;
-
- if (d->cursorItem)
- delete d->cursorItem;
- QQmlContext *creationContext = d->cursorComponent->creationContext();
- QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
- d->cursorItem = qobject_cast<QQuickItem*>(object);
- if (!d->cursorItem) {
- delete object;
- qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
- return;
- }
-
- QRectF r = cursorRectangle();
-
- QQml_setParent_noEvent(d->cursorItem, this);
- d->cursorItem->setParentItem(this);
- d->cursorItem->setPos(r.topLeft());
- d->cursorItem->setHeight(r.height());
+ d->cursorPending = true;
+ QQuickTextUtil::createCursor(d);
}
/*!
m_textLayout.setPreeditArea(m_cursor, event->preeditString());
#endif //QT_NO_IM
const int oldPreeditCursor = m_preeditCursor;
- const bool oldCursorVisible = cursorVisible;
m_preeditCursor = event->preeditString().length();
hasImState = !event->preeditString().isEmpty();
- cursorVisible = true;
+ bool cursorVisible = true;
QList<QTextLayout::FormatRange> formats;
for (int i = 0; i < event->attributes().size(); ++i) {
const QInputMethodEvent::Attribute &a = event->attributes().at(i);
if (isGettingInput)
finishChange(priorState);
- if (cursorVisible != oldCursorVisible)
- emit q->cursorVisibleChanged(cursorVisible);
+ q->setCursorVisible(cursorVisible);
if (selectionChange) {
emit q->selectionChanged();
void triggerPreprocess();
private:
+ friend class QQuickTextUtil;
+
Q_DECLARE_PRIVATE(QQuickTextInput)
};
class Q_AUTOTEST_EXPORT QQuickTextInputPrivate : public QQuickImplicitSizeItemPrivate
{
- Q_DECLARE_PUBLIC(QQuickTextInput)
public:
+ Q_DECLARE_PUBLIC(QQuickTextInput)
+
+ typedef QQuickTextInput Public;
+
QQuickTextInputPrivate()
: hscroll(0)
, vscroll(0)
, m_passwordCharacter(QLatin1Char('*'))
, focusOnPress(true)
, cursorVisible(false)
+ , cursorPending(false)
, autoScroll(true)
, selectByMouse(false)
, canPaste(false)
bool focusOnPress:1;
bool cursorVisible:1;
+ bool cursorPending:1;
bool autoScroll:1;
bool selectByMouse:1;
bool canPaste:1;
return !tripleClickTimer.hasExpired(qApp->styleHints()->mouseDoubleClickInterval());
}
+ void setNativeCursorEnabled(bool enabled) {
+ setCursorBlinkPeriod(enabled && cursorVisible ? qApp->styleHints()->cursorFlashTime() : 0); }
int nextMaskBlank(int pos)
{
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktextutil_p.h"
+
+#include <QtQml/qqmlinfo.h>
+
+#include <private/qqmlglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickItem *QQuickTextUtil::createCursor(
+ QQmlComponent *component, QQuickItem *parent, const QRectF &rectangle, const char *className)
+{
+ QQuickItem *item = 0;
+ if (component->isReady()) {
+ QQmlContext *creationContext = component->creationContext();
+
+ if (QObject *object = component->beginCreate(creationContext
+ ? creationContext
+ : qmlContext(parent))) {
+ if ((item = qobject_cast<QQuickItem *>(object))) {
+ QQml_setParent_noEvent(item, parent);
+ item->setParentItem(parent);
+ item->setPos(rectangle.topLeft());
+ item->setHeight(rectangle.height());
+ } else {
+ qmlInfo(parent) << tr("%1 does not support loading non-visual cursor delegates.")
+ .arg(QString::fromUtf8(className));
+ }
+ component->completeCreate();
+ return item;
+ }
+ } else if (component->isLoading()) {
+ QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
+ parent, SLOT(createCursor()), Qt::UniqueConnection);
+ return item;
+ }
+ qmlInfo(parent, component->errors()) << tr("Could not load cursor delegate");
+ return item;
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTEXTUTIL_P_H
+#define QQUICKTEXTUTIL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlincubator.h>
+#include <QtQuick/qquickitem.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTextUtil : public QObject // For the benefit of translations.
+{
+ Q_OBJECT
+public:
+ template <typename Private> static void setCursorDelegate(Private *d, QQmlComponent *delegate);
+ template <typename Private> static void createCursor(Private *d);
+
+private:
+ static QQuickItem *createCursor(
+ QQmlComponent *component,
+ QQuickItem *parent,
+ const QRectF &cursorRectangle,
+ const char *className);
+};
+
+template <typename Private>
+void QQuickTextUtil::setCursorDelegate(Private *d, QQmlComponent *delegate)
+{
+ if (d->cursorComponent == delegate)
+ return;
+
+ typename Private::Public *parent = d->q_func();
+
+ if (d->cursorComponent) {
+ disconnect(d->cursorComponent, SIGNAL(statusChanged(QQmlComponent::Status)),
+ parent, SLOT(createCursor()));
+ }
+
+ delete d->cursorItem;
+ d->cursorItem = 0;
+ d->cursorPending = true;
+
+ d->cursorComponent = delegate;
+
+ if (parent->isCursorVisible() && parent->isComponentComplete())
+ createCursor(d);
+
+ emit parent->cursorDelegateChanged();
+}
+
+template <typename Private>
+void QQuickTextUtil::createCursor(Private *d)
+{
+ if (!d->cursorPending)
+ return;
+
+ d->cursorPending = false;
+
+ typename Private::Public *parent = d->q_func();
+ if (d->cursorComponent) {
+ d->cursorItem = createCursor(
+ d->cursorComponent,
+ parent,
+ parent->cursorRectangle(),
+ Private::Public::staticMetaObject.className());
+ }
+
+ d->setNativeCursorEnabled(!d->cursorItem);
+ d->updateType = Private::UpdatePaintNode;
+ parent->update();
+}
+
+QT_END_NAMESPACE
+
+#endif
]
TextEdit {
cursorDelegate: cursorFail
+ cursorVisible: true
}
TextEdit {
cursorDelegate: cursorWait
+ cursorVisible: true
}
TextEdit {
cursorDelegate: cursorNorm
+ cursorVisible: true
}
TextEdit {
cursorDelegate: cursorErr
+ cursorVisible: true
}
}
]
TextEdit {
cursorDelegate: cursorFail
+ cursorVisible: true
}
TextEdit {
cursorDelegate: cursorWait
+ cursorVisible: true
}
TextEdit {
cursorDelegate: cursorNorm
+ cursorVisible: true
}
}
]
TextEdit {
cursorDelegate: cursorWait
+ cursorVisible: true
}
TextEdit {
cursorDelegate: cursorNorm
+ cursorVisible: true
}
TextEdit {
cursorDelegate: cursorErr
+ cursorVisible: true
}
}
TextEdit {
cursorDelegate: cursorWait
text: "Hello"
+ cursorVisible: true
}
TextEdit {
objectName: "textEditObject"
cursorDelegate: cursorNorm
+ cursorVisible: true
focus: true;
text: "Hello"
}
view.requestActivateWindow();
QQuickTextEdit *textEditObject = view.rootObject()->findChild<QQuickTextEdit*>("textEditObject");
QVERIFY(textEditObject != 0);
- QVERIFY(textEditObject->findChild<QQuickItem*>("cursorInstance"));
+ // Delegate creation is deferred until focus in or cursor visiblity is forced.
+ QVERIFY(!textEditObject->findChild<QQuickItem*>("cursorInstance"));
+ QVERIFY(!textEditObject->isCursorVisible());
//Test Delegate gets created
textEditObject->setFocus(true);
+ QVERIFY(textEditObject->isCursorVisible());
QQuickItem* delegateObject = textEditObject->findChild<QQuickItem*>("cursorInstance");
QVERIFY(delegateObject);
QCOMPARE(delegateObject->property("localProperty").toString(), QString("Hello"));
cursorComponent.setData("import QtQuick 2.0\nRectangle { height: 20; width: 8 }", QUrl());
edit->setCursorDelegate(&cursorComponent);
+ edit->setCursorVisible(true);
// If a cursor delegate is used it's size should determine the excess width.
QCOMPARE(edit->clipRect().x(), qreal(0));
cursorComponent.setData("import QtQuick 2.0\nRectangle { height: 20; width: 8 }", QUrl());
edit->setCursorDelegate(&cursorComponent);
+ edit->setCursorVisible(true);
// Don't include the size of a cursor delegate as it has its own bounding rect.
QCOMPARE(edit->boundingRect().x(), qreal(0));
cursorComponent.setData("import QtQuick 2.0\nRectangle { height: 20; width: 8 }", QUrl());
input->setCursorDelegate(&cursorComponent);
+ input->setCursorVisible(true);
// If a cursor delegate is used it's size should determine the excess width.
QCOMPARE(input->clipRect().x(), qreal(0));
cursorComponent.setData("import QtQuick 2.0\nRectangle { height: 20; width: 8 }", QUrl());
input->setCursorDelegate(&cursorComponent);
+ input->setCursorVisible(true);
// Don't include the size of a cursor delegate as it has its own bounding rect.
QCOMPARE(input->boundingRect().x(), input->width() - line.naturalTextWidth());
view.requestActivateWindow();
QQuickTextInput *textInputObject = view.rootObject()->findChild<QQuickTextInput*>("textInputObject");
QVERIFY(textInputObject != 0);
- QVERIFY(textInputObject->findChild<QQuickItem*>("cursorInstance"));
+ // Delegate is created on demand, and so won't be available immediately. Focus in or
+ // setCursorVisible(true) will trigger creation.
+ QTRY_VERIFY(!textInputObject->findChild<QQuickItem*>("cursorInstance"));
+ QVERIFY(!textInputObject->isCursorVisible());
//Test Delegate gets created
textInputObject->setFocus(true);
+ QVERIFY(textInputObject->isCursorVisible());
QQuickItem* delegateObject = textInputObject->findChild<QQuickItem*>("cursorInstance");
QVERIFY(delegateObject);
QCOMPARE(delegateObject->property("localProperty").toString(), QString("Hello"));
QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x());
QCOMPARE(textInputObject->cursorRectangle().y(), delegateObject->y());
-
// Test delegate gets moved on mouse press.
textInputObject->setSelectByMouse(true);
textInputObject->setCursorPosition(0);