1921451f88393794af8076a35a1fb80a6df5b506
[profile/ivi/qtdeclarative.git] / src / quick / items / qquicktextinput_p_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #ifndef QQUICKTEXTINPUT_P_P_H
43 #define QQUICKTEXTINPUT_P_P_H
44
45 #include "qquicktextinput_p.h"
46 #include "qquicktext_p.h"
47 #include "qquickimplicitsizeitem_p_p.h"
48
49 #include <QtDeclarative/qdeclarative.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>
58
59 #include "qplatformdefs.h"
60
61 //
62 //  W A R N I N G
63 //  -------------
64 //
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.
68 //
69 // We mean it.
70
71 QT_BEGIN_NAMESPACE
72
73 class QQuickTextNode;
74
75 class Q_AUTOTEST_EXPORT QQuickTextInputPrivate : public QQuickImplicitSizeItemPrivate
76 {
77     Q_DECLARE_PUBLIC(QQuickTextInput)
78 public:
79     QQuickTextInputPrivate()
80         : hscroll(0)
81         , vscroll(0)
82         , cursorItem(0)
83         , textNode(0)
84         , m_maskData(0)
85         , color(QRgb(0xFF000000))
86         , selectionColor(QRgb(0xFF000080))
87         , selectedTextColor(QRgb(0xFFFFFFFF))
88         , m_cursor(0)
89         , m_preeditCursor(0)
90         , m_blinkPeriod(0)
91         , m_blinkTimer(0)
92         , m_maxLength(32767)
93         , m_lastCursorPos(-1)
94         , m_undoState(0)
95         , m_selstart(0)
96         , m_selend(0)
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('*'))
106         , focusOnPress(true)
107         , cursorVisible(false)
108         , autoScroll(true)
109         , selectByMouse(false)
110         , canPaste(false)
111         , canPasteValid(false)
112         , canUndo(false)
113         , canRedo(false)
114         , hAlignImplicit(true)
115         , selectPressed(false)
116         , textLayoutDirty(true)
117         , persistentSelection(false)
118         , m_hideCursor(false)
119         , m_separator(0)
120         , m_readOnly(0)
121         , m_textDirty(0)
122         , m_preeditDirty(0)
123         , m_selDirty(0)
124         , m_validInput(1)
125         , m_acceptableInput(1)
126         , m_blinkStatus(0)
127         , m_passwordEchoEditing(false)
128     {
129     }
130
131     ~QQuickTextInputPrivate()
132     {
133     }
134
135     void init();
136     void startCreatingCursor();
137     void updateHorizontalScroll();
138     void updateVerticalScroll();
139     bool determineHorizontalAlignment();
140     bool setHAlign(QQuickTextInput::HAlignment, bool forceAlign = false);
141     void mirrorChange();
142     bool sendMouseEventToInputContext(QMouseEvent *event);
143     Qt::InputMethodHints effectiveInputMethodHints() const;
144     void hideCursor();
145     void showCursor();
146
147
148     struct MaskInputData {
149         enum Casemode { NoCaseMode, Upper, Lower };
150         QChar maskChar; // either the separator char or the inputmask
151         bool separator;
152         Casemode caseMode;
153     };
154
155     // undo/redo handling
156     enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection, SetSelection };
157     struct Command {
158         inline Command() {}
159         inline Command(CommandType t, int p, QChar c, int ss, int se) : type(t),uc(c),pos(p),selStart(ss),selEnd(se) {}
160         uint type : 4;
161         QChar uc;
162         int pos, selStart, selEnd;
163     };
164
165     enum DrawFlags {
166         DrawText = 0x01,
167         DrawSelections = 0x02,
168         DrawCursor = 0x04,
169         DrawAll = DrawText | DrawSelections | DrawCursor
170     };
171
172     QElapsedTimer tripleClickTimer;
173     QRectF boundingRect;
174     QPointF pressPos;
175     QPointF tripleClickStartPoint;
176
177     QDeclarativeGuard<QDeclarativeComponent> cursorComponent;
178 #ifndef QT_NO_VALIDATOR
179     QDeclarativeGuard<QValidator> m_validator;
180 #endif
181
182     qreal hscroll;
183     qreal vscroll;
184
185     QTextLayout m_textLayout;
186     QString m_text;
187     QString m_inputMask;
188     QString m_cancelText;
189     QString m_tentativeCommit;
190     QFont font;
191     QFont sourceFont;
192
193     QQuickItem *cursorItem;
194     QQuickTextNode *textNode;
195     MaskInputData *m_maskData;
196
197     QList<int> m_transactions;
198     QVector<Command> m_history;
199
200     QColor color;
201     QColor selectionColor;
202     QColor selectedTextColor;
203
204 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
205     QBasicTimer m_passwordEchoTimer;
206 #endif
207     int lastSelectionStart;
208     int lastSelectionEnd;
209     int m_cursor;
210     int m_preeditCursor;
211     int m_blinkPeriod; // 0 for non-blinking cursor
212     int m_blinkTimer;
213     int m_maxLength;
214     int m_lastCursorPos;
215     int m_undoState;
216     int m_selstart;
217     int m_selend;
218
219     enum UpdateType {
220         UpdateNone,
221         UpdateOnlyPreprocess,
222         UpdatePaintNode
223     };
224
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;
233
234     QChar m_blank;
235     QChar m_passwordCharacter;
236
237     bool focusOnPress:1;
238     bool cursorVisible:1;
239     bool autoScroll:1;
240     bool selectByMouse:1;
241     bool canPaste:1;
242     bool canPasteValid:1;
243     bool canUndo:1;
244     bool canRedo: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;
251     bool m_readOnly : 1;
252     bool m_textDirty : 1;
253     bool m_preeditDirty : 1;
254     bool m_selDirty : 1;
255     bool m_validInput : 1;
256     bool m_acceptableInput : 1;
257     bool m_blinkStatus : 1;
258     bool m_passwordEchoEditing : 1;
259
260
261     static inline QQuickTextInputPrivate *get(QQuickTextInput *t) {
262         return t->d_func();
263     }
264     bool hasPendingTripleClick() const {
265         return !tripleClickTimer.hasExpired(qApp->styleHints()->mouseDoubleClickInterval());
266     }
267
268
269     int nextMaskBlank(int pos)
270     {
271         int c = findInMask(pos, true, false);
272         m_separator |= (c != pos);
273         return (c != -1 ?  c : m_maxLength);
274     }
275
276     int prevMaskBlank(int pos)
277     {
278         int c = findInMask(pos, false, false);
279         m_separator |= (c != pos);
280         return (c != -1 ? c : 0);
281     }
282
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; }
286
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; }
289
290     void setSelection(int start, int length);
291
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(); }
295
296     int selectionStart() const { return hasSelectedText() ? m_selstart : -1; }
297     int selectionEnd() const { return hasSelectedText() ? m_selend : -1; }
298
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);
302     }
303
304     void removeSelection()
305     {
306         int priorState = m_undoState;
307         removeSelectedText();
308         finishChange(priorState);
309     }
310
311     int start() const { return 0; }
312     int end() const { return m_text.length(); }
313
314     QString realText() const;
315
316 #ifndef QT_NO_CLIPBOARD
317     void copy(QClipboard::Mode mode = QClipboard::Clipboard) const;
318     void paste(QClipboard::Mode mode = QClipboard::Clipboard);
319 #endif
320
321     void commitPreedit();
322
323     Qt::CursorMoveStyle cursorMoveStyle() const { return m_textLayout.cursorMoveStyle(); }
324     void setCursorMoveStyle(Qt::CursorMoveStyle style) { m_textLayout.setCursorMoveStyle(style); }
325
326     void moveCursor(int pos, bool mark = false);
327     void cursorForward(bool mark, int steps)
328     {
329         int c = m_cursor;
330         if (steps > 0) {
331             while (steps--)
332                 c = cursorMoveStyle() == Qt::VisualMoveStyle ? m_textLayout.rightCursorPosition(c)
333                                                              : m_textLayout.nextCursorPosition(c);
334         } else if (steps < 0) {
335             while (steps++)
336                 c = cursorMoveStyle() == Qt::VisualMoveStyle ? m_textLayout.leftCursorPosition(c)
337                                                              : m_textLayout.previousCursorPosition(c);
338         }
339         moveCursor(c, mark);
340     }
341
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); }
344
345     void home(bool mark) { moveCursor(0, mark); }
346     void end(bool mark) { moveCursor(q_func()->text().length(), mark); }
347
348     void backspace();
349     void del();
350     void deselect() { internalDeselect(); finishChange(); }
351     void selectAll() { m_selstart = m_selend = m_cursor = 0; moveCursor(m_text.length(), true); }
352
353     void insert(const QString &);
354     void clear();
355     void selectWordAtPos(int);
356
357     void setCursorPosition(int pos) { if (pos <= m_text.length()) moveCursor(qMax(0, pos)); }
358
359     bool fixup();
360
361     QString inputMask() const { return m_maskData ? m_inputMask + QLatin1Char(';') + m_blank : QString(); }
362     void setInputMask(const QString &mask)
363     {
364         parseInputMask(mask);
365         if (m_maskData)
366             moveCursor(nextMaskBlank(0));
367     }
368
369     // input methods
370 #ifndef QT_NO_IM
371     bool composeMode() const { return !m_textLayout.preeditAreaText().isEmpty(); }
372 #endif
373
374     QString preeditAreaText() const { return m_textLayout.preeditAreaText(); }
375
376     void updatePasswordEchoEditing(bool editing);
377
378     void cancelPasswordEchoTimer() {
379 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
380         m_passwordEchoTimer.stop();
381 #endif
382     }
383
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;
389         }
390         return m_layoutDirection;
391     }
392     void setLayoutDirection(Qt::LayoutDirection direction)
393     {
394         if (direction != m_layoutDirection) {
395             m_layoutDirection = direction;
396             updateDisplayText();
397         }
398     }
399
400     void processInputMethodEvent(QInputMethodEvent *event);
401     void processKeyEvent(QKeyEvent* ev);
402
403     void setCursorBlinkPeriod(int msec);
404
405     void updateLayout();
406
407 private:
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);
412
413     void internalInsert(const QString &s);
414     void internalDelete(bool wasBackspace = false);
415     void internalRemove(int pos);
416
417     inline void internalDeselect()
418     {
419         m_selDirty |= (m_selend > m_selstart);
420         m_selstart = m_selend = 0;
421     }
422
423     void internalUndo(int until = -1);
424     void internalRedo();
425     void emitUndoRedoChanged();
426
427     bool emitCursorPositionChanged();
428
429     bool finishChange(int validateFromState = -1, bool update = false, bool edited = true);
430
431     void addCommand(const Command& cmd);
432
433     inline void separate() { m_separator = true; }
434
435     enum ValidatorState {
436 #ifndef QT_NO_VALIDATOR
437         InvalidInput        = QValidator::Invalid,
438         IntermediateInput   = QValidator::Intermediate,
439         AcceptableInput     = QValidator::Acceptable
440 #else
441         Invalid,
442         Intermediate,
443         Acceptable
444 #endif
445     };
446
447     // masking
448     void parseInputMask(const QString &maskFields);
449     bool isValidInput(QChar key, QChar mask) const;
450     ValidatorState hasAcceptableInput(const QString &text) const;
451     void checkIsValid();
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;
456 };
457
458 QT_END_NAMESPACE
459
460 #endif // QQUICKTEXTINPUT_P_P_H