1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #ifndef QQUICKTEXTINPUT_P_P_H
43 #define QQUICKTEXTINPUT_P_P_H
45 #include "qquicktextinput_p.h"
46 #include "qquicktext_p.h"
47 #include "qquickimplicitsizeitem_p_p.h"
49 #include <QtQml/qqml.h>
50 #include <QtCore/qelapsedtimer.h>
51 #include <QtCore/qpointer.h>
52 #include <QtCore/qbasictimer.h>
53 #include <QtGui/qclipboard.h>
54 #include <QtGui/qguiapplication.h>
55 #include <QtGui/qpalette.h>
56 #include <QtGui/qtextlayout.h>
57 #include <QtGui/qstylehints.h>
59 #include "qplatformdefs.h"
65 // This file is not part of the Qt API. It exists purely as an
66 // implementation detail. This header file may change from version to
67 // version without notice, or even be removed.
75 class Q_AUTOTEST_EXPORT QQuickTextInputPrivate : public QQuickImplicitSizeItemPrivate
77 Q_DECLARE_PUBLIC(QQuickTextInput)
79 QQuickTextInputPrivate()
85 , color(QRgb(0xFF000000))
86 , selectionColor(QRgb(0xFF000080))
87 , selectedTextColor(QRgb(0xFFFFFFFF))
97 , inputMethodHints(Qt::ImhNone)
98 , hAlign(QQuickTextInput::AlignLeft)
99 , vAlign(QQuickTextInput::AlignTop)
100 , wrapMode(QQuickTextInput::NoWrap)
101 , m_echoMode(QQuickTextInput::Normal)
102 , updateType(UpdatePaintNode)
103 , mouseSelectionMode(QQuickTextInput::SelectCharacters)
104 , m_layoutDirection(Qt::LayoutDirectionAuto)
105 , m_passwordCharacter(QLatin1Char('*'))
107 , cursorVisible(false)
109 , selectByMouse(false)
111 , canPasteValid(false)
114 , hAlignImplicit(true)
115 , selectPressed(false)
116 , textLayoutDirty(true)
117 , persistentSelection(false)
118 , m_hideCursor(false)
125 , m_acceptableInput(1)
127 , m_passwordEchoEditing(false)
131 ~QQuickTextInputPrivate()
136 void startCreatingCursor();
137 void updateHorizontalScroll();
138 void updateVerticalScroll();
139 bool determineHorizontalAlignment();
140 bool setHAlign(QQuickTextInput::HAlignment, bool forceAlign = false);
142 bool sendMouseEventToInputContext(QMouseEvent *event);
143 Qt::InputMethodHints effectiveInputMethodHints() const;
148 struct MaskInputData {
149 enum Casemode { NoCaseMode, Upper, Lower };
150 QChar maskChar; // either the separator char or the inputmask
155 // undo/redo handling
156 enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection, SetSelection };
159 inline Command(CommandType t, int p, QChar c, int ss, int se) : type(t),uc(c),pos(p),selStart(ss),selEnd(se) {}
162 int pos, selStart, selEnd;
167 DrawSelections = 0x02,
169 DrawAll = DrawText | DrawSelections | DrawCursor
172 QElapsedTimer tripleClickTimer;
175 QPointF tripleClickStartPoint;
177 QQmlGuard<QQmlComponent> cursorComponent;
178 #ifndef QT_NO_VALIDATOR
179 QQmlGuard<QValidator> m_validator;
185 QTextLayout m_textLayout;
188 QString m_cancelText;
189 QString m_tentativeCommit;
193 QQuickItem *cursorItem;
194 QQuickTextNode *textNode;
195 MaskInputData *m_maskData;
197 QList<int> m_transactions;
198 QVector<Command> m_history;
201 QColor selectionColor;
202 QColor selectedTextColor;
204 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
205 QBasicTimer m_passwordEchoTimer;
207 int lastSelectionStart;
208 int lastSelectionEnd;
211 int m_blinkPeriod; // 0 for non-blinking cursor
221 UpdateOnlyPreprocess,
225 Qt::InputMethodHints inputMethodHints;
226 QQuickTextInput::HAlignment hAlign;
227 QQuickTextInput::VAlignment vAlign;
228 QQuickTextInput::WrapMode wrapMode;
229 QQuickTextInput::EchoMode m_echoMode;
230 UpdateType updateType;
231 QQuickTextInput::SelectionMode mouseSelectionMode;
232 Qt::LayoutDirection m_layoutDirection;
235 QChar m_passwordCharacter;
238 bool cursorVisible:1;
240 bool selectByMouse:1;
242 bool canPasteValid:1;
245 bool hAlignImplicit:1;
246 bool selectPressed:1;
247 bool textLayoutDirty:1;
248 bool persistentSelection:1;
249 bool m_hideCursor : 1; // used to hide the m_cursor inside preedit areas
250 bool m_separator : 1;
252 bool m_textDirty : 1;
253 bool m_preeditDirty : 1;
255 bool m_validInput : 1;
256 bool m_acceptableInput : 1;
257 bool m_blinkStatus : 1;
258 bool m_passwordEchoEditing : 1;
261 static inline QQuickTextInputPrivate *get(QQuickTextInput *t) {
264 bool hasPendingTripleClick() const {
265 return !tripleClickTimer.hasExpired(qApp->styleHints()->mouseDoubleClickInterval());
269 int nextMaskBlank(int pos)
271 int c = findInMask(pos, true, false);
272 m_separator |= (c != pos);
273 return (c != -1 ? c : m_maxLength);
276 int prevMaskBlank(int pos)
278 int c = findInMask(pos, false, false);
279 m_separator |= (c != pos);
280 return (c != -1 ? c : 0);
283 bool isUndoAvailable() const { return !m_readOnly && m_undoState; }
284 bool isRedoAvailable() const { return !m_readOnly && m_undoState < (int)m_history.size(); }
285 void clearUndo() { m_history.clear(); m_undoState = 0; }
287 bool allSelected() const { return !m_text.isEmpty() && m_selstart == 0 && m_selend == (int)m_text.length(); }
288 bool hasSelectedText() const { return !m_text.isEmpty() && m_selend > m_selstart; }
290 void setSelection(int start, int length);
292 inline QString selectedText() const { return hasSelectedText() ? m_text.mid(m_selstart, m_selend - m_selstart) : QString(); }
293 QString textBeforeSelection() const { return hasSelectedText() ? m_text.left(m_selstart) : QString(); }
294 QString textAfterSelection() const { return hasSelectedText() ? m_text.mid(m_selend) : QString(); }
296 int selectionStart() const { return hasSelectedText() ? m_selstart : -1; }
297 int selectionEnd() const { return hasSelectedText() ? m_selend : -1; }
299 int positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const;
300 int positionAt(const QPointF &point, QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters) const {
301 return positionAt(point.x(), point.y(), position);
304 void removeSelection()
306 int priorState = m_undoState;
307 removeSelectedText();
308 finishChange(priorState);
311 int start() const { return 0; }
312 int end() const { return m_text.length(); }
314 QString realText() const;
316 #ifndef QT_NO_CLIPBOARD
317 void copy(QClipboard::Mode mode = QClipboard::Clipboard) const;
318 void paste(QClipboard::Mode mode = QClipboard::Clipboard);
321 void commitPreedit();
323 Qt::CursorMoveStyle cursorMoveStyle() const { return m_textLayout.cursorMoveStyle(); }
324 void setCursorMoveStyle(Qt::CursorMoveStyle style) { m_textLayout.setCursorMoveStyle(style); }
326 void moveCursor(int pos, bool mark = false);
327 void cursorForward(bool mark, int steps)
332 c = cursorMoveStyle() == Qt::VisualMoveStyle ? m_textLayout.rightCursorPosition(c)
333 : m_textLayout.nextCursorPosition(c);
334 } else if (steps < 0) {
336 c = cursorMoveStyle() == Qt::VisualMoveStyle ? m_textLayout.leftCursorPosition(c)
337 : m_textLayout.previousCursorPosition(c);
342 void cursorWordForward(bool mark) { moveCursor(m_textLayout.nextCursorPosition(m_cursor, QTextLayout::SkipWords), mark); }
343 void cursorWordBackward(bool mark) { moveCursor(m_textLayout.previousCursorPosition(m_cursor, QTextLayout::SkipWords), mark); }
345 void home(bool mark) { moveCursor(0, mark); }
346 void end(bool mark) { moveCursor(q_func()->text().length(), mark); }
350 void deselect() { internalDeselect(); finishChange(); }
351 void selectAll() { m_selstart = m_selend = m_cursor = 0; moveCursor(m_text.length(), true); }
353 void insert(const QString &);
355 void selectWordAtPos(int);
357 void setCursorPosition(int pos) { if (pos <= m_text.length()) moveCursor(qMax(0, pos)); }
361 QString inputMask() const { return m_maskData ? m_inputMask + QLatin1Char(';') + m_blank : QString(); }
362 void setInputMask(const QString &mask)
364 parseInputMask(mask);
366 moveCursor(nextMaskBlank(0));
371 bool composeMode() const { return !m_textLayout.preeditAreaText().isEmpty(); }
374 QString preeditAreaText() const { return m_textLayout.preeditAreaText(); }
376 void updatePasswordEchoEditing(bool editing);
378 void cancelPasswordEchoTimer() {
379 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
380 m_passwordEchoTimer.stop();
384 Qt::LayoutDirection layoutDirection() const {
385 if (m_layoutDirection == Qt::LayoutDirectionAuto) {
386 if (m_text.isEmpty())
387 return qApp->inputMethod()->inputDirection();
388 return m_text.isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight;
390 return m_layoutDirection;
392 void setLayoutDirection(Qt::LayoutDirection direction)
394 if (direction != m_layoutDirection) {
395 m_layoutDirection = direction;
400 void processInputMethodEvent(QInputMethodEvent *event);
401 void processKeyEvent(QKeyEvent* ev);
403 void setCursorBlinkPeriod(int msec);
408 void init(const QString &txt);
409 void removeSelectedText();
410 void internalSetText(const QString &txt, int pos = -1, bool edited = true);
411 void updateDisplayText(bool forceUpdate = false);
413 void internalInsert(const QString &s);
414 void internalDelete(bool wasBackspace = false);
415 void internalRemove(int pos);
417 inline void internalDeselect()
419 m_selDirty |= (m_selend > m_selstart);
420 m_selstart = m_selend = 0;
423 void internalUndo(int until = -1);
425 void emitUndoRedoChanged();
427 bool emitCursorPositionChanged();
429 bool finishChange(int validateFromState = -1, bool update = false, bool edited = true);
431 void addCommand(const Command& cmd);
433 inline void separate() { m_separator = true; }
435 enum ValidatorState {
436 #ifndef QT_NO_VALIDATOR
437 InvalidInput = QValidator::Invalid,
438 IntermediateInput = QValidator::Intermediate,
439 AcceptableInput = QValidator::Acceptable
448 void parseInputMask(const QString &maskFields);
449 bool isValidInput(QChar key, QChar mask) const;
450 ValidatorState hasAcceptableInput(const QString &text) const;
452 QString maskString(uint pos, const QString &str, bool clear = false) const;
453 QString clearString(uint pos, uint len) const;
454 QString stripString(const QString &str) const;
455 int findInMask(int pos, bool forward, bool findSeparator, QChar searchChar = QChar()) const;
460 #endif // QQUICKTEXTINPUT_P_P_H