diff options
author | Andrew den Exter <andrew.den-exter@nokia.com> | 2011-01-28 05:58:37 (GMT) |
---|---|---|
committer | Andrew den Exter <andrew.den-exter@nokia.com> | 2011-02-01 00:00:30 (GMT) |
commit | ba63becc13221ca6538fb40c790275465dd47703 (patch) | |
tree | 46d27e12faee710564866b2779343f7ac5791209 /src | |
parent | 2b337d8cbe8e6646ec78b3acaad50ce108d33dc0 (diff) | |
download | Qt-ba63becc13221ca6538fb40c790275465dd47703.zip Qt-ba63becc13221ca6538fb40c790275465dd47703.tar.gz Qt-ba63becc13221ca6538fb40c790275465dd47703.tar.bz2 |
Add a mouseSelectionMode property to TextEdit and TextInput.
Adds an option to do per word selection when selectByMouse is true.
Also changes the selection behavior so that the first word selected
remains selected when the direction of the selection changes which
is more consistent with other implementations including the existing
per word selection in QTextEdit.
Task-number: QTBUG-16283
Reviewed-by: Martin Jones
Diffstat (limited to 'src')
-rw-r--r-- | src/declarative/graphicsitems/qdeclarativetextedit.cpp | 84 | ||||
-rw-r--r-- | src/declarative/graphicsitems/qdeclarativetextedit_p.h | 5 | ||||
-rw-r--r-- | src/declarative/graphicsitems/qdeclarativetextedit_p_p.h | 3 | ||||
-rw-r--r-- | src/declarative/graphicsitems/qdeclarativetextinput.cpp | 90 | ||||
-rw-r--r-- | src/declarative/graphicsitems/qdeclarativetextinput_p.h | 5 | ||||
-rw-r--r-- | src/declarative/graphicsitems/qdeclarativetextinput_p_p.h | 2 | ||||
-rw-r--r-- | src/gui/text/qtextcontrol.cpp | 27 | ||||
-rw-r--r-- | src/gui/text/qtextcontrol_p.h | 5 | ||||
-rw-r--r-- | src/gui/text/qtextcontrol_p_p.h | 2 |
9 files changed, 148 insertions, 75 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp index 959d655..f63e4cb 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp @@ -653,9 +653,7 @@ void QDeclarativeTextEdit::moveCursorSelection(int pos) 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. + before or on position 5 and extend the selection end to a word boundary on or past position 9. */ void QDeclarativeTextEdit::moveCursorSelection(int pos, SelectionMode mode) { @@ -665,48 +663,43 @@ void QDeclarativeTextEdit::moveCursorSelection(int pos, SelectionMode mode) return; 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 if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) { + if (cursor.anchor() > cursor.position()) { + cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor); + cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor); + if (cursor.position() == cursor.anchor()) + cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor); + else + cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor); } else { - cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::MoveAnchor); + cursor.setPosition(cursor.anchor(), 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); + if (cursor.position() != pos) 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); + } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) { + if (cursor.anchor() < cursor.position()) { + cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor); cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor); } else { - cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor); + cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor); + cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); + cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); + if (cursor.position() != cursor.anchor()) { + cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor); + 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 { + if (cursor.position() != pos) { cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor); } - } else { - cursor.setPosition(pos, QTextCursor::MoveAnchor); } d->control->setTextCursor(cursor); } @@ -986,6 +979,35 @@ void QDeclarativeTextEdit::setSelectByMouse(bool on) } +/*! + \qmlproperty enum TextEdit::mouseSelectionMode + \since Quick 1.1 + + Specifies how text should be selected using a mouse. + + \list + \o TextEdit.SelectCharacters - The selection is updated with individual characters. (Default) + \o TextEdit.SelectWords - The selection is updated with whole words. + \endlist + + This property only applies when \l selectByMouse is true. +*/ + +QDeclarativeTextEdit::SelectionMode QDeclarativeTextEdit::mouseSelectionMode() const +{ + Q_D(const QDeclarativeTextEdit); + return d->mouseSelectionMode; +} + +void QDeclarativeTextEdit::setMouseSelectionMode(SelectionMode mode) +{ + Q_D(QDeclarativeTextEdit); + if (d->mouseSelectionMode != mode) { + d->mouseSelectionMode = mode; + d->control->setWordSelectionEnabled(mode == SelectWords); + emit mouseSelectionModeChanged(mode); + } +} /*! \qmlproperty bool TextEdit::readOnly diff --git a/src/declarative/graphicsitems/qdeclarativetextedit_p.h b/src/declarative/graphicsitems/qdeclarativetextedit_p.h index db3cb2d..7785a7a 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextedit_p.h @@ -92,6 +92,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextEdit : public QDeclarativeImplicitSizePa Q_PROPERTY(qreal textMargin READ textMargin WRITE setTextMargin NOTIFY textMarginChanged) Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints) Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged) + Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged REVISION 1) Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged REVISION 1) public: @@ -186,6 +187,9 @@ public: bool selectByMouse() const; void setSelectByMouse(bool); + SelectionMode mouseSelectionMode() const; + void setMouseSelectionMode(SelectionMode mode); + bool canPaste() const; virtual void componentComplete(); @@ -235,6 +239,7 @@ Q_SIGNALS: void persistentSelectionChanged(bool isPersistentSelection); void textMarginChanged(qreal textMargin); void selectByMouseChanged(bool selectByMouse); + Q_REVISION(1) void mouseSelectionModeChanged(SelectionMode mode); Q_REVISION(1) void linkActivated(const QString &link); Q_REVISION(1) void canPasteChanged(); diff --git a/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h b/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h index 98b3c6d..111cc02 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h @@ -73,7 +73,7 @@ public: showInputPanelOnFocus(true), clickCausedFocus(false), persistentSelection(true), requireImplicitWidth(false), textMargin(0.0), lastSelectionStart(0), lastSelectionEnd(0), cursorComponent(0), cursor(0), format(QDeclarativeTextEdit::AutoText), document(0), wrapMode(QDeclarativeTextEdit::NoWrap), - selectByMouse(false), canPaste(false), + mouseSelectionMode(QDeclarativeTextEdit::SelectCharacters), selectByMouse(false), canPaste(false), yoff(0) { #ifdef Q_OS_SYMBIAN @@ -121,6 +121,7 @@ public: QTextDocument *document; QTextControl *control; QDeclarativeTextEdit::WrapMode wrapMode; + QDeclarativeTextEdit::SelectionMode mouseSelectionMode; int lineCount; bool selectByMouse; bool canPaste; diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp index 3d2466d..9e62291 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp @@ -1022,7 +1022,7 @@ void QDeclarativeTextInput::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeTextInput); if (d->selectByMouse) { - d->control->moveCursor(d->xToPos(event->pos().x()), true); + moveCursorSelection(d->xToPos(event->pos().x()), d->mouseSelectionMode); event->setAccepted(true); } else { QDeclarativePaintedItem::mouseMoveEvent(event); @@ -1348,6 +1348,35 @@ void QDeclarativeTextInput::setSelectByMouse(bool on) } } +/*! + \qmlproperty enum TextInput::mouseSelectionMode + \since Quick 1.1 + + Specifies how text should be selected using a mouse. + + \list + \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default) + \o TextInput.SelectWords - The selection is updated with whole words. + \endlist + + This property only applies when \l selectByMouse is true. +*/ + +QDeclarativeTextInput::SelectionMode QDeclarativeTextInput::mouseSelectionMode() const +{ + Q_D(const QDeclarativeTextInput); + return d->mouseSelectionMode; +} + +void QDeclarativeTextInput::setMouseSelectionMode(SelectionMode mode) +{ + Q_D(QDeclarativeTextInput); + if (d->mouseSelectionMode != mode) { + d->mouseSelectionMode = mode; + emit mouseSelectionModeChanged(mode); + } +} + bool QDeclarativeTextInput::canPaste() const { Q_D(const QDeclarativeTextInput); @@ -1397,9 +1426,7 @@ void QDeclarativeTextInput::moveCursorSelection(int position) 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. + before or on position 5 and extend the selection end to a word boundary on or past position 9. */ void QDeclarativeTextInput::moveCursorSelection(int pos, SelectionMode mode) { @@ -1408,6 +1435,7 @@ void QDeclarativeTextInput::moveCursorSelection(int pos, SelectionMode mode) if (mode == SelectCharacters) { d->control->moveCursor(pos, true); } else if (pos != d->control->cursor()){ + const int cursor = d->control->cursor(); int anchor; if (!d->control->hasSelectedText()) anchor = d->control->cursor(); @@ -1416,55 +1444,39 @@ void QDeclarativeTextInput::moveCursorSelection(int pos, SelectionMode mode) else anchor = d->control->selectionStart(); - if (anchor < pos) { + if (anchor < pos || (anchor == pos && cursor < 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(); + const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons(); + if (!(reasons & QTextBoundaryFinder::StartWord) + || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor)) { + 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 (!finder.isAtBoundary()) + finder.toNextBoundary(); - if (anchor < cursor) - d->control->setSelection(anchor, cursor - anchor); - else - d->control->moveCursor(pos, false); - - } else if (anchor > pos) { + d->control->setSelection(anchor, finder.position() - anchor); + } else if (anchor > pos || (anchor == pos && cursor > 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(); + + const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons(); + if (!(reasons & QTextBoundaryFinder::EndWord) + || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor)) { + 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); + if (!finder.isAtBoundary()) + finder.toPreviousBoundary(); + + d->control->setSelection(anchor, finder.position() - anchor); } } } diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p.h index 543f7a8..63d0e53 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextinput_p.h @@ -95,6 +95,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextInput : public QDeclarativeImplicitSizeP Q_PROPERTY(QString displayText READ displayText NOTIFY displayTextChanged) Q_PROPERTY(bool autoScroll READ autoScroll WRITE setAutoScroll NOTIFY autoScrollChanged) Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged) + Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged REVISION 1) Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged REVISION 1) public: @@ -192,6 +193,9 @@ public: bool selectByMouse() const; void setSelectByMouse(bool); + SelectionMode mouseSelectionMode() const; + void setMouseSelectionMode(SelectionMode mode); + bool hasAcceptableInput() const; void drawContents(QPainter *p,const QRect &r); @@ -225,6 +229,7 @@ Q_SIGNALS: void activeFocusOnPressChanged(bool activeFocusOnPress); void autoScrollChanged(bool autoScroll); void selectByMouseChanged(bool selectByMouse); + Q_REVISION(1) void mouseSelectionModeChanged(SelectionMode mode); Q_REVISION(1) void canPasteChanged(); protected: diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h index 1f45c11..7a0086e 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h @@ -73,6 +73,7 @@ public: QDeclarativeTextInputPrivate() : control(new QLineControl(QString())), color((QRgb)0), style(QDeclarativeText::Normal), styleColor((QRgb)0), hAlign(QDeclarativeTextInput::AlignLeft), + mouseSelectionMode(QDeclarativeTextInput::SelectCharacters), hscroll(0), oldScroll(0), focused(false), focusOnPress(true), showInputPanelOnFocus(true), clickCausedFocus(false), cursorVisible(false), autoScroll(true), selectByMouse(false), canPaste(false) @@ -114,6 +115,7 @@ public: QDeclarativeText::TextStyle style; QColor styleColor; QDeclarativeTextInput::HAlignment hAlign; + QDeclarativeTextInput::SelectionMode mouseSelectionMode; QPointer<QDeclarativeComponent> cursorComponent; QPointer<QDeclarativeItem> cursorItem; diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index 030e196..e380b37 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -129,7 +129,8 @@ QTextControlPrivate::QTextControlPrivate() isEnabled(true), hadSelectionOnMousePress(false), ignoreUnusedNavigationEvents(false), - openExternalLinks(false) + openExternalLinks(false), + wordSelectionEnabled(false) {} bool QTextControlPrivate::cursorMoveKeyEvent(QKeyEvent *e) @@ -1544,11 +1545,16 @@ void QTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton button, con } #endif if (modifiers == Qt::ShiftModifier) { + if (wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) { + selectedWordOnDoubleClick = cursor; + selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor); + } + if (selectedBlockOnTrippleClick.hasSelection()) extendBlockwiseSelection(cursorPos); else if (selectedWordOnDoubleClick.hasSelection()) extendWordwiseSelection(cursorPos, pos.x()); - else + else if (wordSelectionEnabled) setCursorPosition(cursorPos, QTextCursor::KeepAnchor); } else { @@ -1626,6 +1632,11 @@ void QTextControlPrivate::mouseMoveEvent(Qt::MouseButtons buttons, const QPointF if (newCursorPos == -1) return; + if (wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) { + selectedWordOnDoubleClick = cursor; + selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor); + } + if (selectedBlockOnTrippleClick.hasSelection()) extendBlockwiseSelection(newCursorPos); else if (selectedWordOnDoubleClick.hasSelection()) @@ -2343,6 +2354,18 @@ bool QTextControl::isDragEnabled() const return d->dragEnabled; } +void QTextControl::setWordSelectionEnabled(bool enabled) +{ + Q_D(QTextControl); + d->wordSelectionEnabled = enabled; +} + +bool QTextControl::isWordSelectionEnabled() const +{ + Q_D(const QTextControl); + return d->wordSelectionEnabled; +} + #ifndef QT_NO_PRINTER void QTextControl::print(QPrinter *printer) const { diff --git a/src/gui/text/qtextcontrol_p.h b/src/gui/text/qtextcontrol_p.h index 9277b68..31fa843 100644 --- a/src/gui/text/qtextcontrol_p.h +++ b/src/gui/text/qtextcontrol_p.h @@ -178,6 +178,9 @@ public: void setDragEnabled(bool enabled); bool isDragEnabled() const; + bool isWordSelectionEnabled() const; + void setWordSelectionEnabled(bool enabled); + #ifndef QT_NO_PRINTER void print(QPrinter *printer) const; #endif @@ -186,8 +189,6 @@ public: virtual QRectF blockBoundingRect(const QTextBlock &block) const; QAbstractTextDocumentLayout::PaintContext getPaintContext(QWidget *widget) const; - - public Q_SLOTS: void setPlainText(const QString &text); void setHtml(const QString &text); diff --git a/src/gui/text/qtextcontrol_p_p.h b/src/gui/text/qtextcontrol_p_p.h index d7463ca..ecd13ea 100644 --- a/src/gui/text/qtextcontrol_p_p.h +++ b/src/gui/text/qtextcontrol_p_p.h @@ -211,6 +211,8 @@ public: bool ignoreUnusedNavigationEvents; bool openExternalLinks; + bool wordSelectionEnabled; + QString linkToCopy; void _q_copyLink(); void _q_updateBlock(const QTextBlock &); |