diff options
9 files changed, 250 insertions, 22 deletions
diff --git a/doc/src/declarative/whatsnew.qdoc b/doc/src/declarative/whatsnew.qdoc index e8c2124..1a8ebd7 100644 --- a/doc/src/declarative/whatsnew.qdoc +++ b/doc/src/declarative/whatsnew.qdoc @@ -31,20 +31,33 @@ \section1 Qt 4.7.3 includes QtQuick 1.1 -QtQuick 1.1 is a minor feature update. +QtQuick 1.1 is a minor feature update. \e {import QtQuick 1.1} to use the new features. \section2 PinchArea PinchArea provides support for the common two finger pinch gesture. +\section2 LayoutMirroring + +\l {LayoutMirroring}{Layout mirroring} is useful when you need to support both left-to-right and right-to-left layout versions of your application that target different language areas. + +\section2 Anchors + +Added the following property: +\list +\o \l {Item::}{anchors.mirrored} +\endlist + \section2 Text Added the following properties: \list \o \l {Text::}{lineHeight} +\o \l {Text::}{lineHeightMode} \o \l {Text::}{lineCount} \o \l {Text::}{maximumLineCount} \o \l {Text::}{truncated} +\o \l {Text::}{effectiveHorizontalAlignment} \endlist horizontalAlignment now accepts Text.AlignJustify alignment mode. @@ -55,7 +68,11 @@ Added the following properties, methods and signal handlers: \list \o \l {TextEdit::}{canPaste} \o \l {TextEdit::}{lineCount} +\o \l {TextEdit::}{inputMethodComposing} +\o \l {TextEdit::}{mouseSelectionMode} +\o \l {TextEdit::}{effectiveHorizontalAlignment} \o \l {TextEdit::}{deselect()} +\o \l {TextEdit::}{isRightToLeft()} \o \l {TextEdit::}{moveCursorSelection()} to enable selection by word \o \l {TextEdit::}{onLinkActivated} \endlist @@ -64,9 +81,13 @@ Added the following properties, methods and signal handlers: Added the following properties and methods: \list -\o \l{TextInput::}{canPaste} -\o \l{TextInput::}{deselect()} -\o \l{TextInput::}{moveCursorSelection()} to enable selection by word +\o \l {TextInput::}{canPaste} +\o \l {TextInput::}{inputMethodComposing} +\o \l {TextInput::}{mouseSelectionMode} +\o \l {TextInput::}{effectiveHorizontalAlignment} +\o \l {TextInput::}{deselect()} +\o \l {TextInput::}{isRightToLeft()} +\o \l {TextInput::}{moveCursorSelection()} to enable selection by word \endlist \section2 Image, BorderImage and AnimatedImage @@ -92,10 +113,19 @@ Added the following methods: \o \l{Flickable::}{returnToBounds()} \endlist +\section2 MouseArea + +Added the following property: +\list +\o \l{MouseArea::}{preventStealing} +\endlist + \section2 ListView and GridView -Added the following methods: +Added the following properties and methods: \list +\o \l{ListView::}{layoutDirection} +\o \l{ListView::}{effectiveLayoutDirection} \o \l{ListView::}{positionViewAtBeginning()} \o \l{ListView::}{positionViewAtEnd()} \endlist @@ -105,6 +135,7 @@ Added the following methods: Added the following properties: \list \o \l{Flow::}{layoutDirection} +\o \l{Flow::}{effectiveLayoutDirection} \endlist \section2 Repeater @@ -135,6 +166,7 @@ properties. \list \o Functions can be \l{Binding Properties from JavaScript}{assigned to properties from JavaScript} to create property bindings. +\o QtQuick now supports Right to Left layout in positioners, views, anchors and text elements. \endlist diff --git a/src/declarative/graphicsitems/qdeclarativeitem.cpp b/src/declarative/graphicsitems/qdeclarativeitem.cpp index 1b1c476..9cf1e78 100644 --- a/src/declarative/graphicsitems/qdeclarativeitem.cpp +++ b/src/declarative/graphicsitems/qdeclarativeitem.cpp @@ -2317,6 +2317,8 @@ QDeclarativeAnchorLine QDeclarativeItemPrivate::baseline() const \qmlproperty real Item::anchors.verticalCenterOffset \qmlproperty real Item::anchors.baselineOffset + \qmlproperty bool Item::anchors.mirrored + Anchors provide a way to position an item by specifying its relationship with other items. @@ -2374,6 +2376,8 @@ QDeclarativeAnchorLine QDeclarativeItemPrivate::baseline() const To clear an anchor value, set it to \c undefined. + \c anchors.mirrored returns true it the layout has been \l {LayoutMirroring}{mirrored}. + \note You can only anchor an item to siblings or a parent. For more information see \l {anchor-layout}{Anchor Layouts}. diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index f9f1a48..2c23a1b 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -272,6 +272,22 @@ public: void regenerate() { Q_Q(QDeclarativeListView); if (q->isComponentComplete()) { + if (header) { + if (q->scene()) + q->scene()->removeItem(header->item); + header->item->deleteLater(); + delete header; + header = 0; + } + if (footer) { + if (q->scene()) + q->scene()->removeItem(footer->item); + footer->item->deleteLater(); + delete footer; + footer = 0; + } + updateHeader(); + updateFooter(); clear(); setPosition(0); q->refill(); @@ -2633,7 +2649,8 @@ qreal QDeclarativeListView::maxYExtent() const return height(); if (d->maxExtentDirty) { if (!d->model || !d->model->count()) { - d->maxExtent = 0; + d->maxExtent = d->header ? -d->header->size() : 0; + d->maxExtent += height(); } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart); if (d->highlightRangeEnd != d->highlightRangeStart) @@ -2661,21 +2678,26 @@ qreal QDeclarativeListView::minXExtent() const qreal highlightStart; qreal highlightEnd; - qreal endPositionFirstItem; + qreal endPositionFirstItem = 0; if (d->isRightToLeft()) { if (d->model && d->model->count()) endPositionFirstItem = d->positionAt(d->model->count()-1); + else if (d->header) + d->minExtent += d->header->size(); highlightStart = d->highlightRangeStartValid ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem) : d->size() - (d->lastPosition()-endPositionFirstItem); highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size(); if (d->footer) d->minExtent += d->footer->size(); + qreal maxX = maxXExtent(); + if (d->minExtent < maxX) + d->minExtent = maxX; } else { endPositionFirstItem = d->endPositionAt(0); highlightStart = d->highlightRangeStart; highlightEnd = d->highlightRangeEnd; - if (d->header) + if (d->header && d->visibleItems.count()) d->minExtent += d->header->size(); } if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { @@ -2696,7 +2718,8 @@ qreal QDeclarativeListView::maxXExtent() const if (d->maxExtentDirty) { qreal highlightStart; qreal highlightEnd; - qreal lastItemPosition; + qreal lastItemPosition = 0; + d->maxExtent = 0; if (d->isRightToLeft()) { highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size(); highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size(); @@ -2708,7 +2731,9 @@ qreal QDeclarativeListView::maxXExtent() const lastItemPosition = d->positionAt(d->model->count()-1); } if (!d->model || !d->model->count()) { - d->maxExtent = 0; + if (!d->isRightToLeft()) + d->maxExtent = d->header ? -d->header->size() : 0; + d->maxExtent += width(); } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { d->maxExtent = -(lastItemPosition - highlightStart); if (highlightEnd != highlightStart) { @@ -2720,15 +2745,15 @@ qreal QDeclarativeListView::maxXExtent() const d->maxExtent = -(d->endPosition() - width() + 1); } if (d->isRightToLeft()) { - if (d->header) + if (d->header && d->visibleItems.count()) d->maxExtent -= d->header->size(); } else { if (d->footer) d->maxExtent -= d->footer->size(); + qreal minX = minXExtent(); + if (d->maxExtent > minX) + d->maxExtent = minX; } - qreal minX = minXExtent(); - if (d->maxExtent > minX) - d->maxExtent = minX; d->maxExtentDirty = false; } return d->maxExtent; @@ -2776,6 +2801,11 @@ void QDeclarativeListView::geometryChanged(const QRectF &newGeometry, Q_D(QDeclarativeListView); d->maxExtentDirty = true; d->minExtentDirty = true; + if (d->isRightToLeft() && d->orient == Qt::Horizontal) { + // maintain position relative to the right edge + int dx = newGeometry.width() - oldGeometry.width(); + setContentX(contentX() - dx); + } QDeclarativeFlickable::geometryChanged(newGeometry, oldGeometry); } diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp index babc020..2cb1c94 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp @@ -1508,7 +1508,7 @@ bool QDeclarativeTextEdit::canPaste() const } /*! - \qmlproperty bool TextEdit::isInputMethodComposing() + \qmlproperty bool TextEdit::inputMethodComposing \since QtQuick 1.1 diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp index 6c26fd3..c6de7a0 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp @@ -1374,7 +1374,10 @@ QVariant QDeclarativeTextInput::inputMethodQuery(Qt::InputMethodQuery property) case Qt::ImCursorPosition: return QVariant(d->control->cursor()); case Qt::ImSurroundingText: - return QVariant(text()); + if (d->control->echoMode() == PasswordEchoOnEdit && !d->control->passwordEchoEditing()) + return QVariant(displayText()); + else + return QVariant(text()); case Qt::ImCurrentSelection: return QVariant(selectedText()); case Qt::ImMaximumTextLength: @@ -1672,8 +1675,8 @@ void QDeclarativeTextInput::moveCursorSelection(int pos, SelectionMode mode) finder.setPosition(anchor); const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons(); - if (anchor < text.length() && !(reasons & QTextBoundaryFinder::StartWord) - || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor)) { + if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord) + || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) { finder.toPreviousBoundary(); } anchor = finder.position() != -1 ? finder.position() : 0; @@ -1690,8 +1693,8 @@ void QDeclarativeTextInput::moveCursorSelection(int pos, SelectionMode mode) finder.setPosition(anchor); const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons(); - if (anchor > 0 && !(reasons & QTextBoundaryFinder::EndWord) - || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor)) { + if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord) + || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) { finder.toNextBoundary(); } anchor = finder.position() != -1 ? finder.position() : text.length(); @@ -1821,7 +1824,7 @@ void QDeclarativeTextInput::focusInEvent(QFocusEvent *event) } /*! - \qmlproperty bool TextInput::isInputMethodComposing() + \qmlproperty bool TextInput::inputMethodComposing \since QtQuick 1.1 @@ -1867,6 +1870,8 @@ void QDeclarativeTextInputPrivate::init() #endif // QT_NO_CLIPBOARD q->connect(control, SIGNAL(updateMicroFocus()), q, SLOT(updateMicroFocus())); + q->connect(control, SIGNAL(displayTextChanged(QString)), + q, SLOT(updateRect())); q->updateSize(); oldValidity = control->hasAcceptableInput(); lastSelectionStart = 0; diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index f20e018..3eac64a 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -414,10 +414,14 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) if (isGettingInput) { // If any text is being input, remove selected text. priorState = m_undoState; + if (echoMode() == QLineEdit::PasswordEchoOnEdit && !passwordEchoEditing()) { + updatePasswordEchoEditing(true); + m_selstart = 0; + m_selend = m_text.length(); + } removeSelectedText(); } - int c = m_cursor; // cursor position after insertion of commit string if (event->replacementStart() <= 0) c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength()); diff --git a/tests/auto/declarative/qdeclarativelistview/data/headerfooter.qml b/tests/auto/declarative/qdeclarativelistview/data/headerfooter.qml new file mode 100644 index 0000000..5633831 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistview/data/headerfooter.qml @@ -0,0 +1,26 @@ +import QtQuick 1.1 + +ListView { + id: view + property bool horizontal: false + property bool rtl: false + width: 240 + height: 320 + + orientation: horizontal ? ListView.Horizontal : ListView.Vertical + header: Rectangle { + objectName: "header" + width: horizontal ? 20 : view.width + height: horizontal ? view.height : 20 + color: "red" + } + footer: Rectangle { + objectName: "footer" + width: horizontal ? 30 : view.width + height: horizontal ? view.height : 30 + color: "blue" + } +// model: testModel + delegate: Text { width: 30; height: 30; text: index + "(" + x + ")" } + layoutDirection: rtl ? Qt.RightToLeft : Qt.LeftToRight +} diff --git a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp index a699bbe..c87318e 100644 --- a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp +++ b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp @@ -103,6 +103,7 @@ private slots: void QTBUG_11105(); void header(); void footer(); + void headerFooter(); void resizeView(); void sizeLessThan1(); void QTBUG_14821(); @@ -1958,6 +1959,112 @@ void tst_QDeclarativeListView::footer() delete canvas; } +class LVAccessor : public QDeclarativeListView +{ +public: + qreal minY() const { return minYExtent(); } + qreal maxY() const { return maxYExtent(); } + qreal minX() const { return minXExtent(); } + qreal maxX() const { return maxXExtent(); } +}; + +void tst_QDeclarativeListView::headerFooter() +{ + { + // Vertical + QDeclarativeView *canvas = createView(); + + TestModel model; + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/headerfooter.qml")); + qApp->processEvents(); + + QDeclarativeListView *listview = qobject_cast<QDeclarativeListView*>(canvas->rootObject()); + QTRY_VERIFY(listview != 0); + + QDeclarativeItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + QDeclarativeItem *header = findItem<QDeclarativeItem>(contentItem, "header"); + QVERIFY(header); + QCOMPARE(header->y(), 0.0); + + QDeclarativeItem *footer = findItem<QDeclarativeItem>(contentItem, "footer"); + QVERIFY(footer); + QCOMPARE(footer->y(), 20.0); + + QVERIFY(static_cast<LVAccessor*>(listview)->minY() == 0); + QVERIFY(static_cast<LVAccessor*>(listview)->maxY() == 0); + + delete canvas; + } + { + // Horizontal + QDeclarativeView *canvas = createView(); + + TestModel model; + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/headerfooter.qml")); + canvas->rootObject()->setProperty("horizontal", true); + qApp->processEvents(); + + QDeclarativeListView *listview = qobject_cast<QDeclarativeListView*>(canvas->rootObject()); + QTRY_VERIFY(listview != 0); + + QDeclarativeItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + QDeclarativeItem *header = findItem<QDeclarativeItem>(contentItem, "header"); + QVERIFY(header); + QCOMPARE(header->x(), 0.0); + + QDeclarativeItem *footer = findItem<QDeclarativeItem>(contentItem, "footer"); + QVERIFY(footer); + QCOMPARE(footer->x(), 20.0); + + QVERIFY(static_cast<LVAccessor*>(listview)->minX() == 0); + QVERIFY(static_cast<LVAccessor*>(listview)->maxX() == 0); + + delete canvas; + } + { + // Horizontal RTL + QDeclarativeView *canvas = createView(); + + TestModel model; + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/headerfooter.qml")); + canvas->rootObject()->setProperty("horizontal", true); + canvas->rootObject()->setProperty("rtl", true); + qApp->processEvents(); + + QDeclarativeListView *listview = qobject_cast<QDeclarativeListView*>(canvas->rootObject()); + QTRY_VERIFY(listview != 0); + + QDeclarativeItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + QDeclarativeItem *header = findItem<QDeclarativeItem>(contentItem, "header"); + QVERIFY(header); + QCOMPARE(header->x(), -20.0); + + QDeclarativeItem *footer = findItem<QDeclarativeItem>(contentItem, "footer"); + QVERIFY(footer); + QCOMPARE(footer->x(), -50.0); + + QCOMPARE(static_cast<LVAccessor*>(listview)->minX(), 240.); + QCOMPARE(static_cast<LVAccessor*>(listview)->maxX(), 240.); + + delete canvas; + } +} + void tst_QDeclarativeListView::resizeView() { QDeclarativeView *canvas = createView(); @@ -2360,6 +2467,7 @@ void tst_QDeclarativeListView::testQtQuick11Attributes_data() void tst_QDeclarativeListView::rightToLeft() { QDeclarativeView *canvas = createView(); + canvas->setFixedSize(640,320); canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/rightToLeft.qml")); qApp->processEvents(); @@ -2376,6 +2484,9 @@ void tst_QDeclarativeListView::rightToLeft() QTRY_VERIFY(model->count() == 3); QTRY_COMPARE(listview->currentIndex(), 0); + // initial position at first item, right edge aligned + QCOMPARE(listview->contentX(), -640.); + QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "item1"); QTRY_VERIFY(item); QTRY_COMPARE(item->x(), -100.0); @@ -2395,6 +2506,12 @@ void tst_QDeclarativeListView::rightToLeft() QTRY_VERIFY(text); QTRY_COMPARE(text->text(), QLatin1String("index: 2")); + QCOMPARE(listview->contentX(), -640.); + + // Ensure resizing maintains position relative to right edge + qobject_cast<QDeclarativeItem*>(canvas->rootObject())->setWidth(600); + QTRY_COMPARE(listview->contentX(), -600.); + delete canvas; } diff --git a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp index 796ac23..45f38a4 100644 --- a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp +++ b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp @@ -1829,13 +1829,23 @@ void tst_qdeclarativetextinput::echoMode() QCOMPARE(input->inputMethodHints(), ref); QCOMPARE(input->text(), initial); QCOMPARE(input->displayText(), QLatin1String("QQQQQQQQ")); + QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("QQQQQQQQ")); QTest::keyPress(canvas, Qt::Key_A);//Clearing previous entry is part of PasswordEchoOnEdit QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10); QCOMPARE(input->text(), QLatin1String("a")); QCOMPARE(input->displayText(), QLatin1String("a")); + QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("a")); input->setFocus(false); QVERIFY(input->hasActiveFocus() == false); QCOMPARE(input->displayText(), QLatin1String("Q")); + QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("Q")); + input->setFocus(true); + QInputMethodEvent inputEvent; + inputEvent.setCommitString(initial); + QApplication::sendEvent(canvas, &inputEvent); + QCOMPARE(input->text(), initial); + QCOMPARE(input->displayText(), initial); + QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), initial); delete canvas; } |