aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquicktextinput_p_p.h
diff options
context:
space:
mode:
authorAndrew den Exter <andrew.den-exter@nokia.com>2011-11-11 13:47:59 +1000
committerQt by Nokia <qt-info@nokia.com>2011-12-16 00:53:17 +0100
commite7fb84adb5d5d9cc5c61db3bbd025f206854bcb4 (patch)
treef5e1d922b8cc0a3ffe01358efdddd15a93867d30 /src/quick/items/qquicktextinput_p_p.h
parentd70cca804e88110eae32f92baff7cee957a6a531 (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.h341
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