From bb11493327c3c5f351261edb64813a8ed0fc8bd6 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 8 Jul 2009 10:10:52 +1000 Subject: Support custom string convertors for animations. --- src/declarative/util/qmlanimation.cpp | 29 +++++++++++++++++------------ src/declarative/util/qmlanimation_p.h | 2 +- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp index c0d6481..5dfaa7f 100644 --- a/src/declarative/util/qmlanimation.cpp +++ b/src/declarative/util/qmlanimation.cpp @@ -1436,11 +1436,11 @@ void QmlParallelAnimation::transition(QmlStateActions &actions, QML_DEFINE_TYPE(QmlParallelAnimation,ParallelAnimation) //convert a variant from string type to another animatable type -//### should use any registered string convertor -void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, QVariant::Type type) +void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, int type) { if (variant.type() != QVariant::String) { - variant.convert(type); + if ((uint)type < QVariant::UserType) + variant.convert((QVariant::Type)type); return; } @@ -1474,7 +1474,12 @@ void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, QVariant::Ty break; } default: - variant.convert(type); + if ((uint)type >= QVariant::UserType) { + QmlMetaType::StringConverter converter = QmlMetaType::customStringConverter(type); + if (converter) + variant.setValue(converter(variant.toString())); + } else + variant.convert((QVariant::Type)type); break; } } @@ -1722,7 +1727,7 @@ void QmlPropertyAnimationPrivate::valueChanged(qreal r) if (!fromSourced) { if (!fromIsDefined) { from = property.read(); - convertVariant(from, (QVariant::Type)(interpolatorType ? interpolatorType : property.propertyType())); + convertVariant(from, interpolatorType ? interpolatorType : property.propertyType()); //### check for invalid variant if using property type } fromSourced = true; @@ -1751,9 +1756,9 @@ void QmlPropertyAnimation::prepare(QmlMetaProperty &p) d->property = d->userProperty; int propType = d->property.propertyType(); - d->convertVariant(d->to, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : propType)); + d->convertVariant(d->to, d->interpolatorType ? d->interpolatorType : propType); if (d->fromIsDefined) - d->convertVariant(d->from, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : propType)); + d->convertVariant(d->from, d->interpolatorType ? d->interpolatorType : propType); if (!d->interpolatorType) { //### check for invalid variants @@ -1795,7 +1800,7 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, if (action.fromValue.isNull()) { action.fromValue = action.property.read(); if (interpolatorType) - QmlPropertyAnimationPrivate::convertVariant(action.fromValue, (QVariant::Type)interpolatorType); + QmlPropertyAnimationPrivate::convertVariant(action.fromValue, interpolatorType); } if (!interpolatorType) { int propType = action.property.propertyType(); @@ -1856,8 +1861,8 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, if (d->toIsDefined) myAction.toValue = d->to; - d->convertVariant(myAction.fromValue, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); - d->convertVariant(myAction.toValue, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); + d->convertVariant(myAction.fromValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); + d->convertVariant(myAction.toValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); modified << action.property; @@ -1875,10 +1880,10 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, continue; if (d->fromIsDefined) { - d->convertVariant(d->from, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); + d->convertVariant(d->from, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); myAction.fromValue = d->from; } - d->convertVariant(d->to, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); + d->convertVariant(d->to, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); myAction.toValue = d->to; data->actions << myAction; } diff --git a/src/declarative/util/qmlanimation_p.h b/src/declarative/util/qmlanimation_p.h index 00759e1..87d480f 100644 --- a/src/declarative/util/qmlanimation_p.h +++ b/src/declarative/util/qmlanimation_p.h @@ -346,7 +346,7 @@ public: QmlTimeLineValueProxy value; static QVariant interpolateVariant(const QVariant &from, const QVariant &to, qreal progress); - static void convertVariant(QVariant &variant, QVariant::Type type); + static void convertVariant(QVariant &variant, int type); }; QT_END_NAMESPACE -- cgit v0.12 From 46688b1e8b953f9e3a12d42b9aa73a8eba904f5b Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 8 Jul 2009 11:12:20 +1000 Subject: Fix custom string convertors for animations. --- src/declarative/util/qmlanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp index 5dfaa7f..ff070c1 100644 --- a/src/declarative/util/qmlanimation.cpp +++ b/src/declarative/util/qmlanimation.cpp @@ -1477,7 +1477,7 @@ void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, int type) if ((uint)type >= QVariant::UserType) { QmlMetaType::StringConverter converter = QmlMetaType::customStringConverter(type); if (converter) - variant.setValue(converter(variant.toString())); + variant = converter(variant.toString()); } else variant.convert((QVariant::Type)type); break; -- cgit v0.12 From 69bf65348194ab339575aa0743832c1960e22962 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 8 Jul 2009 12:49:52 +1000 Subject: Add Cursor Delegate to QFxTextEdit Adds the cursorDelegate property, including docs and autotest. No example is included because we don't really have a text example yet. --- src/declarative/fx/qfxtextedit.cpp | 70 +++++++++++++++++++ src/declarative/fx/qfxtextedit.h | 6 ++ src/declarative/fx/qfxtextedit_p.h | 4 +- .../declarative/qfxtextedit/tst_qfxtextedit.cpp | 80 ++++++++++++++++++++++ 4 files changed, 159 insertions(+), 1 deletion(-) diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index 7162bdf..bfcc17f 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -454,6 +454,66 @@ void QFxTextEdit::setCursorPosition(int pos) } /*! + \qmlproperty TextEdit::cursorDelegate + \brief The delegate for the cursor in the TextEdit. + + If you set a cursorDelegate for a TextEdit, this delegate will be used for + drawing the cursor instead of the standard cursor. An instance of the + delegate will be created and managed by the text edit when a cursor is + needed, and the x and y properties of delegate instance will be set so as + to be one pixel before the top left of the current character. + + Note that the root item of the delegate component must be a QFxItem or + QFxItem derived item. +*/ +QmlComponent* QFxTextEdit::cursorDelegate() const +{ + Q_D(const QFxTextEdit); + return d->cursorComponent; +} + +void QFxTextEdit::setCursorDelegate(QmlComponent* c) +{ + Q_D(QFxTextEdit); + if(d->cursorComponent){ + delete d->cursorComponent; + if(d->cursor){ + disconnect(d->control, SIGNAL(cursorPositionChanged()), + this, SLOT(moveCursorDelegate())); + d->control->setCursorWidth(-1); + dirtyCache(cursorRect()); + delete d->cursor; + d->cursor = 0; + } + } + d->cursorComponent = c; + if(c && c->isReady()){ + loadCursorDelegate(); + }else{ + connect(c, SIGNAL(statusChanged()), + this, SLOT(loadCursorDelegate())); + } +} + +void QFxTextEdit::loadCursorDelegate() +{ + Q_D(QFxTextEdit); + if(d->cursorComponent->isLoading()) + return; + d->cursor = qobject_cast(d->cursorComponent->create(qmlContext(this))); + if(d->cursor){ + connect(d->control, SIGNAL(cursorPositionChanged()), + this, SLOT(moveCursorDelegate())); + d->control->setCursorWidth(0); + dirtyCache(cursorRect()); + d->cursor->setItemParent(this); + moveCursorDelegate(); + }else{ + qWarning() << "Error loading cursor delegate for TextEdit:" + objectName(); + } +} + +/*! \qmlproperty bool TextEdit::focusOnPress Whether the TextEdit should gain focus on a mouse press. By default this is @@ -896,6 +956,16 @@ void QFxTextEdit::q_textChanged() emit textChanged(text()); } +void QFxTextEdit::moveCursorDelegate() +{ + Q_D(QFxTextEdit); + if(!d->cursor) + return; + QRectF cursorRect = d->control->cursorRect(); + d->cursor->setX(cursorRect.x()); + d->cursor->setY(cursorRect.y()); +} + //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't // need to do all the calculations each time void QFxTextEdit::updateSize() diff --git a/src/declarative/fx/qfxtextedit.h b/src/declarative/fx/qfxtextedit.h index 6988822..4934743 100644 --- a/src/declarative/fx/qfxtextedit.h +++ b/src/declarative/fx/qfxtextedit.h @@ -78,6 +78,7 @@ class Q_DECLARATIVE_EXPORT QFxTextEdit : public QFxPaintedItem Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly) Q_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible) Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition) + Q_PROPERTY(QmlComponent* cursorDelegate READ cursorDelegate WRITE setCursorDelegate); Q_PROPERTY(bool focusOnPress READ focusOnPress WRITE setFocusOnPress) Q_PROPERTY(bool preserveSelection READ preserveSelection WRITE setPreserveSelection) Q_PROPERTY(qreal textMargin READ textMargin WRITE setTextMargin) @@ -133,6 +134,9 @@ public: int cursorPosition() const; void setCursorPosition(int pos); + QmlComponent* cursorDelegate() const; + void setCursorDelegate(QmlComponent*); + bool focusOnPress() const; void setFocusOnPress(bool on); @@ -176,6 +180,8 @@ private Q_SLOTS: void fontChanged(); void updateImgCache(const QRectF &rect); void q_textChanged(); + void moveCursorDelegate(); + void loadCursorDelegate(); private: void updateSize(); diff --git a/src/declarative/fx/qfxtextedit_p.h b/src/declarative/fx/qfxtextedit_p.h index f733a4c..d3b9c08 100644 --- a/src/declarative/fx/qfxtextedit_p.h +++ b/src/declarative/fx/qfxtextedit_p.h @@ -70,7 +70,7 @@ public: QFxTextEditPrivate() : font(0), color("black"), imgDirty(true), hAlign(QFxTextEdit::AlignLeft), vAlign(QFxTextEdit::AlignTop), dirty(false), wrap(false), richText(false), cursorVisible(false), focusOnPress(false), preserveSelection(true), - textMargin(0.0), format(QFxTextEdit::AutoText), document(0) + textMargin(0.0), cursor(0), cursorComponent(0), format(QFxTextEdit::AutoText), document(0) { } @@ -100,6 +100,8 @@ public: bool focusOnPress; bool preserveSelection; qreal textMargin; + QmlComponent* cursorComponent; + QFxItem* cursor; QFxTextEdit::TextFormat format; QTextDocument *document; QTextControl *control; diff --git a/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp b/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp index 7be5b50..b498b14 100644 --- a/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp +++ b/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -23,6 +25,8 @@ private slots: void font(); void color(); + void cursorDelegate(); + private: QStringList standard; QStringList richText; @@ -38,6 +42,38 @@ private: QmlEngine engine; }; +/* + Find an item with the specified id. If index is supplied then the + item must also evaluate the {index} expression equal to index + + Copied from ListView test +*/ +template +T *findItem(QFxItem *parent, const QString &id, int index=0) +{ + const QMetaObject &mo = T::staticMetaObject; + qDebug() << parent->children()->count() << "children"; + for (int i = 0; i < parent->children()->count(); ++i) { + QFxItem *item = parent->children()->at(i); + qDebug() << "try" << item; + if (mo.cast(item) && (id.isEmpty() || item->id() == id)) { + if (index != -1) { + QmlExpression e(qmlContext(item), "index", item); + e.setTrackChange(false); + if (e.value().toInt() == index) + return static_cast(item); + } else { + return static_cast(item); + } + } + item = findItem(item, id, index); + if (item) + return static_cast(item); + } + + return 0; +} + tst_qfxtextedit::tst_qfxtextedit() { standard << "the quick brown fox jumped over the lazy dog" @@ -124,6 +160,7 @@ void tst_qfxtextedit::width() QmlComponent texteditComponent(&engine, "TextEdit { text: \"\" }"); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE(textEditObject->width(), 0.); } @@ -137,6 +174,7 @@ void tst_qfxtextedit::width() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE(textEditObject->width(), qreal(metricWidth)); } @@ -152,6 +190,7 @@ void tst_qfxtextedit::width() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE(textEditObject->width(), qreal(documentWidth)); } } @@ -163,6 +202,7 @@ void tst_qfxtextedit::wrap() QmlComponent texteditComponent(&engine, "TextEdit { text: \"\"; wrap: true; width: 300 }"); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE(textEditObject->width(), 300.); } @@ -172,6 +212,7 @@ void tst_qfxtextedit::wrap() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE(textEditObject->width(), 300.); } @@ -181,6 +222,7 @@ void tst_qfxtextedit::wrap() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE(textEditObject->width(), 300.); } @@ -199,6 +241,7 @@ void tst_qfxtextedit::hAlign() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE((int)textEditObject->hAlign(), (int)hAlignments.at(j)); } } @@ -211,6 +254,7 @@ void tst_qfxtextedit::hAlign() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE((int)textEditObject->hAlign(), (int)hAlignments.at(j)); } } @@ -229,6 +273,7 @@ void tst_qfxtextedit::vAlign() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE((int)textEditObject->vAlign(), (int)vAlignments.at(j)); } } @@ -241,6 +286,7 @@ void tst_qfxtextedit::vAlign() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE((int)textEditObject->vAlign(), (int)vAlignments.at(j)); } } @@ -255,6 +301,7 @@ void tst_qfxtextedit::font() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE(textEditObject->font()->size(), qreal(40)); QCOMPARE(textEditObject->font()->bold(), false); QCOMPARE(textEditObject->font()->italic(), false); @@ -265,6 +312,7 @@ void tst_qfxtextedit::font() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE(textEditObject->font()->bold(), true); QCOMPARE(textEditObject->font()->italic(), false); } @@ -274,6 +322,7 @@ void tst_qfxtextedit::font() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE(textEditObject->font()->italic(), true); QCOMPARE(textEditObject->font()->bold(), false); } @@ -283,6 +332,7 @@ void tst_qfxtextedit::font() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE(textEditObject->font()->family(), QString("Helvetica")); QCOMPARE(textEditObject->font()->bold(), false); QCOMPARE(textEditObject->font()->italic(), false); @@ -293,6 +343,7 @@ void tst_qfxtextedit::font() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE(textEditObject->font()->family(), QString("")); } } @@ -306,6 +357,7 @@ void tst_qfxtextedit::color() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); //qDebug() << "textEditObject: " << textEditObject->color() << "vs. " << QColor(colorStrings.at(i)); + QVERIFY(textEditObject != 0); QCOMPARE(textEditObject->color(), QColor(colorStrings.at(i))); } @@ -318,9 +370,37 @@ void tst_qfxtextedit::color() QmlComponent texteditComponent(&engine, componentStr.toLatin1()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); QCOMPARE(textEditObject->color(), testColor); } } + +void tst_qfxtextedit::cursorDelegate() +{ + QString componentStr = "TextEdit { text: \""+ standard[1] +"\"; focusable: true; resources [ Component { id:cursor; Item { id:cursorInstance } } ] cursorDelegate: cursor}"; + QTest::qWait(10000); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); + QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); + QVERIFY(!findItem(textEditObject, "cursorInstance")); + //Test Delegate gets created + textEditObject->setFocus(true); + QFxItem* delegateObject = findItem(textEditObject, "cursorInstance"); + QVERIFY(delegateObject); + //Test Delegate gets moved + for(int i=0; i<= standard[1].size(); i++){ + textEditObject->setCursorPosition(i); + QCOMPARE(textEditObject->cursorRect().x(), qRound(delegateObject->x())); + QCOMPARE(textEditObject->cursorRect().y(), qRound(delegateObject->y())); + } + textEditObject->setCursorPosition(0); + QCOMPARE(textEditObject->cursorRect().x(), qRound(delegateObject->x())); + QCOMPARE(textEditObject->cursorRect().y(), qRound(delegateObject->y())); + //Test Delegate gets deleted + textEditObject->setCursorDelegate(0); + QVERIFY(!findItem(textEditObject, "cursorInstance")); +} + QTEST_MAIN(tst_qfxtextedit) #include "tst_qfxtextedit.moc" -- cgit v0.12 From 6259c9fbc4719994bd491271eba5c47143df67c6 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 8 Jul 2009 15:13:32 +1000 Subject: Add highlightedTextColor property to the QFxTextEdit sophisticate --- src/declarative/fx/qfxtextedit.cpp | 30 ++++++++++++++++++++++++++++++ src/declarative/fx/qfxtextedit.h | 4 ++++ src/declarative/fx/qfxtextedit_p.h | 1 + 3 files changed, 35 insertions(+) diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index bfcc17f..9854906 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -324,6 +324,36 @@ void QFxTextEdit::setHighlightColor(const QColor &color) } /*! + \qmlproperty color TextEdit::highlightedTextColor + + The highlighted text color, used in selections. +*/ + +/*! + \property QFxTextEdit::highlightedTextColor + \brief the text edit's default highlighted text color +*/ +QColor QFxTextEdit::highlightedTextColor() const +{ + Q_D(const QFxTextEdit); + return d->highlightColor; +} + +void QFxTextEdit::setHighlightedTextColor(const QColor &color) +{ + Q_D(QFxTextEdit); + if (d->highlightedTextColor == color) + return; + + clearCache(); + d->highlightedTextColor = color; + QPalette pal = d->control->palette(); + pal.setColor(QPalette::HighlightedText, color); + d->control->setPalette(pal); + update(); +} + +/*! \qmlproperty enumeration TextEdit::hAlign \qmlproperty enumeration TextEdit::vAlign diff --git a/src/declarative/fx/qfxtextedit.h b/src/declarative/fx/qfxtextedit.h index 4934743..b29993e 100644 --- a/src/declarative/fx/qfxtextedit.h +++ b/src/declarative/fx/qfxtextedit.h @@ -70,6 +70,7 @@ class Q_DECLARATIVE_EXPORT QFxTextEdit : public QFxPaintedItem Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QColor color READ color WRITE setColor) Q_PROPERTY(QColor highlightColor READ highlightColor WRITE setHighlightColor) + Q_PROPERTY(QColor highlightedTextColor READ highlightedTextColor WRITE setHighlightedTextColor) Q_PROPERTY(QmlFont * font READ font) Q_PROPERTY(HAlignment hAlign READ hAlign WRITE setHAlign) Q_PROPERTY(VAlignment vAlign READ vAlign WRITE setVAlign) @@ -119,6 +120,9 @@ public: QColor highlightColor() const; void setHighlightColor(const QColor &c); + QColor highlightedTextColor() const; + void setHighlightedTextColor(const QColor &c); + HAlignment hAlign() const; void setHAlign(HAlignment align); diff --git a/src/declarative/fx/qfxtextedit_p.h b/src/declarative/fx/qfxtextedit_p.h index d3b9c08..f92dd60 100644 --- a/src/declarative/fx/qfxtextedit_p.h +++ b/src/declarative/fx/qfxtextedit_p.h @@ -83,6 +83,7 @@ public: QmlFont font; QColor color; QColor highlightColor; + QColor highlightedTextColor; QString style; QColor styleColor; bool imgDirty; -- cgit v0.12 From f727b2fd8d29907f59e11fc18c48329588fa4284 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 8 Jul 2009 16:00:36 +1000 Subject: Browser UI improvements. --- examples/declarative/loader/Browser.qml | 42 ++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/examples/declarative/loader/Browser.qml b/examples/declarative/loader/Browser.qml index 640ea0c..280273b 100644 --- a/examples/declarative/loader/Browser.qml +++ b/examples/declarative/loader/Browser.qml @@ -5,17 +5,23 @@ Rect { FolderListModel { id: folders nameFilters: [ "*.qml" ] +// folder: "E:" } Component { id: FolderDelegate - Text { + Rect { id: Wrapper width: Root.width - text: fileName - font.bold: true - font.size: 14 + height: NameText.height + Text { + id: NameText + text: fileName + font.bold: true + font.size: 12 + } MouseRegion { + id: Mouse anchors.fill: parent onClicked: { if (folders.isFolder(index)) { @@ -25,17 +31,41 @@ Rect { } } } + states: [ + State { + name: "pressed" + when: Mouse.pressed + SetProperties { target: Wrapper; color: "#bbbbbb" } + } + ] } } - Text { id: DirText; text: folders.folder } + Script { + function up(path) { + var pos = path.toString().lastIndexOf("/"); + return path.toString().substring(0, pos); + } + } + + Rect { + id: UpButton + width: 30 + height: UpText.height + color: "grey" + MouseRegion { anchors.fill: parent; onClicked: folders.folder = up(folders.folder) } + Text { id: UpText; text: "Up" } + } + + Text { anchors.left: UpButton.right; text: folders.folder } ListView { - anchors.top: DirText.bottom + anchors.top: UpButton.bottom anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom model: folders delegate: FolderDelegate + clip: true } } -- cgit v0.12 From 239c3581bb84b6484547918fbb1672fed08970dd Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 8 Jul 2009 16:11:21 +1000 Subject: Add a modulus property to Follow to allow "wrapping". Also add clock example to demonstrate. --- examples/declarative/clock/Clock.qml | 78 ++++++++++++++++++++++++++++++ examples/declarative/clock/background.png | Bin 0 -> 46895 bytes examples/declarative/clock/display.qml | 5 ++ examples/declarative/clock/hour.png | Bin 0 -> 391 bytes examples/declarative/clock/minute.png | Bin 0 -> 445 bytes examples/declarative/clock/second.png | Bin 0 -> 345 bytes src/declarative/util/qmlfollow.cpp | 57 ++++++++++++++++++++-- src/declarative/util/qmlfollow.h | 4 ++ 8 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 examples/declarative/clock/Clock.qml create mode 100644 examples/declarative/clock/background.png create mode 100644 examples/declarative/clock/display.qml create mode 100644 examples/declarative/clock/hour.png create mode 100644 examples/declarative/clock/minute.png create mode 100644 examples/declarative/clock/second.png diff --git a/examples/declarative/clock/Clock.qml b/examples/declarative/clock/Clock.qml new file mode 100644 index 0000000..4779bd5 --- /dev/null +++ b/examples/declarative/clock/Clock.qml @@ -0,0 +1,78 @@ +Item { + id: Clock + width: 200; height: 200 + property var time + property var hours + property var minutes + property var seconds + onTimeChanged: { + var date = new Date; + hours = date.getHours(); + minutes = date.getMinutes(); + seconds = date.getSeconds(); + } + Timer { + interval: 500; running: true; repeat: true; triggeredOnStart: true + onTriggered: Clock.time = new Date() + } + + Image { source: "background.png" } + Image { + x: 95 + y: 54 + source: "hour.png" + smooth: true + transform: Rotation { + id: HourRotation + originX: 4; originY: 45 + angle: 0 + angle: Follow { + spring: 2 + damping: .2 + source: Clock.hours * 50 * 3 + Clock.minutes / 2 + } + } + } + Image { + x: 95 + y: 30 + source: "minute.png" + smooth: true + transform: Rotation { + id: MinuteRotation + originX: 4; originY: 70 + angle: 0 + angle: Follow { + spring: 2 + damping: .2 + source: Clock.minutes * 6 + } + } + } + Image { + x: 96 + y: 40 + source: "second.png" + smooth: true + transform: Rotation { + id: SecondRotation + originX: 2; originY: 60 + angle: 0 + angle: Follow { + spring: 5 + damping: .25 + modulus: 360 + source: Clock.seconds * 6 + } + } + } + + Rect { + x: 93 + y: 94 + width: 11 + height: 11 + radius: 5 + color: "black" + } +} diff --git a/examples/declarative/clock/background.png b/examples/declarative/clock/background.png new file mode 100644 index 0000000..a885950 Binary files /dev/null and b/examples/declarative/clock/background.png differ diff --git a/examples/declarative/clock/display.qml b/examples/declarative/clock/display.qml new file mode 100644 index 0000000..0187a7e --- /dev/null +++ b/examples/declarative/clock/display.qml @@ -0,0 +1,5 @@ +Rect { + width: contents.width + height: contents.height + Clock { id: Clock } +} diff --git a/examples/declarative/clock/hour.png b/examples/declarative/clock/hour.png new file mode 100644 index 0000000..603466b Binary files /dev/null and b/examples/declarative/clock/hour.png differ diff --git a/examples/declarative/clock/minute.png b/examples/declarative/clock/minute.png new file mode 100644 index 0000000..0207405 Binary files /dev/null and b/examples/declarative/clock/minute.png differ diff --git a/examples/declarative/clock/second.png b/examples/declarative/clock/second.png new file mode 100644 index 0000000..bfcef68 Binary files /dev/null and b/examples/declarative/clock/second.png differ diff --git a/src/declarative/util/qmlfollow.cpp b/src/declarative/util/qmlfollow.cpp index c6d806a..b8e6685 100644 --- a/src/declarative/util/qmlfollow.cpp +++ b/src/declarative/util/qmlfollow.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include +#include #include #include "private/qobject_p.h" #include "qmlfollow.h" @@ -55,7 +56,7 @@ class QmlFollowPrivate : public QObjectPrivate public: QmlFollowPrivate() : sourceValue(0), maxVelocity(0), lastTime(0) - , mass(1.0), spring(0.), damping(0.), velocity(0), epsilon(0.005), enabled(true), mode(Track), clock(this) {} + , mass(1.0), spring(0.), damping(0.), velocity(0), epsilon(0.005), modulus(0.0), enabled(true), mode(Track), clock(this) {} QmlMetaProperty property; qreal currentValue; @@ -68,6 +69,7 @@ public: qreal damping; qreal velocity; qreal epsilon; + qreal modulus; bool enabled; enum Mode { @@ -92,6 +94,11 @@ void QmlFollowPrivate::tick(int time) int elapsed = time - lastTime; if (!elapsed) return; + qreal srcVal = sourceValue; + if (modulus != 0.0) { + currentValue = fmod(currentValue, modulus); + srcVal = fmod(srcVal, modulus); + } if (mode == Spring) { if (elapsed < 16) // capped at 62fps. return; @@ -99,7 +106,13 @@ void QmlFollowPrivate::tick(int time) // We'll do something much simpler which gives a result that looks fine. int count = (elapsed+8) / 16; for (int i = 0; i < count; ++i) { - qreal diff = sourceValue - currentValue; + qreal diff = srcVal - currentValue; + if (modulus != 0.0 && qAbs(diff) > modulus / 2) { + if (diff < 0) + diff += modulus; + else + diff -= modulus; + } velocity = velocity + spring * diff - damping * velocity; // The following line supports mass. Not sure its worth the extra divisions. // velocity = velocity + spring / mass * diff - damping / mass * velocity; @@ -111,24 +124,39 @@ void QmlFollowPrivate::tick(int time) velocity = -maxVelocity; } currentValue += velocity * 16.0 / 1000.0; + if (modulus != 0.0) { + currentValue = fmod(currentValue, modulus); + if (currentValue < 0.0) + currentValue += modulus; + } } - if (qAbs(velocity) < epsilon && qAbs(sourceValue - currentValue) < epsilon) { + if (qAbs(velocity) < epsilon && qAbs(srcVal - currentValue) < epsilon) { velocity = 0.0; - currentValue = sourceValue; + currentValue = srcVal; clock.stop(); } lastTime = time - (elapsed - count * 16); } else { qreal moveBy = elapsed * velocityms; - qreal diff = sourceValue - currentValue; + qreal diff = srcVal - currentValue; + if (modulus != 0.0 && qAbs(diff) > modulus / 2) { + if (diff < 0) + diff += modulus; + else + diff -= modulus; + } if (diff > 0) { currentValue += moveBy; + if (modulus != 0.0) + currentValue = fmod(currentValue, modulus); if (currentValue > sourceValue) { currentValue = sourceValue; clock.stop(); } } else { currentValue -= moveBy; + if (modulus != 0.0 && currentValue < 0.0) + currentValue = fmod(currentValue, modulus) + modulus; if (currentValue < sourceValue) { currentValue = sourceValue; clock.stop(); @@ -326,6 +354,25 @@ void QmlFollow::setEpsilon(qreal epsilon) } /*! + \qmlproperty qreal Follow::modulus + This property holds the modulus value. + + Setting a \a modulus forces the target value to "wrap around" at the modulus. + For example, setting the modulus to 360 will cause a value of 370 to wrap around to 10. +*/ +qreal QmlFollow::modulus() const +{ + Q_D(const QmlFollow); + return d->modulus; +} + +void QmlFollow::setModulus(qreal modulus) +{ + Q_D(QmlFollow); + d->modulus = modulus; +} + +/*! \qmlproperty qreal Follow::followValue The current value. */ diff --git a/src/declarative/util/qmlfollow.h b/src/declarative/util/qmlfollow.h index 0953f2c..07e15e9 100644 --- a/src/declarative/util/qmlfollow.h +++ b/src/declarative/util/qmlfollow.h @@ -64,8 +64,10 @@ class Q_DECLARATIVE_EXPORT QmlFollow : public QmlPropertyValueSource, Q_PROPERTY(qreal spring READ spring WRITE setSpring) Q_PROPERTY(qreal damping READ damping WRITE setDamping) Q_PROPERTY(qreal epsilon READ epsilon WRITE setEpsilon) + Q_PROPERTY(qreal modulus READ modulus WRITE setModulus) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) Q_PROPERTY(qreal followValue READ value NOTIFY valueChanged) + Q_PROPERTY(qreal modulus READ modulus WRITE setModulus NOTIFY modulusChanged) public: QmlFollow(QObject *parent=0); @@ -83,6 +85,8 @@ public: void setDamping(qreal damping); qreal epsilon() const; void setEpsilon(qreal epsilon); + qreal modulus() const; + void setModulus(qreal modulus); bool enabled() const; void setEnabled(bool enabled); -- cgit v0.12 From 5be447a0f1a7cdd69fc94543e9b83038cc2b77b3 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 8 Jul 2009 18:27:58 +1000 Subject: Implement selectedText, selectionStart and selectionEnd properties. Still to go: Setting the selectionStart/End properties doesn't work and there are no autotests. --- src/declarative/fx/qfxtextedit.cpp | 117 +++++++++++++++++++++++++++++++++++++ src/declarative/fx/qfxtextedit.h | 19 +++++- src/declarative/fx/qfxtextedit_p.h | 8 ++- 3 files changed, 140 insertions(+), 4 deletions(-) diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index 9854906..d3b6fab 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -544,6 +544,80 @@ void QFxTextEdit::loadCursorDelegate() } /*! + \qmlproperty int TextEdit::selectionStart + + The cursor position before the first character in the current selection. + Setting this and selectionEnd allows you to specify a selection in the + text edit. + + Note that if selectionStart == selectionEnd then there is no current + selection. + + \sa selectionEnd, cursorPosition, selectedText +*/ +int QFxTextEdit::selectionStart() const +{ + Q_D(const QFxTextEdit); + return d->control->textCursor().selectionStart(); +} + +void QFxTextEdit::setSelectionStart(int s) +{ + Q_D(QFxTextEdit); + if(d->lastSelectionStart == s) + return; + d->lastSelectionStart = s; + d->updateSelection();// Will emit the relevant signals +} + +/*! + \qmlproperty int TextEdit::selectionEnd + + The cursor position after the last character in the current selection. + Setting this and selectionStart allows you to specify a selection in the + text edit. + + Note that if selectionStart == selectionEnd then there is no current + selection. + + \sa selectionStart, cursorPosition, selectedText +*/ +int QFxTextEdit::selectionEnd() const +{ + Q_D(const QFxTextEdit); + return d->control->textCursor().selectionEnd(); +} + +void QFxTextEdit::setSelectionEnd(int s) +{ + Q_D(QFxTextEdit); + if(d->lastSelectionEnd == s) + return; + d->lastSelectionEnd = s; + d->updateSelection();// Will emit the relevant signals +} + +/*! + \qmlproperty string TextEdit::selectedText + + This read-only property provides the text currently selected in the + text edit. + + It is equivalent to the following snippet, but is faster and easier + to use. + \code + //myTextEdit is the id of the TextEdit + myTextEdit.text.toString().substring(myTextEdit.selectionStart, + myTextEdit.selectionEnd); + \endcode +*/ +QString QFxTextEdit::selectedText() const +{ + Q_D(const QFxTextEdit); + return d->control->textCursor().selectedText(); +} + +/*! \qmlproperty bool TextEdit::focusOnPress Whether the TextEdit should gain focus on a mouse press. By default this is @@ -969,6 +1043,8 @@ void QFxTextEditPrivate::init() QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF))); QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged())); + QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged())); + QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers())); QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); document = control->document(); @@ -996,6 +1072,47 @@ void QFxTextEdit::moveCursorDelegate() d->cursor->setY(cursorRect.y()); } +void QFxTextEditPrivate::updateSelection() +{ + Q_Q(QFxTextEdit); + bool startChange = (lastSelectionStart != control->textCursor().selectionStart()); + bool endChange = (lastSelectionEnd != control->textCursor().selectionEnd()); + if(startChange){ + //### Does this generate spurious intermediate signals? + control->textCursor().setPosition(lastSelectionStart, QTextCursor::MoveAnchor); + control->textCursor().setPosition(lastSelectionEnd, QTextCursor::KeepAnchor); + }else if(endChange){ + int n = lastSelectionEnd - control->textCursor().selectionEnd(); + if(n > 0) + control->textCursor().movePosition(QTextCursor::NextCharacter, + QTextCursor::KeepAnchor, n); + else + control->textCursor().movePosition(QTextCursor::PreviousCharacter, + QTextCursor::KeepAnchor, -n); + } + if(startChange) + q->selectionStartChanged(); + if(endChange) + q->selectionEndChanged(); + startChange = (lastSelectionStart != control->textCursor().selectionStart()); + endChange = (lastSelectionEnd != control->textCursor().selectionEnd()); + if(startChange || endChange) + qWarning() << "QFxTextEditPrivate::updateSelection() has failed you."; +} + +void QFxTextEdit::updateSelectionMarkers() +{ + Q_D(QFxTextEdit); + if(d->lastSelectionStart != d->control->textCursor().selectionStart()){ + d->lastSelectionStart = d->control->textCursor().selectionStart(); + emit selectionStartChanged(); + } + if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){ + d->lastSelectionEnd = d->control->textCursor().selectionEnd(); + emit selectionEndChanged(); + } +} + //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't // need to do all the calculations each time void QFxTextEdit::updateSize() diff --git a/src/declarative/fx/qfxtextedit.h b/src/declarative/fx/qfxtextedit.h index b29993e..80636e2 100644 --- a/src/declarative/fx/qfxtextedit.h +++ b/src/declarative/fx/qfxtextedit.h @@ -78,8 +78,11 @@ class Q_DECLARATIVE_EXPORT QFxTextEdit : public QFxPaintedItem Q_PROPERTY(TextFormat textFormat READ textFormat WRITE setTextFormat) Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly) Q_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible) - Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition) - Q_PROPERTY(QmlComponent* cursorDelegate READ cursorDelegate WRITE setCursorDelegate); + Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged) + Q_PROPERTY(QmlComponent* cursorDelegate READ cursorDelegate WRITE setCursorDelegate) + Q_PROPERTY(int selectionStart READ selectionStart WRITE setSelectionStart NOTIFY selectionStartChanged) + Q_PROPERTY(int selectionEnd READ selectionEnd WRITE setSelectionEnd NOTIFY selectionEndChanged) + Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectionChanged) Q_PROPERTY(bool focusOnPress READ focusOnPress WRITE setFocusOnPress) Q_PROPERTY(bool preserveSelection READ preserveSelection WRITE setPreserveSelection) Q_PROPERTY(qreal textMargin READ textMargin WRITE setTextMargin) @@ -141,6 +144,14 @@ public: QmlComponent* cursorDelegate() const; void setCursorDelegate(QmlComponent*); + int selectionStart() const; + void setSelectionStart(int); + + int selectionEnd() const; + void setSelectionEnd(int); + + QString selectedText() const; + bool focusOnPress() const; void setFocusOnPress(bool on); @@ -176,6 +187,9 @@ public: Q_SIGNALS: void textChanged(const QString &); void cursorPositionChanged(); + void selectionStartChanged(); + void selectionEndChanged(); + void selectionChanged(); public Q_SLOTS: void selectAll(); @@ -184,6 +198,7 @@ private Q_SLOTS: void fontChanged(); void updateImgCache(const QRectF &rect); void q_textChanged(); + void updateSelectionMarkers(); void moveCursorDelegate(); void loadCursorDelegate(); diff --git a/src/declarative/fx/qfxtextedit_p.h b/src/declarative/fx/qfxtextedit_p.h index f92dd60..b7d667e 100644 --- a/src/declarative/fx/qfxtextedit_p.h +++ b/src/declarative/fx/qfxtextedit_p.h @@ -69,8 +69,9 @@ class QFxTextEditPrivate : public QFxPaintedItemPrivate public: QFxTextEditPrivate() : font(0), color("black"), imgDirty(true), hAlign(QFxTextEdit::AlignLeft), vAlign(QFxTextEdit::AlignTop), - dirty(false), wrap(false), richText(false), cursorVisible(false), focusOnPress(false), preserveSelection(true), - textMargin(0.0), cursor(0), cursorComponent(0), format(QFxTextEdit::AutoText), document(0) + dirty(false), wrap(false), richText(false), cursorVisible(false), focusOnPress(false), + preserveSelection(true), textMargin(0.0), lastSelectionStart(0), lastSelectionEnd(0), + cursor(0), cursorComponent(0), format(QFxTextEdit::AutoText), document(0) { } @@ -78,6 +79,7 @@ public: void updateDefaultTextOption(); void relayoutDocument(); + void updateSelection(); QString text; QmlFont font; @@ -101,6 +103,8 @@ public: bool focusOnPress; bool preserveSelection; qreal textMargin; + int lastSelectionStart; + int lastSelectionEnd; QmlComponent* cursorComponent; QFxItem* cursor; QFxTextEdit::TextFormat format; -- cgit v0.12 From 25b603c4dcbe5452f37fec17afe26e8689bc618c Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 9 Jul 2009 13:01:21 +1000 Subject: selectionStart/End now work properly Autotests still in progress --- src/declarative/fx/qfxtextedit.cpp | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index d3b6fab..caa48cf 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -551,7 +551,8 @@ void QFxTextEdit::loadCursorDelegate() text edit. Note that if selectionStart == selectionEnd then there is no current - selection. + selection. If you attempt to set selectionStart to a value outside of + the current text, selectionStart will not be changed. \sa selectionEnd, cursorPosition, selectedText */ @@ -564,7 +565,7 @@ int QFxTextEdit::selectionStart() const void QFxTextEdit::setSelectionStart(int s) { Q_D(QFxTextEdit); - if(d->lastSelectionStart == s) + if(d->lastSelectionStart == s || s < 0 || s > text().length()) return; d->lastSelectionStart = s; d->updateSelection();// Will emit the relevant signals @@ -578,7 +579,8 @@ void QFxTextEdit::setSelectionStart(int s) text edit. Note that if selectionStart == selectionEnd then there is no current - selection. + selection. If you attempt to set selectionEnd to a value outside of + the current text, selectionEnd will not be changed. \sa selectionStart, cursorPosition, selectedText */ @@ -591,7 +593,7 @@ int QFxTextEdit::selectionEnd() const void QFxTextEdit::setSelectionEnd(int s) { Q_D(QFxTextEdit); - if(d->lastSelectionEnd == s) + if(d->lastSelectionEnd == s || s < 0 || s > text().length()) return; d->lastSelectionEnd = s; d->updateSelection();// Will emit the relevant signals @@ -1075,21 +1077,13 @@ void QFxTextEdit::moveCursorDelegate() void QFxTextEditPrivate::updateSelection() { Q_Q(QFxTextEdit); - bool startChange = (lastSelectionStart != control->textCursor().selectionStart()); - bool endChange = (lastSelectionEnd != control->textCursor().selectionEnd()); - if(startChange){ - //### Does this generate spurious intermediate signals? - control->textCursor().setPosition(lastSelectionStart, QTextCursor::MoveAnchor); - control->textCursor().setPosition(lastSelectionEnd, QTextCursor::KeepAnchor); - }else if(endChange){ - int n = lastSelectionEnd - control->textCursor().selectionEnd(); - if(n > 0) - control->textCursor().movePosition(QTextCursor::NextCharacter, - QTextCursor::KeepAnchor, n); - else - control->textCursor().movePosition(QTextCursor::PreviousCharacter, - QTextCursor::KeepAnchor, -n); - } + QTextCursor cursor = control->textCursor(); + bool startChange = (lastSelectionStart != cursor.selectionStart()); + bool endChange = (lastSelectionEnd != cursor.selectionEnd()); + //### Is it worth calculating a more minimal set of movements? + cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor); + cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor); + control->setTextCursor(cursor); if(startChange) q->selectionStartChanged(); if(endChange) -- cgit v0.12 From 7343bbb230161d563b0226011e4519f695fdc593 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 9 Jul 2009 15:05:28 +1000 Subject: Tests for QFxTextEdit selection properties Also fixes some bugs that the tests uncovered. Also fixes the test, which was using a now invalid QmlComponent Constructor. --- src/declarative/fx/qfxtextedit.cpp | 4 + .../declarative/qfxtextedit/tst_qfxtextedit.cpp | 126 +++++++++++++++++---- 2 files changed, 108 insertions(+), 22 deletions(-) diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index caa48cf..87a27d9 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -481,6 +481,7 @@ void QFxTextEdit::setCursorPosition(int pos) if (cursor.position() == pos) return; cursor.setPosition(pos); + d->control->setTextCursor(cursor); } /*! @@ -1047,6 +1048,7 @@ void QFxTextEditPrivate::init() QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged())); QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged())); QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers())); + QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers())); QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); document = control->document(); @@ -1081,8 +1083,10 @@ void QFxTextEditPrivate::updateSelection() bool startChange = (lastSelectionStart != cursor.selectionStart()); bool endChange = (lastSelectionEnd != cursor.selectionEnd()); //### Is it worth calculating a more minimal set of movements? + cursor.beginEditBlock(); cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor); cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor); + cursor.endEditBlock(); control->setTextCursor(cursor); if(startChange) q->selectionStartChanged(); diff --git a/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp b/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp index b498b14..809ed5b 100644 --- a/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp +++ b/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp @@ -24,6 +24,7 @@ private slots: void vAlign(); void font(); void color(); + void selection(); void cursorDelegate(); @@ -120,7 +121,7 @@ tst_qfxtextedit::tst_qfxtextedit() void tst_qfxtextedit::text() { { - QmlComponent texteditComponent(&engine, "TextEdit { text: \"\" }"); + QmlComponent texteditComponent(&engine, "TextEdit { text: \"\" }", QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -130,7 +131,7 @@ void tst_qfxtextedit::text() for (int i = 0; i < standard.size(); i++) { QString componentStr = "TextEdit { text: \"" + standard.at(i) + "\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -140,7 +141,7 @@ void tst_qfxtextedit::text() for (int i = 0; i < richText.size(); i++) { QString componentStr = "TextEdit { text: \"" + richText.at(i) + "\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -157,7 +158,7 @@ void tst_qfxtextedit::width() { // uses Font metrics to find the width for standard and document to find the width for rich { - QmlComponent texteditComponent(&engine, "TextEdit { text: \"\" }"); + QmlComponent texteditComponent(&engine, "TextEdit { text: \"\" }", QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -171,7 +172,7 @@ void tst_qfxtextedit::width() int metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width(); QString componentStr = "TextEdit { text: \"" + standard.at(i) + "\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -187,7 +188,7 @@ void tst_qfxtextedit::width() int documentWidth = document.idealWidth(); QString componentStr = "TextEdit { text: \"" + richText.at(i) + "\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -199,7 +200,7 @@ void tst_qfxtextedit::wrap() { // for specified width and wrap set true { - QmlComponent texteditComponent(&engine, "TextEdit { text: \"\"; wrap: true; width: 300 }"); + QmlComponent texteditComponent(&engine, "TextEdit { text: \"\"; wrap: true; width: 300 }", QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -209,7 +210,7 @@ void tst_qfxtextedit::wrap() for (int i = 0; i < standard.size(); i++) { QString componentStr = "TextEdit { wrap: true; width: 300; text: \"" + standard.at(i) + "\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -219,7 +220,7 @@ void tst_qfxtextedit::wrap() for (int i = 0; i < richText.size(); i++) { QString componentStr = "TextEdit { wrap: true; width: 300; text: \"" + richText.at(i) + "\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -238,7 +239,7 @@ void tst_qfxtextedit::hAlign() for (int j=0; j < hAlignmentStrings.size(); j++) { QString componentStr = "TextEdit { hAlign: \"" + hAlignmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -251,7 +252,7 @@ void tst_qfxtextedit::hAlign() for (int j=0; j < hAlignmentStrings.size(); j++) { QString componentStr = "TextEdit { hAlign: \"" + hAlignmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -270,7 +271,7 @@ void tst_qfxtextedit::vAlign() for (int j=0; j < vAlignmentStrings.size(); j++) { QString componentStr = "TextEdit { vAlign: \"" + vAlignmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -283,7 +284,7 @@ void tst_qfxtextedit::vAlign() for (int j=0; j < vAlignmentStrings.size(); j++) { QString componentStr = "TextEdit { vAlign: \"" + vAlignmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -298,7 +299,7 @@ void tst_qfxtextedit::font() //test size, then bold, then italic, then family { QString componentStr = "TextEdit { font.size: 40; text: \"Hello World\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -309,7 +310,7 @@ void tst_qfxtextedit::font() { QString componentStr = "TextEdit { font.bold: true; text: \"Hello World\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -319,7 +320,7 @@ void tst_qfxtextedit::font() { QString componentStr = "TextEdit { font.italic: true; text: \"Hello World\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -329,7 +330,7 @@ void tst_qfxtextedit::font() { QString componentStr = "TextEdit { font.family: \"Helvetica\"; text: \"Hello World\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -340,7 +341,7 @@ void tst_qfxtextedit::font() { QString componentStr = "TextEdit { font.family: \"\"; text: \"Hello World\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -354,7 +355,7 @@ void tst_qfxtextedit::color() for (int i = 0; i < colorStrings.size(); i++) { QString componentStr = "TextEdit { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); //qDebug() << "textEditObject: " << textEditObject->color() << "vs. " << QColor(colorStrings.at(i)); QVERIFY(textEditObject != 0); @@ -367,7 +368,7 @@ void tst_qfxtextedit::color() testColor.setAlpha(170); QString componentStr = "TextEdit { color: \"" + colorStr + "\"; text: \"Hello World\" }"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); @@ -375,16 +376,97 @@ void tst_qfxtextedit::color() } } +void tst_qfxtextedit::selection() +{ + QString testStr = standard[0];//TODO: What should happen for multiline/rich text? + QString componentStr = "TextEdit { text: \""+ testStr +"\"; }"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); + QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QVERIFY(textEditObject != 0); + + + //Test selection follows cursor + for(int i=0; i<= testStr.size(); i++) { + textEditObject->setCursorPosition(i); + QCOMPARE(textEditObject->cursorPosition(), i); + QCOMPARE(textEditObject->selectionStart(), i); + QCOMPARE(textEditObject->selectionEnd(), i); + QVERIFY(textEditObject->selectedText().isNull()); + } + + textEditObject->setCursorPosition(0); + QVERIFY(textEditObject->cursorPosition() == 0); + QVERIFY(textEditObject->selectionStart() == 0); + QVERIFY(textEditObject->selectionEnd() == 0); + QVERIFY(textEditObject->selectedText().isNull()); + + //Test selection + for(int i=0; i<= testStr.size(); i++) { + textEditObject->setSelectionEnd(i); + QCOMPARE(testStr.mid(0,i), textEditObject->selectedText()); + } + for(int i=0; i<= testStr.size(); i++) { + textEditObject->setSelectionStart(i); + QCOMPARE(testStr.mid(i,testStr.size()-i), textEditObject->selectedText()); + } + + textEditObject->setCursorPosition(0); + QVERIFY(textEditObject->cursorPosition() == 0); + QVERIFY(textEditObject->selectionStart() == 0); + QVERIFY(textEditObject->selectionEnd() == 0); + QVERIFY(textEditObject->selectedText().isNull()); + + for(int i=0; i< testStr.size(); i++) { + textEditObject->setSelectionStart(i); + QCOMPARE(textEditObject->selectionEnd(), i); + QCOMPARE(testStr.mid(i,0), textEditObject->selectedText()); + textEditObject->setSelectionEnd(i+1); + QCOMPARE(textEditObject->selectionStart(), i); + QCOMPARE(testStr.mid(i,1), textEditObject->selectedText()); + } + + for(int i= testStr.size() - 1; i>0; i--) { + textEditObject->setSelectionEnd(i); + QCOMPARE(testStr.mid(i,0), textEditObject->selectedText()); + textEditObject->setSelectionStart(i-1); + QCOMPARE(testStr.mid(i-1,1), textEditObject->selectedText()); + } + + //Test Error Ignoring behaviour + textEditObject->setCursorPosition(0); + QVERIFY(textEditObject->selectedText().isNull()); + textEditObject->setSelectionStart(-10); + QVERIFY(textEditObject->selectedText().isNull()); + textEditObject->setSelectionStart(100); + QVERIFY(textEditObject->selectedText().isNull()); + textEditObject->setSelectionEnd(-10); + QVERIFY(textEditObject->selectedText().isNull()); + textEditObject->setSelectionEnd(100); + QVERIFY(textEditObject->selectedText().isNull()); + textEditObject->setSelectionStart(0); + textEditObject->setSelectionEnd(10); + QVERIFY(textEditObject->selectedText().size() == 10); + textEditObject->setSelectionStart(-10); + QVERIFY(textEditObject->selectedText().size() == 10); + textEditObject->setSelectionStart(100); + QVERIFY(textEditObject->selectedText().size() == 10); + textEditObject->setSelectionEnd(-10); + QVERIFY(textEditObject->selectedText().size() == 10); + textEditObject->setSelectionEnd(100); + QVERIFY(textEditObject->selectedText().size() == 10); +} + void tst_qfxtextedit::cursorDelegate() { - QString componentStr = "TextEdit { text: \""+ standard[1] +"\"; focusable: true; resources [ Component { id:cursor; Item { id:cursorInstance } } ] cursorDelegate: cursor}"; - QTest::qWait(10000); + QString componentStr = "TextEdit { text: \""+ standard[1] +"\"; focusable: true; resources: [ Component { id:cursor; Item { id:cursorInstance } } ] cursorDelegate: cursor}"; QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); QVERIFY(textEditObject != 0); QVERIFY(!findItem(textEditObject, "cursorInstance")); //Test Delegate gets created textEditObject->setFocus(true); + //TODO:To get focus you also need to be in a focused window - switch this to a QFxView + return; QFxItem* delegateObject = findItem(textEditObject, "cursorInstance"); QVERIFY(delegateObject); //Test Delegate gets moved -- cgit v0.12 From ce0ff6de3d6f8715f6b7d18cdcb2f4b6a3a0c548 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 9 Jul 2009 16:40:15 +1000 Subject: Fix QFxTextEdit cursor delegate for multi-line and font changes They weren't handled before, and now they are. --- src/declarative/fx/qfxtextedit.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index 87a27d9..ef56cc8 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -538,6 +538,7 @@ void QFxTextEdit::loadCursorDelegate() d->control->setCursorWidth(0); dirtyCache(cursorRect()); d->cursor->setItemParent(this); + d->cursor->setHeight(QFontMetrics(d->font.font()).height()); moveCursorDelegate(); }else{ qWarning() << "Error loading cursor delegate for TextEdit:" + objectName(); @@ -1020,6 +1021,10 @@ void QFxTextEdit::fontChanged() Q_D(QFxTextEdit); clearCache(); d->document->setDefaultFont(d->font.font()); + if(d->cursor){ + d->cursor->setHeight(QFontMetrics(d->font.font()).height()); + moveCursorDelegate(); + } updateSize(); emit update(); } -- cgit v0.12 From 3399066881c42d1dd6fda6b3ae8cf3fc8961929b Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 9 Jul 2009 17:06:22 +1000 Subject: Fix QFxTextEdit cursorDelegate auto test properly Also fixes the minor bug that it found. --- src/declarative/fx/qfxtextedit.cpp | 5 ++- .../declarative/qfxtextedit/data/cursorTest.qml | 6 +++ .../declarative/qfxtextedit/tst_qfxtextedit.cpp | 51 +++++----------------- 3 files changed, 19 insertions(+), 43 deletions(-) create mode 100644 tests/auto/declarative/qfxtextedit/data/cursorTest.qml diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index ef56cc8..c2bda6f 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -521,8 +521,9 @@ void QFxTextEdit::setCursorDelegate(QmlComponent* c) if(c && c->isReady()){ loadCursorDelegate(); }else{ - connect(c, SIGNAL(statusChanged()), - this, SLOT(loadCursorDelegate())); + if(c) + connect(c, SIGNAL(statusChanged()), + this, SLOT(loadCursorDelegate())); } } diff --git a/tests/auto/declarative/qfxtextedit/data/cursorTest.qml b/tests/auto/declarative/qfxtextedit/data/cursorTest.qml new file mode 100644 index 0000000..10ac2fd --- /dev/null +++ b/tests/auto/declarative/qfxtextedit/data/cursorTest.qml @@ -0,0 +1,6 @@ +Rect { width: 300; height: 300; color: "white" + TextEdit { text: "Hello world!"; focusable: true; id: textEditObject + resources: [ Component { id:cursor; Item { id:cursorInstance } } ] + cursorDelegate: cursor + } +} diff --git a/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp b/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp index 809ed5b..241dbad 100644 --- a/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp +++ b/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp @@ -43,38 +43,6 @@ private: QmlEngine engine; }; -/* - Find an item with the specified id. If index is supplied then the - item must also evaluate the {index} expression equal to index - - Copied from ListView test -*/ -template -T *findItem(QFxItem *parent, const QString &id, int index=0) -{ - const QMetaObject &mo = T::staticMetaObject; - qDebug() << parent->children()->count() << "children"; - for (int i = 0; i < parent->children()->count(); ++i) { - QFxItem *item = parent->children()->at(i); - qDebug() << "try" << item; - if (mo.cast(item) && (id.isEmpty() || item->id() == id)) { - if (index != -1) { - QmlExpression e(qmlContext(item), "index", item); - e.setTrackChange(false); - if (e.value().toInt() == index) - return static_cast(item); - } else { - return static_cast(item); - } - } - item = findItem(item, id, index); - if (item) - return static_cast(item); - } - - return 0; -} - tst_qfxtextedit::tst_qfxtextedit() { standard << "the quick brown fox jumped over the lazy dog" @@ -456,21 +424,22 @@ void tst_qfxtextedit::selection() QVERIFY(textEditObject->selectedText().size() == 10); } +#include void tst_qfxtextedit::cursorDelegate() { - QString componentStr = "TextEdit { text: \""+ standard[1] +"\"; focusable: true; resources: [ Component { id:cursor; Item { id:cursorInstance } } ] cursorDelegate: cursor}"; - QmlComponent texteditComponent(&engine, componentStr.toLatin1(), QUrl()); - QFxTextEdit *textEditObject = qobject_cast(texteditComponent.create()); + QFxView* view = new QFxView(0); + view->show(); + view->setUrl(QUrl("data/cursorTest.qml")); + view->execute(); + QFxTextEdit *textEditObject = view->root()->findChild("textEditObject"); QVERIFY(textEditObject != 0); - QVERIFY(!findItem(textEditObject, "cursorInstance")); + QVERIFY(textEditObject->findChild("cursorInstance")); //Test Delegate gets created textEditObject->setFocus(true); - //TODO:To get focus you also need to be in a focused window - switch this to a QFxView - return; - QFxItem* delegateObject = findItem(textEditObject, "cursorInstance"); + QFxItem* delegateObject = textEditObject->findChild("cursorInstance"); QVERIFY(delegateObject); //Test Delegate gets moved - for(int i=0; i<= standard[1].size(); i++){ + for(int i=0; i<= textEditObject->text().length(); i++){ textEditObject->setCursorPosition(i); QCOMPARE(textEditObject->cursorRect().x(), qRound(delegateObject->x())); QCOMPARE(textEditObject->cursorRect().y(), qRound(delegateObject->y())); @@ -480,7 +449,7 @@ void tst_qfxtextedit::cursorDelegate() QCOMPARE(textEditObject->cursorRect().y(), qRound(delegateObject->y())); //Test Delegate gets deleted textEditObject->setCursorDelegate(0); - QVERIFY(!findItem(textEditObject, "cursorInstance")); + QVERIFY(!textEditObject->findChild("cursorInstance")); } QTEST_MAIN(tst_qfxtextedit) -- cgit v0.12