diff options
author | Andrew den Exter <andrew.den-exter@nokia.com> | 2011-11-11 13:47:59 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2011-12-16 00:53:17 +0100 |
commit | e7fb84adb5d5d9cc5c61db3bbd025f206854bcb4 (patch) | |
tree | f5e1d922b8cc0a3ffe01358efdddd15a93867d30 /src/quick/items/qquicktextinput_p_p.h | |
parent | d70cca804e88110eae32f92baff7cee957a6a531 (diff) |
Merge QQuickLineControl into QQuickTextInput.
There's no clear separation of responsibilty between these classes and
keeping them in sync and forwarding signals is a unnecessary overhead
that can be avoided by combining them.
Task-number: QTBUG-22627
Change-Id: I4350eb3c612b10d4ed34886374889ae893b8183a
Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'src/quick/items/qquicktextinput_p_p.h')
-rw-r--r-- | src/quick/items/qquicktextinput_p_p.h | 341 |
1 files changed, 305 insertions, 36 deletions
diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index 119df5fd39..b410bfd187 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -47,12 +47,13 @@ #include "qquicktext_p.h" #include "qquickimplicitsizeitem_p_p.h" -#include "qquicklinecontrol_p.h" - #include <QtDeclarative/qdeclarative.h> #include <QtCore/qelapsedtimer.h> #include <QtCore/qpointer.h> +#include <QtGui/qclipboard.h> #include <QtGui/qguiapplication.h> +#include <QtGui/qpalette.h> +#include <QtGui/qtextlayout.h> #include <QtGui/qstylehints.h> @@ -75,26 +76,50 @@ class Q_AUTOTEST_EXPORT QQuickTextInputPrivate : public QQuickImplicitSizeItemPr Q_DECLARE_PUBLIC(QQuickTextInput) public: QQuickTextInputPrivate() - : control(new QQuickLineControl(QString())) - , color((QRgb)0) - , style(QQuickText::Normal) - , styleColor((QRgb)0) - , hAlign(QQuickTextInput::AlignLeft) - , mouseSelectionMode(QQuickTextInput::SelectCharacters) - , inputMethodHints(Qt::ImhNone) - , textNode(0) - , hscroll(0) - , oldScroll(0) - , oldValidity(false) - , focused(false) - , focusOnPress(true) - , cursorVisible(false) - , autoScroll(true) - , selectByMouse(false) - , canPaste(false) - , hAlignImplicit(true) - , selectPressed(false) - , textLayoutDirty(true) + : color((QRgb)0) + , styleColor((QRgb)0) + , textNode(0) + , m_maskData(0) + , hscroll(0) + , oldScroll(0) + , m_cursor(0) + , m_preeditCursor(0) + , m_cursorWidth(1) + , m_blinkPeriod(0) + , m_blinkTimer(0) + , m_deleteAllTimer(0) + , m_ascent(0) + , m_maxLength(32767) + , m_lastCursorPos(-1) + , m_modifiedState(0) + , m_undoState(0) + , m_selstart(0) + , m_selend(0) + , style(QQuickText::Normal) + , hAlign(QQuickTextInput::AlignLeft) + , mouseSelectionMode(QQuickTextInput::SelectCharacters) + , inputMethodHints(Qt::ImhNone) + , m_layoutDirection(Qt::LayoutDirectionAuto) + , m_passwordCharacter(QLatin1Char('*')) + , oldValidity(false) + , focused(false) + , focusOnPress(true) + , cursorVisible(false) + , autoScroll(true) + , selectByMouse(false) + , canPaste(false) + , hAlignImplicit(true) + , selectPressed(false) + , textLayoutDirty(true) + , m_hideCursor(false) + , m_separator(0) + , m_readOnly(0) + , m_echoMode(QQuickTextInput::Normal) + , m_textDirty(0) + , m_selDirty(0) + , m_validInput(1) + , m_blinkStatus(0) + , m_passwordEchoEditing(false) { } @@ -102,44 +127,65 @@ public: { } - int xToPos(int x, QTextLine::CursorPosition betweenOrOn = QTextLine::CursorBetweenCharacters) const - { - Q_Q(const QQuickTextInput); - QRect cr = q->boundingRect().toRect(); - x-= cr.x() - hscroll; - return control->xToPos(x, betweenOrOn); - } - void init(); void startCreatingCursor(); void updateHorizontalScroll(); bool determineHorizontalAlignment(); bool setHAlign(QQuickTextInput::HAlignment, bool forceAlign = false); void mirrorChange(); - int calculateTextWidth(); bool sendMouseEventToInputContext(QMouseEvent *event); void updateInputMethodHints(); void hideCursor(); void showCursor(); - QQuickLineControl* control; + struct MaskInputData { + enum Casemode { NoCaseMode, Upper, Lower }; + QChar maskChar; // either the separator char or the inputmask + bool separator; + Casemode caseMode; + }; + + // undo/redo handling + enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection, SetSelection }; + struct Command { + inline Command() {} + inline Command(CommandType t, int p, QChar c, int ss, int se) : type(t),uc(c),pos(p),selStart(ss),selEnd(se) {} + uint type : 4; + QChar uc; + int pos, selStart, selEnd; + }; + enum DrawFlags { + DrawText = 0x01, + DrawSelections = 0x02, + DrawCursor = 0x04, + DrawAll = DrawText | DrawSelections | DrawCursor + }; + + QTextLayout m_textLayout; + QString m_text; + QString m_inputMask; + QString m_cancelText; + QString m_tentativeCommit; + QPalette m_palette; QFont font; QFont sourceFont; QColor color; QColor selectionColor; QColor selectedTextColor; - QQuickText::TextStyle style; QColor styleColor; - QQuickTextInput::HAlignment hAlign; - QQuickTextInput::SelectionMode mouseSelectionMode; - Qt::InputMethodHints inputMethodHints; QPointer<QDeclarativeComponent> cursorComponent; QPointer<QQuickItem> cursorItem; +#ifndef QT_NO_VALIDATOR + QPointer<QValidator> m_validator; +#endif QPointF pressPos; QQuickTextNode *textNode; + MaskInputData *m_maskData; QElapsedTimer tripleClickTimer; QPoint tripleClickStartPoint; + QList<int> m_transactions; + QVector<Command> m_history; int lastSelectionStart; int lastSelectionEnd; @@ -147,6 +193,28 @@ public: int oldWidth; int hscroll; int oldScroll; + int m_cursor; + int m_preeditCursor; + int m_cursorWidth; + int m_blinkPeriod; // 0 for non-blinking cursor + int m_blinkTimer; + int m_deleteAllTimer; + int m_ascent; + int m_maxLength; + int m_lastCursorPos; + int m_modifiedState; + int m_undoState; + int m_selstart; + int m_selend; + + QQuickText::TextStyle style; + QQuickTextInput::HAlignment hAlign; + QQuickTextInput::SelectionMode mouseSelectionMode; + Qt::InputMethodHints inputMethodHints; + Qt::LayoutDirection m_layoutDirection; + + QChar m_blank; + QChar m_passwordCharacter; bool oldValidity:1; bool focused:1; @@ -159,12 +227,213 @@ public: bool selectPressed:1; bool textLayoutDirty:1; + uint m_hideCursor : 1; // used to hide the m_cursor inside preedit areas + uint m_separator : 1; + uint m_readOnly : 1; + uint m_echoMode : 2; + uint m_textDirty : 1; + uint m_selDirty : 1; + uint m_validInput : 1; + uint m_blinkStatus : 1; + uint m_passwordEchoEditing; + static inline QQuickTextInputPrivate *get(QQuickTextInput *t) { return t->d_func(); } bool hasPendingTripleClick() const { return !tripleClickTimer.hasExpired(qApp->styleHints()->mouseDoubleClickInterval()); } + + + int nextMaskBlank(int pos) + { + int c = findInMask(pos, true, false); + m_separator |= (c != pos); + return (c != -1 ? c : m_maxLength); + } + + int prevMaskBlank(int pos) + { + int c = findInMask(pos, false, false); + m_separator |= (c != pos); + return (c != -1 ? c : 0); + } + + bool isUndoAvailable() const { return !m_readOnly && m_undoState; } + bool isRedoAvailable() const { return !m_readOnly && m_undoState < (int)m_history.size(); } + void clearUndo() { m_history.clear(); m_modifiedState = m_undoState = 0; } + + bool isModified() const { return m_modifiedState != m_undoState; } + void setModified(bool modified) { m_modifiedState = modified ? -1 : m_undoState; } + + bool allSelected() const { return !m_text.isEmpty() && m_selstart == 0 && m_selend == (int)m_text.length(); } + bool hasSelectedText() const { return !m_text.isEmpty() && m_selend > m_selstart; } + + int calculateTextHeight() const { return qRound(m_textLayout.lineAt(0).height()); } + int calculateTextWidth() const { return qRound(m_textLayout.lineAt(0).naturalTextWidth()); } + int ascent() const { return m_ascent; } + + void setSelection(int start, int length); + + inline QString selectedText() const { return hasSelectedText() ? m_text.mid(m_selstart, m_selend - m_selstart) : QString(); } + QString textBeforeSelection() const { return hasSelectedText() ? m_text.left(m_selstart) : QString(); } + QString textAfterSelection() const { return hasSelectedText() ? m_text.mid(m_selend) : QString(); } + + int selectionStart() const { return hasSelectedText() ? m_selstart : -1; } + int selectionEnd() const { return hasSelectedText() ? m_selend : -1; } + bool inSelection(int x) const + { + if (m_selstart >= m_selend) + return false; + int pos = xToPos(x, QTextLine::CursorOnCharacter); + return pos >= m_selstart && pos < m_selend; + } + + void removeSelection() + { + int priorState = m_undoState; + removeSelectedText(); + finishChange(priorState); + } + + int start() const { return 0; } + int end() const { return m_text.length(); } + + QString realText() const; + +#ifndef QT_NO_CLIPBOARD + void copy(QClipboard::Mode mode = QClipboard::Clipboard) const; + void paste(QClipboard::Mode mode = QClipboard::Clipboard); +#endif + + void commitPreedit(); + + Qt::CursorMoveStyle cursorMoveStyle() const { return m_textLayout.cursorMoveStyle(); } + void setCursorMoveStyle(Qt::CursorMoveStyle style) { m_textLayout.setCursorMoveStyle(style); } + + void moveCursor(int pos, bool mark = false); + void cursorForward(bool mark, int steps) + { + int c = m_cursor; + if (steps > 0) { + while (steps--) + c = cursorMoveStyle() == Qt::VisualMoveStyle ? m_textLayout.rightCursorPosition(c) + : m_textLayout.nextCursorPosition(c); + } else if (steps < 0) { + while (steps++) + c = cursorMoveStyle() == Qt::VisualMoveStyle ? m_textLayout.leftCursorPosition(c) + : m_textLayout.previousCursorPosition(c); + } + moveCursor(c, mark); + } + + void cursorWordForward(bool mark) { moveCursor(m_textLayout.nextCursorPosition(m_cursor, QTextLayout::SkipWords), mark); } + void cursorWordBackward(bool mark) { moveCursor(m_textLayout.previousCursorPosition(m_cursor, QTextLayout::SkipWords), mark); } + + void home(bool mark) { moveCursor(0, mark); } + void end(bool mark) { moveCursor(q_func()->text().length(), mark); } + + int xToPos(int x, QTextLine::CursorPosition = QTextLine::CursorBetweenCharacters) const; + + qreal cursorToX(int cursor) const { return m_textLayout.lineAt(0).cursorToX(cursor); } + qreal cursorToX() const + { + int cursor = m_cursor; + if (m_preeditCursor != -1) + cursor += m_preeditCursor; + return cursorToX(cursor); + } + + void backspace(); + void del(); + void deselect() { internalDeselect(); finishChange(); } + void selectAll() { m_selstart = m_selend = m_cursor = 0; moveCursor(m_text.length(), true); } + + void insert(const QString &); + void clear(); + void undo() { internalUndo(); finishChange(-1, true); } + void redo() { internalRedo(); finishChange(); } + void selectWordAtPos(int); + + void setCursorPosition(int pos) { if (pos <= m_text.length()) moveCursor(qMax(0, pos)); } + + bool fixup(); + + QString inputMask() const { return m_maskData ? m_inputMask + QLatin1Char(';') + m_blank : QString(); } + void setInputMask(const QString &mask) + { + parseInputMask(mask); + if (m_maskData) + moveCursor(nextMaskBlank(0)); + } + + // input methods +#ifndef QT_NO_IM + bool composeMode() const { return !m_textLayout.preeditAreaText().isEmpty(); } +#endif + + QString preeditAreaText() const { return m_textLayout.preeditAreaText(); } + + void updatePasswordEchoEditing(bool editing); + + Qt::LayoutDirection layoutDirection() const { + if (m_layoutDirection == Qt::LayoutDirectionAuto) { + if (m_text.isEmpty()) + return QGuiApplication::keyboardInputDirection(); + return m_text.isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight; + } + return m_layoutDirection; + } + void setLayoutDirection(Qt::LayoutDirection direction) + { + if (direction != m_layoutDirection) { + m_layoutDirection = direction; + updateDisplayText(); + } + } + + void processInputMethodEvent(QInputMethodEvent *event); + void processKeyEvent(QKeyEvent* ev); + + void setCursorBlinkPeriod(int msec); + void resetCursorBlinkTimer(); + +private: + void init(const QString &txt); + void removeSelectedText(); + void internalSetText(const QString &txt, int pos = -1, bool edited = true); + void updateDisplayText(bool forceUpdate = false); + + void internalInsert(const QString &s); + void internalDelete(bool wasBackspace = false); + void internalRemove(int pos); + + inline void internalDeselect() + { + m_selDirty |= (m_selend > m_selstart); + m_selstart = m_selend = 0; + } + + void internalUndo(int until = -1); + void internalRedo(); + + void emitCursorPositionChanged(); + + bool finishChange(int validateFromState = -1, bool update = false, bool edited = true); + + void addCommand(const Command& cmd); + + inline void separate() { m_separator = true; } + + + // masking + void parseInputMask(const QString &maskFields); + bool isValidInput(QChar key, QChar mask) const; + bool hasAcceptableInput(const QString &text) const; + QString maskString(uint pos, const QString &str, bool clear = false) const; + QString clearString(uint pos, uint len) const; + QString stripString(const QString &str) const; + int findInMask(int pos, bool forward, bool findSeparator, QChar searchChar = QChar()) const; }; QT_END_NAMESPACE |