1fc55658e6550055b59b152ed75d74b18ab0f631
[profile/ivi/qtdeclarative.git] / src / quick / items / qquicktextinput_p_p.h
1 // Commit: 47712d1f330e4b22ce6dd30e7557288ef7f7fca0
2 /****************************************************************************
3 **
4 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
5 ** All rights reserved.
6 ** Contact: http://www.qt-project.org/
7 **
8 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** GNU Lesser General Public License Usage
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this
15 ** file. Please review the following information to ensure the GNU Lesser
16 ** General Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** GNU General Public License Usage
24 ** Alternatively, this file may be used under the terms of the GNU General
25 ** Public License version 3.0 as published by the Free Software Foundation
26 ** and appearing in the file LICENSE.GPL included in the packaging of this
27 ** file. Please review the following information to ensure the GNU General
28 ** Public License version 3.0 requirements will be met:
29 ** http://www.gnu.org/copyleft/gpl.html.
30 **
31 ** Other Usage
32 ** Alternatively, this file may be used in accordance with the terms and
33 ** conditions contained in a signed written agreement between you and Nokia.
34 **
35 **
36 **
37 **
38 **
39 ** $QT_END_LICENSE$
40 **
41 ****************************************************************************/
42
43 #ifndef QQUICKTEXTINPUT_P_P_H
44 #define QQUICKTEXTINPUT_P_P_H
45
46 #include "qquicktextinput_p.h"
47 #include "qquicktext_p.h"
48 #include "qquickimplicitsizeitem_p_p.h"
49
50 #include <QtDeclarative/qdeclarative.h>
51 #include <QtCore/qelapsedtimer.h>
52 #include <QtCore/qpointer.h>
53 #include <QtCore/qbasictimer.h>
54 #include <QtGui/qclipboard.h>
55 #include <QtGui/qguiapplication.h>
56 #include <QtGui/qpalette.h>
57 #include <QtGui/qtextlayout.h>
58 #include <QtGui/qstylehints.h>
59
60 #include "qplatformdefs.h"
61
62 //
63 //  W A R N I N G
64 //  -------------
65 //
66 // This file is not part of the Qt API.  It exists purely as an
67 // implementation detail.  This header file may change from version to
68 // version without notice, or even be removed.
69 //
70 // We mean it.
71
72 QT_BEGIN_NAMESPACE
73
74 class QQuickTextNode;
75
76 class Q_AUTOTEST_EXPORT QQuickTextInputPrivate : public QQuickImplicitSizeItemPrivate
77 {
78     Q_DECLARE_PUBLIC(QQuickTextInput)
79 public:
80     QQuickTextInputPrivate()
81         : color((QRgb)0)
82         , styleColor((QRgb)0)
83         , textNode(0)
84         , m_maskData(0)
85         , hscroll(0)
86         , vscroll(0)
87         , m_cursor(0)
88         , m_preeditCursor(0)
89         , m_cursorWidth(1)
90         , m_blinkPeriod(0)
91         , m_blinkTimer(0)
92         , m_deleteAllTimer(0)
93         , m_ascent(0)
94         , m_maxLength(32767)
95         , m_lastCursorPos(-1)
96         , m_modifiedState(0)
97         , m_undoState(0)
98         , m_selstart(0)
99         , m_selend(0)
100         , style(QQuickText::Normal)
101         , hAlign(QQuickTextInput::AlignLeft)
102         , vAlign(QQuickTextInput::AlignTop)
103         , wrapMode(QQuickTextInput::NoWrap)
104         , mouseSelectionMode(QQuickTextInput::SelectCharacters)
105         , inputMethodHints(Qt::ImhNone)
106         , m_layoutDirection(Qt::LayoutDirectionAuto)
107         , m_passwordCharacter(QLatin1Char('*'))
108         , focused(false)
109         , focusOnPress(true)
110         , cursorVisible(false)
111         , autoScroll(true)
112         , selectByMouse(false)
113         , canPaste(false)
114         , canPasteValid(false)
115         , canUndo(false)
116         , canRedo(false)
117         , hAlignImplicit(true)
118         , selectPressed(false)
119         , textLayoutDirty(true)
120         , m_hideCursor(false)
121         , m_separator(0)
122         , m_readOnly(0)
123         , m_echoMode(QQuickTextInput::Normal)
124         , m_textDirty(0)
125         , m_preeditDirty(0)
126         , m_selDirty(0)
127         , m_validInput(1)
128         , m_acceptableInput(1)
129         , m_blinkStatus(0)
130         , m_passwordEchoEditing(false)
131         , updateType(UpdatePaintNode)
132     {
133     }
134
135     ~QQuickTextInputPrivate()
136     {
137     }
138
139     void init();
140     void startCreatingCursor();
141     void updateHorizontalScroll();
142     void updateVerticalScroll();
143     bool determineHorizontalAlignment();
144     bool setHAlign(QQuickTextInput::HAlignment, bool forceAlign = false);
145     void mirrorChange();
146     bool sendMouseEventToInputContext(QMouseEvent *event);
147     void updateInputMethodHints();
148     void hideCursor();
149     void showCursor();
150
151     struct MaskInputData {
152         enum Casemode { NoCaseMode, Upper, Lower };
153         QChar maskChar; // either the separator char or the inputmask
154         bool separator;
155         Casemode caseMode;
156     };
157
158     // undo/redo handling
159     enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection, SetSelection };
160     struct Command {
161         inline Command() {}
162         inline Command(CommandType t, int p, QChar c, int ss, int se) : type(t),uc(c),pos(p),selStart(ss),selEnd(se) {}
163         uint type : 4;
164         QChar uc;
165         int pos, selStart, selEnd;
166     };
167
168     enum DrawFlags {
169         DrawText = 0x01,
170         DrawSelections = 0x02,
171         DrawCursor = 0x04,
172         DrawAll = DrawText | DrawSelections | DrawCursor
173     };
174
175     QTextLayout m_textLayout;
176     QString m_text;
177     QString m_inputMask;
178     QString m_cancelText;
179     QString m_tentativeCommit;
180     QPalette m_palette;
181     QFont font;
182     QFont sourceFont;
183     QColor  color;
184     QColor  selectionColor;
185     QColor  selectedTextColor;
186     QColor  styleColor;
187     QPointer<QDeclarativeComponent> cursorComponent;
188     QPointer<QQuickItem> cursorItem;
189 #ifndef QT_NO_VALIDATOR
190     QPointer<QValidator> m_validator;
191 #endif
192     QPointF pressPos;
193     QQuickTextNode *textNode;
194     MaskInputData *m_maskData;
195     QElapsedTimer tripleClickTimer;
196     QPoint tripleClickStartPoint;
197     QList<int> m_transactions;
198     QVector<Command> m_history;
199     QRectF boundingRect;
200
201     int lastSelectionStart;
202     int lastSelectionEnd;
203     int oldHeight;
204     int oldWidth;
205     int hscroll;
206     int vscroll;
207     int m_cursor;
208     int m_preeditCursor;
209     int m_cursorWidth;
210     int m_blinkPeriod; // 0 for non-blinking cursor
211     int m_blinkTimer;
212     int m_deleteAllTimer;
213 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
214     QBasicTimer m_passwordEchoTimer;
215 #endif
216     int m_ascent;
217     int m_maxLength;
218     int m_lastCursorPos;
219     int m_modifiedState;
220     int m_undoState;
221     int m_selstart;
222     int m_selend;
223
224     QQuickText::TextStyle style;
225     QQuickTextInput::HAlignment hAlign;
226     QQuickTextInput::VAlignment vAlign;
227     QQuickTextInput::WrapMode wrapMode;
228     QQuickTextInput::SelectionMode mouseSelectionMode;
229     Qt::InputMethodHints inputMethodHints;
230     Qt::LayoutDirection m_layoutDirection;
231
232     QChar m_blank;
233     QChar m_passwordCharacter;
234
235     bool focused:1;
236     bool focusOnPress:1;
237     bool cursorVisible:1;
238     bool autoScroll:1;
239     bool selectByMouse:1;
240     bool canPaste:1;
241     bool canPasteValid:1;
242     bool canUndo:1;
243     bool canRedo:1;
244     bool hAlignImplicit:1;
245     bool selectPressed:1;
246     bool textLayoutDirty:1;
247
248     uint m_hideCursor : 1; // used to hide the m_cursor inside preedit areas
249     uint m_separator : 1;
250     uint m_readOnly : 1;
251     uint m_echoMode : 2;
252     uint m_textDirty : 1;
253     uint m_preeditDirty : 1;
254     uint m_selDirty : 1;
255     uint m_validInput : 1;
256     uint m_acceptableInput : 1;
257     uint m_blinkStatus : 1;
258     uint m_passwordEchoEditing;
259
260     enum UpdateType {
261         UpdateNone,
262         UpdateOnlyPreprocess,
263         UpdatePaintNode
264     };
265     UpdateType updateType;
266
267     static inline QQuickTextInputPrivate *get(QQuickTextInput *t) {
268         return t->d_func();
269     }
270     bool hasPendingTripleClick() const {
271         return !tripleClickTimer.hasExpired(qApp->styleHints()->mouseDoubleClickInterval());
272     }
273
274
275     int nextMaskBlank(int pos)
276     {
277         int c = findInMask(pos, true, false);
278         m_separator |= (c != pos);
279         return (c != -1 ?  c : m_maxLength);
280     }
281
282     int prevMaskBlank(int pos)
283     {
284         int c = findInMask(pos, false, false);
285         m_separator |= (c != pos);
286         return (c != -1 ? c : 0);
287     }
288
289     bool isUndoAvailable() const { return !m_readOnly && m_undoState; }
290     bool isRedoAvailable() const { return !m_readOnly && m_undoState < (int)m_history.size(); }
291     void clearUndo() { m_history.clear(); m_modifiedState = m_undoState = 0; }
292
293     bool isModified() const { return m_modifiedState != m_undoState; }
294     void setModified(bool modified) { m_modifiedState = modified ? -1 : m_undoState; }
295
296     bool allSelected() const { return !m_text.isEmpty() && m_selstart == 0 && m_selend == (int)m_text.length(); }
297     bool hasSelectedText() const { return !m_text.isEmpty() && m_selend > m_selstart; }
298
299     void setSelection(int start, int length);
300
301     inline QString selectedText() const { return hasSelectedText() ? m_text.mid(m_selstart, m_selend - m_selstart) : QString(); }
302     QString textBeforeSelection() const { return hasSelectedText() ? m_text.left(m_selstart) : QString(); }
303     QString textAfterSelection() const { return hasSelectedText() ? m_text.mid(m_selend) : QString(); }
304
305     int selectionStart() const { return hasSelectedText() ? m_selstart : -1; }
306     int selectionEnd() const { return hasSelectedText() ? m_selend : -1; }
307
308     int positionAt(int x, int y, QTextLine::CursorPosition position) const;
309     int positionAt(const QPointF &point, QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters) const {
310         return positionAt(point.x(), point.y(), position);
311     }
312
313     void removeSelection()
314     {
315         int priorState = m_undoState;
316         removeSelectedText();
317         finishChange(priorState);
318     }
319
320     int start() const { return 0; }
321     int end() const { return m_text.length(); }
322
323     QString realText() const;
324
325 #ifndef QT_NO_CLIPBOARD
326     void copy(QClipboard::Mode mode = QClipboard::Clipboard) const;
327     void paste(QClipboard::Mode mode = QClipboard::Clipboard);
328 #endif
329
330     void commitPreedit();
331
332     Qt::CursorMoveStyle cursorMoveStyle() const { return m_textLayout.cursorMoveStyle(); }
333     void setCursorMoveStyle(Qt::CursorMoveStyle style) { m_textLayout.setCursorMoveStyle(style); }
334
335     void moveCursor(int pos, bool mark = false);
336     void cursorForward(bool mark, int steps)
337     {
338         int c = m_cursor;
339         if (steps > 0) {
340             while (steps--)
341                 c = cursorMoveStyle() == Qt::VisualMoveStyle ? m_textLayout.rightCursorPosition(c)
342                                                              : m_textLayout.nextCursorPosition(c);
343         } else if (steps < 0) {
344             while (steps++)
345                 c = cursorMoveStyle() == Qt::VisualMoveStyle ? m_textLayout.leftCursorPosition(c)
346                                                              : m_textLayout.previousCursorPosition(c);
347         }
348         moveCursor(c, mark);
349     }
350
351     void cursorWordForward(bool mark) { moveCursor(m_textLayout.nextCursorPosition(m_cursor, QTextLayout::SkipWords), mark); }
352     void cursorWordBackward(bool mark) { moveCursor(m_textLayout.previousCursorPosition(m_cursor, QTextLayout::SkipWords), mark); }
353
354     void home(bool mark) { moveCursor(0, mark); }
355     void end(bool mark) { moveCursor(q_func()->text().length(), mark); }
356
357     void backspace();
358     void del();
359     void deselect() { internalDeselect(); finishChange(); }
360     void selectAll() { m_selstart = m_selend = m_cursor = 0; moveCursor(m_text.length(), true); }
361
362     void insert(const QString &);
363     void clear();
364     void selectWordAtPos(int);
365
366     void setCursorPosition(int pos) { if (pos <= m_text.length()) moveCursor(qMax(0, pos)); }
367
368     bool fixup();
369
370     QString inputMask() const { return m_maskData ? m_inputMask + QLatin1Char(';') + m_blank : QString(); }
371     void setInputMask(const QString &mask)
372     {
373         parseInputMask(mask);
374         if (m_maskData)
375             moveCursor(nextMaskBlank(0));
376     }
377
378     // input methods
379 #ifndef QT_NO_IM
380     bool composeMode() const { return !m_textLayout.preeditAreaText().isEmpty(); }
381 #endif
382
383     QString preeditAreaText() const { return m_textLayout.preeditAreaText(); }
384
385     void updatePasswordEchoEditing(bool editing);
386
387     void cancelPasswordEchoTimer() {
388 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
389         m_passwordEchoTimer.stop();
390 #endif
391     }
392
393     Qt::LayoutDirection layoutDirection() const {
394         if (m_layoutDirection == Qt::LayoutDirectionAuto) {
395             if (m_text.isEmpty())
396                 return qApp->inputPanel()->inputDirection();
397             return m_text.isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight;
398         }
399         return m_layoutDirection;
400     }
401     void setLayoutDirection(Qt::LayoutDirection direction)
402     {
403         if (direction != m_layoutDirection) {
404             m_layoutDirection = direction;
405             updateDisplayText();
406         }
407     }
408
409     void processInputMethodEvent(QInputMethodEvent *event);
410     void processKeyEvent(QKeyEvent* ev);
411
412     void setCursorBlinkPeriod(int msec);
413     void resetCursorBlinkTimer();
414
415     void updateLayout();
416
417 private:
418     void init(const QString &txt);
419     void removeSelectedText();
420     void internalSetText(const QString &txt, int pos = -1, bool edited = true);
421     void updateDisplayText(bool forceUpdate = false);
422
423     void internalInsert(const QString &s);
424     void internalDelete(bool wasBackspace = false);
425     void internalRemove(int pos);
426
427     inline void internalDeselect()
428     {
429         m_selDirty |= (m_selend > m_selstart);
430         m_selstart = m_selend = 0;
431     }
432
433     void internalUndo(int until = -1);
434     void internalRedo();
435     void emitUndoRedoChanged();
436
437     bool emitCursorPositionChanged();
438
439     bool finishChange(int validateFromState = -1, bool update = false, bool edited = true);
440
441     void addCommand(const Command& cmd);
442
443     inline void separate() { m_separator = true; }
444
445     enum ValidatorState {
446 #ifndef QT_NO_VALIDATOR
447         InvalidInput        = QValidator::Invalid,
448         IntermediateInput   = QValidator::Intermediate,
449         AcceptableInput     = QValidator::Acceptable
450 #else
451         Invalid,
452         Intermediate,
453         Acceptable
454 #endif
455     };
456
457     // masking
458     void parseInputMask(const QString &maskFields);
459     bool isValidInput(QChar key, QChar mask) const;
460     ValidatorState hasAcceptableInput(const QString &text) const;
461     void checkIsValid();
462     QString maskString(uint pos, const QString &str, bool clear = false) const;
463     QString clearString(uint pos, uint len) const;
464     QString stripString(const QString &str) const;
465     int findInMask(int pos, bool forward, bool findSeparator, QChar searchChar = QChar()) const;
466 };
467
468 QT_END_NAMESPACE
469
470 #endif // QQUICKTEXTINPUT_P_P_H