diff options
author | Andrew den Exter <andrew.den-exter@nokia.com> | 2011-01-07 07:42:12 (GMT) |
---|---|---|
committer | Andrew den Exter <andrew.den-exter@nokia.com> | 2011-01-10 03:51:19 (GMT) |
commit | cbf6bfbff8c0643bc82bb2456214994931052bd6 (patch) | |
tree | c9f8510af5dfddb365e4b5f0c34ed6729332fa49 /src | |
parent | 6db61ce39aa2fefaa9e22ca84edd8d140a5c6449 (diff) | |
download | Qt-cbf6bfbff8c0643bc82bb2456214994931052bd6.zip Qt-cbf6bfbff8c0643bc82bb2456214994931052bd6.tar.gz Qt-cbf6bfbff8c0643bc82bb2456214994931052bd6.tar.bz2 |
Add selection modes to TextEdit and TextInput.
Add an overload for moveCursorSelection which takes a parameter
specifying whether to update the selection with individual characters
or whole words.
Task-number: QTBUG-16283
Reviewed-by: Martin Jones
Diffstat (limited to 'src')
4 files changed, 187 insertions, 17 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp index 6a51a3c..7ea3dec 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp @@ -579,37 +579,108 @@ int QDeclarativeTextEdit::positionAt(int x, int y) const return r; } +void QDeclarativeTextEdit::moveCursorSelection(int pos) +{ + //Note that this is the same as setCursorPosition but with the KeepAnchor flag set + Q_D(QDeclarativeTextEdit); + QTextCursor cursor = d->control->textCursor(); + if (cursor.position() == pos) + return; + cursor.setPosition(pos, QTextCursor::KeepAnchor); + d->control->setTextCursor(cursor); +} + /*! - \qmlmethod int TextEdit::moveCursorSelection(int pos) + \qmlmethod void TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters) + \since Quick 1.1 - Moves the cursor to \a position and updates the selection accordingly. - (To only move the cursor, set the \l cursorPosition property.) + Moves the cursor to \a position and updates the selection according to the optional \a mode + parameter. (To only move the cursor, set the \l cursorPosition property.) When this method is called it additionally sets either the selectionStart or the selectionEnd (whichever was at the previous cursor position) to the specified position. This allows you to easily extend and contract the selected text range. + The selection mode specifies whether the selection is updated on a per character or a per word + basis. If not specified the selection mode will default to TextEdit.SelectCharacters. + + \list + \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at + the previous cursor position) to the specified position. + \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all + words between the specified postion and the previous cursor position. Words partially in the + range are included. + \endlist + For example, take this sequence of calls: \code cursorPosition = 5 - moveCursorSelection(9) - moveCursorSelection(7) + moveCursorSelection(9, TextEdit.SelectCharacters) + moveCursorSelection(7, TextEdit.SelectCharacters) \endcode This moves the cursor to position 5, extend the selection end from 5 to 9 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7 selected (the 6th and 7th characters). + + The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary + before or on position 5 and extend the selection end to a word boundary past position 9, and + then if there is a word boundary between position 7 and 8 retract the selection end to that + boundary. If there is whitespace at position 7 the selection will be retracted further. */ -void QDeclarativeTextEdit::moveCursorSelection(int pos) +void QDeclarativeTextEdit::moveCursorSelection(int pos, SelectionMode mode) { - //Note that this is the same as setCursorPosition but with the KeepAnchor flag set Q_D(QDeclarativeTextEdit); QTextCursor cursor = d->control->textCursor(); if (cursor.position() == pos) return; - cursor.setPosition(pos, QTextCursor::KeepAnchor); + if (mode == SelectCharacters) { + cursor.setPosition(pos, QTextCursor::KeepAnchor); + } else if (cursor.anchor() < pos) { + cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor); + cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); + if (cursor.position() == cursor.anchor()) { + cursor.movePosition(QTextCursor::NextWord, QTextCursor::MoveAnchor); + } else { + cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::MoveAnchor); + cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor); + } + cursor.setPosition(pos, QTextCursor::KeepAnchor); + cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor); + if (cursor.position() == pos) { + cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor); + cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); + + if (cursor.anchor() > cursor.position()) + cursor.setPosition(pos, QTextCursor::MoveAnchor); + } else { + cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); + } + } else if (cursor.anchor() > pos) { + cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor); + cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor); + if (cursor.position() == cursor.anchor()) { + cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor); + cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor); + } else { + cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor); + } + cursor.setPosition(pos, QTextCursor::KeepAnchor); + cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); + if (cursor.position() == pos) { + cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor); + + if (cursor.anchor() < cursor.position()) + cursor.setPosition(pos, QTextCursor::MoveAnchor); + } else { + cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); + cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor); + } + } else { + cursor.setPosition(pos, QTextCursor::MoveAnchor); + } d->control->setTextCursor(cursor); } @@ -655,7 +726,7 @@ void QDeclarativeTextEdit::setCursorPosition(int pos) if (pos < 0 || pos > d->text.length()) return; QTextCursor cursor = d->control->textCursor(); - if (cursor.position() == pos) + if (cursor.position() == pos && cursor.anchor() == pos) return; cursor.setPosition(pos); d->control->setTextCursor(cursor); diff --git a/src/declarative/graphicsitems/qdeclarativetextedit_p.h b/src/declarative/graphicsitems/qdeclarativetextedit_p.h index 37b24f7..6a05aa8 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextedit_p.h @@ -65,6 +65,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextEdit : public QDeclarativePaintedItem Q_ENUMS(HAlignment) Q_ENUMS(TextFormat) Q_ENUMS(WrapMode) + Q_ENUMS(SelectionMode) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) @@ -120,6 +121,11 @@ public: Wrap = QTextOption::WrapAtWordBoundaryOrAnywhere }; + enum SelectionMode { + SelectCharacters, + SelectWords + }; + Q_INVOKABLE void openSoftwareInputPanel(); Q_INVOKABLE void closeSoftwareInputPanel(); @@ -195,6 +201,7 @@ public: Q_INVOKABLE QRectF positionToRectangle(int) const; Q_INVOKABLE int positionAt(int x, int y) const; Q_INVOKABLE void moveCursorSelection(int pos); + Q_INVOKABLE Q_REVISION(1) void moveCursorSelection(int pos, SelectionMode mode); QRectF boundingRect() const; diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp index ac07d4b..491d219c4 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp @@ -50,6 +50,7 @@ #include <QApplication> #include <QFontMetrics> #include <QPainter> +#include <QTextBoundaryFinder> #ifndef QT_NO_LINEEDIT @@ -1320,35 +1321,119 @@ void QDeclarativeTextInput::setSelectByMouse(bool on) } } +void QDeclarativeTextInput::moveCursorSelection(int position) +{ + Q_D(QDeclarativeTextInput); + d->control->moveCursor(position, true); + d->updateHorizontalScroll(); +} /*! - \qmlmethod void TextInput::moveCursorSelection(int position) + \qmlmethod void TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters) + \since Quick 1.1 - Moves the cursor to \a position and updates the selection accordingly. - (To only move the cursor, set the \l cursorPosition property.) + Moves the cursor to \a position and updates the selection according to the optional \a mode + parameter. (To only move the cursor, set the \l cursorPosition property.) When this method is called it additionally sets either the selectionStart or the selectionEnd (whichever was at the previous cursor position) to the specified position. This allows you to easily extend and contract the selected text range. + The selection mode specifies whether the selection is updated on a per character or a per word + basis. If not specified the selection mode will default to TextInput.SelectCharacters. + + \list + \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at + the previous cursor position) to the specified position. + \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all + words between the specified postion and the previous cursor position. Words partially in the + range are included. + \endlist + For example, take this sequence of calls: \code cursorPosition = 5 - moveCursorSelection(9) - moveCursorSelection(7) + moveCursorSelection(9, TextInput.SelectCharacters) + moveCursorSelection(7, TextInput.SelectCharacters) \endcode This moves the cursor to position 5, extend the selection end from 5 to 9 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7 selected (the 6th and 7th characters). + + The same sequence with TextInput.SelectWords will extend the selection start to a word boundary + before or on position 5 and extend the selection end to a word boundary past position 9, and + then if there is a word boundary between position 7 and 8 retract the selection end to that + boundary. If there is whitespace at position 7 the selection will be retracted further. */ -void QDeclarativeTextInput::moveCursorSelection(int position) +void QDeclarativeTextInput::moveCursorSelection(int pos, SelectionMode mode) { Q_D(QDeclarativeTextInput); - d->control->moveCursor(position, true); - d->updateHorizontalScroll(); + + if (mode == SelectCharacters) { + d->control->moveCursor(pos, true); + } else if (pos != d->control->cursor()){ + int anchor; + if (!d->control->hasSelectedText()) + anchor = d->control->cursor(); + else if (d->control->selectionStart() == d->control->cursor()) + anchor = d->control->selectionEnd(); + else + anchor = d->control->selectionStart(); + + if (anchor < pos) { + QTextBoundaryFinder finder(QTextBoundaryFinder::Word, d->control->text()); + finder.setPosition(anchor); + + if (!(finder.boundaryReasons() & QTextBoundaryFinder::StartWord)) { + finder.toNextBoundary(); + if (finder.boundaryReasons() != QTextBoundaryFinder::StartWord) + finder.toPreviousBoundary(); + } + anchor = finder.position(); + + finder.setPosition(pos); + if (!(finder.boundaryReasons() & QTextBoundaryFinder::EndWord)) { + finder.toPreviousBoundary(); + if (finder.boundaryReasons() != QTextBoundaryFinder::EndWord) + finder.toNextBoundary(); + } + int cursor = finder.position(); + + if (anchor < cursor) + d->control->setSelection(anchor, cursor - anchor); + else + d->control->moveCursor(pos, false); + + } else if (anchor > pos) { + QTextBoundaryFinder finder(QTextBoundaryFinder::Word, d->control->text()); + + finder.setPosition(anchor); + if (!(finder.boundaryReasons() & QTextBoundaryFinder::EndWord)) { + finder.toPreviousBoundary(); + if (finder.boundaryReasons() != QTextBoundaryFinder::EndWord) + finder.toNextBoundary(); + } + anchor = finder.position(); + + finder.setPosition(pos); + if (!(finder.boundaryReasons() & QTextBoundaryFinder::StartWord)) { + finder.toNextBoundary(); + if (finder.boundaryReasons() != QTextBoundaryFinder::StartWord) + finder.toPreviousBoundary(); + } + int cursor = finder.position(); + + if (anchor > cursor) + d->control->setSelection(anchor, cursor - anchor); + else + d->control->moveCursor(pos, false); + } else { + d->control->moveCursor(pos, false); + } + } } /*! diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p.h index 878f040..25b8e66 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextinput_p.h @@ -63,6 +63,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextInput : public QDeclarativePaintedItem Q_OBJECT Q_ENUMS(HAlignment) Q_ENUMS(EchoMode) + Q_ENUMS(SelectionMode) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) @@ -112,10 +113,16 @@ public: AlignHCenter = Qt::AlignHCenter }; + enum SelectionMode { + SelectCharacters, + SelectWords + }; + //Auxilliary functions needed to control the TextInput from QML Q_INVOKABLE int positionAt(int x) const; Q_INVOKABLE QRectF positionToRectangle(int pos) const; Q_INVOKABLE void moveCursorSelection(int pos); + Q_INVOKABLE Q_REVISION(1) void moveCursorSelection(int pos, SelectionMode mode); Q_INVOKABLE void openSoftwareInputPanel(); Q_INVOKABLE void closeSoftwareInputPanel(); |