~loic.molinari/+junk/qtdeclarative-shadereffectsource-changes

« back to all changes in this revision

Viewing changes to src/quick/items/qquicktextinput.cpp

  • Committer: Loïc Molinari
  • Date: 2012-04-21 17:59:51 UTC
  • Revision ID: loic.molinari@canonical.com-20120421175951-bqx68caaf5zrp76l
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 QtQml 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
#include "qquicktextinput_p.h"
 
43
#include "qquicktextinput_p_p.h"
 
44
#include "qquickcanvas.h"
 
45
 
 
46
#include <private/qqmlglobal_p.h>
 
47
 
 
48
#include <QtCore/qcoreapplication.h>
 
49
#include <QtQml/qqmlinfo.h>
 
50
#include <QtGui/qevent.h>
 
51
#include <QTextBoundaryFinder>
 
52
#include "qquicktextnode_p.h"
 
53
#include <QtQuick/qsgsimplerectnode.h>
 
54
 
 
55
#include <QtGui/qstylehints.h>
 
56
#include <QtGui/qinputmethod.h>
 
57
 
 
58
#ifndef QT_NO_ACCESSIBILITY
 
59
#include "qaccessible.h"
 
60
#endif
 
61
 
 
62
QT_BEGIN_NAMESPACE
 
63
 
 
64
DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
 
65
 
 
66
/*!
 
67
    \qmlclass TextInput QQuickTextInput
 
68
    \inqmlmodule QtQuick 2
 
69
    \ingroup qml-basic-visual-elements
 
70
    \brief The TextInput item displays an editable line of text.
 
71
    \inherits Item
 
72
 
 
73
    The TextInput element displays a single line of editable plain text.
 
74
 
 
75
    TextInput is used to accept a line of text input. Input constraints
 
76
    can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
 
77
    and setting \l echoMode to an appropriate value enables TextInput to be used for
 
78
    a password input field.
 
79
 
 
80
    On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
 
81
    If you want such bindings (on any platform), you will need to construct them in QML.
 
82
 
 
83
    \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
 
84
*/
 
85
QQuickTextInput::QQuickTextInput(QQuickItem* parent)
 
86
: QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
 
87
{
 
88
    Q_D(QQuickTextInput);
 
89
    d->init();
 
90
}
 
91
 
 
92
QQuickTextInput::~QQuickTextInput()
 
93
{
 
94
}
 
95
 
 
96
void QQuickTextInput::componentComplete()
 
97
{
 
98
    Q_D(QQuickTextInput);
 
99
 
 
100
    QQuickImplicitSizeItem::componentComplete();
 
101
 
 
102
    d->checkIsValid();
 
103
    d->updateLayout();
 
104
    updateCursorRectangle();
 
105
    if (d->cursorComponent && d->cursorComponent->isReady())
 
106
        createCursor();
 
107
}
 
108
 
 
109
/*!
 
110
    \qmlproperty string QtQuick2::TextInput::text
 
111
 
 
112
    The text in the TextInput.
 
113
*/
 
114
QString QQuickTextInput::text() const
 
115
{
 
116
    Q_D(const QQuickTextInput);
 
117
 
 
118
    QString content = d->m_text;
 
119
    QString res = d->m_maskData ? d->stripString(content) : content;
 
120
    return (res.isNull() ? QString::fromLatin1("") : res);
 
121
}
 
122
 
 
123
void QQuickTextInput::setText(const QString &s)
 
124
{
 
125
    Q_D(QQuickTextInput);
 
126
    if (s == text())
 
127
        return;
 
128
 
 
129
    d->cancelPreedit();
 
130
    d->internalSetText(s, -1, false);
 
131
}
 
132
 
 
133
/*!
 
134
    \qmlproperty int QtQuick2::TextInput::length
 
135
 
 
136
    Returns the total number of characters in the TextInput item.
 
137
 
 
138
    If the TextInput has an inputMask the length will include mask characters and may differ
 
139
    from the length of the string returned by the \l text property.
 
140
 
 
141
    This property can be faster than querying the length the \l text property as it doesn't
 
142
    require any copying or conversion of the TextInput's internal string data.
 
143
*/
 
144
 
 
145
int QQuickTextInput::length() const
 
146
{
 
147
    Q_D(const QQuickTextInput);
 
148
    return d->m_text.length();
 
149
}
 
150
 
 
151
/*!
 
152
    \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
 
153
 
 
154
    Returns the section of text that is between the \a start and \a end positions.
 
155
 
 
156
    If the TextInput has an inputMask the length will include mask characters.
 
157
*/
 
158
 
 
159
QString QQuickTextInput::getText(int start, int end) const
 
160
{
 
161
    Q_D(const QQuickTextInput);
 
162
 
 
163
    if (start > end)
 
164
        qSwap(start, end);
 
165
 
 
166
    return d->m_text.mid(start, end - start);
 
167
}
 
168
 
 
169
QString QQuickTextInputPrivate::realText() const
 
170
{
 
171
    QString res = m_maskData ? stripString(m_text) : m_text;
 
172
    return (res.isNull() ? QString::fromLatin1("") : res);
 
173
}
 
174
 
 
175
/*!
 
176
    \qmlproperty string QtQuick2::TextInput::font.family
 
177
 
 
178
    Sets the family name of the font.
 
179
 
 
180
    The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
 
181
    If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
 
182
    If the family isn't available a family will be set using the font matching algorithm.
 
183
*/
 
184
 
 
185
/*!
 
186
    \qmlproperty bool QtQuick2::TextInput::font.bold
 
187
 
 
188
    Sets whether the font weight is bold.
 
189
*/
 
190
 
 
191
/*!
 
192
    \qmlproperty enumeration QtQuick2::TextInput::font.weight
 
193
 
 
194
    Sets the font's weight.
 
195
 
 
196
    The weight can be one of:
 
197
    \list
 
198
    \li Font.Light
 
199
    \li Font.Normal - the default
 
200
    \li Font.DemiBold
 
201
    \li Font.Bold
 
202
    \li Font.Black
 
203
    \endlist
 
204
 
 
205
    \qml
 
206
    TextInput { text: "Hello"; font.weight: Font.DemiBold }
 
207
    \endqml
 
208
*/
 
209
 
 
210
/*!
 
211
    \qmlproperty bool QtQuick2::TextInput::font.italic
 
212
 
 
213
    Sets whether the font has an italic style.
 
214
*/
 
215
 
 
216
/*!
 
217
    \qmlproperty bool QtQuick2::TextInput::font.underline
 
218
 
 
219
    Sets whether the text is underlined.
 
220
*/
 
221
 
 
222
/*!
 
223
    \qmlproperty bool QtQuick2::TextInput::font.strikeout
 
224
 
 
225
    Sets whether the font has a strikeout style.
 
226
*/
 
227
 
 
228
/*!
 
229
    \qmlproperty real QtQuick2::TextInput::font.pointSize
 
230
 
 
231
    Sets the font size in points. The point size must be greater than zero.
 
232
*/
 
233
 
 
234
/*!
 
235
    \qmlproperty int QtQuick2::TextInput::font.pixelSize
 
236
 
 
237
    Sets the font size in pixels.
 
238
 
 
239
    Using this function makes the font device dependent.
 
240
    Use \c pointSize to set the size of the font in a device independent manner.
 
241
*/
 
242
 
 
243
/*!
 
244
    \qmlproperty real QtQuick2::TextInput::font.letterSpacing
 
245
 
 
246
    Sets the letter spacing for the font.
 
247
 
 
248
    Letter spacing changes the default spacing between individual letters in the font.
 
249
    A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
 
250
*/
 
251
 
 
252
/*!
 
253
    \qmlproperty real QtQuick2::TextInput::font.wordSpacing
 
254
 
 
255
    Sets the word spacing for the font.
 
256
 
 
257
    Word spacing changes the default spacing between individual words.
 
258
    A positive value increases the word spacing by a corresponding amount of pixels,
 
259
    while a negative value decreases the inter-word spacing accordingly.
 
260
*/
 
261
 
 
262
/*!
 
263
    \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
 
264
 
 
265
    Sets the capitalization for the text.
 
266
 
 
267
    \list
 
268
    \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
 
269
    \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
 
270
    \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
 
271
    \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
 
272
    \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
 
273
    \endlist
 
274
 
 
275
    \qml
 
276
    TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
 
277
    \endqml
 
278
*/
 
279
 
 
280
QFont QQuickTextInput::font() const
 
281
{
 
282
    Q_D(const QQuickTextInput);
 
283
    return d->sourceFont;
 
284
}
 
285
 
 
286
void QQuickTextInput::setFont(const QFont &font)
 
287
{
 
288
    Q_D(QQuickTextInput);
 
289
    if (d->sourceFont == font)
 
290
        return;
 
291
 
 
292
    d->sourceFont = font;
 
293
    QFont oldFont = d->font;
 
294
    d->font = font;
 
295
    if (d->font.pointSizeF() != -1) {
 
296
        // 0.5pt resolution
 
297
        qreal size = qRound(d->font.pointSizeF()*2.0);
 
298
        d->font.setPointSizeF(size/2.0);
 
299
    }
 
300
    if (oldFont != d->font) {
 
301
        d->updateLayout();
 
302
        updateCursorRectangle();
 
303
        updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
 
304
    }
 
305
    emit fontChanged(d->sourceFont);
 
306
}
 
307
 
 
308
/*!
 
309
    \qmlproperty color QtQuick2::TextInput::color
 
310
 
 
311
    The text color.
 
312
*/
 
313
QColor QQuickTextInput::color() const
 
314
{
 
315
    Q_D(const QQuickTextInput);
 
316
    return d->color;
 
317
}
 
318
 
 
319
void QQuickTextInput::setColor(const QColor &c)
 
320
{
 
321
    Q_D(QQuickTextInput);
 
322
    if (c != d->color) {
 
323
        d->color = c;
 
324
        d->textLayoutDirty = true;
 
325
        d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
 
326
        update();
 
327
        emit colorChanged();
 
328
    }
 
329
}
 
330
 
 
331
 
 
332
/*!
 
333
    \qmlproperty color QtQuick2::TextInput::selectionColor
 
334
 
 
335
    The text highlight color, used behind selections.
 
336
*/
 
337
QColor QQuickTextInput::selectionColor() const
 
338
{
 
339
    Q_D(const QQuickTextInput);
 
340
    return d->selectionColor;
 
341
}
 
342
 
 
343
void QQuickTextInput::setSelectionColor(const QColor &color)
 
344
{
 
345
    Q_D(QQuickTextInput);
 
346
    if (d->selectionColor == color)
 
347
        return;
 
348
 
 
349
    d->selectionColor = color;
 
350
    if (d->hasSelectedText()) {
 
351
        d->textLayoutDirty = true;
 
352
        d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
 
353
        update();
 
354
    }
 
355
    emit selectionColorChanged();
 
356
}
 
357
/*!
 
358
    \qmlproperty color QtQuick2::TextInput::selectedTextColor
 
359
 
 
360
    The highlighted text color, used in selections.
 
361
*/
 
362
QColor QQuickTextInput::selectedTextColor() const
 
363
{
 
364
    Q_D(const QQuickTextInput);
 
365
    return d->selectedTextColor;
 
366
}
 
367
 
 
368
void QQuickTextInput::setSelectedTextColor(const QColor &color)
 
369
{
 
370
    Q_D(QQuickTextInput);
 
371
    if (d->selectedTextColor == color)
 
372
        return;
 
373
 
 
374
    d->selectedTextColor = color;
 
375
    if (d->hasSelectedText()) {
 
376
        d->textLayoutDirty = true;
 
377
        d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
 
378
        update();
 
379
    }
 
380
    emit selectedTextColorChanged();
 
381
}
 
382
 
 
383
/*!
 
384
    \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
 
385
    \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
 
386
    \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
 
387
 
 
388
    Sets the horizontal alignment of the text within the TextInput item's
 
389
    width and height. By default, the text alignment follows the natural alignment
 
390
    of the text, for example text that is read from left to right will be aligned to
 
391
    the left.
 
392
 
 
393
    TextInput does not have vertical alignment, as the natural height is
 
394
    exactly the height of the single line of text. If you set the height
 
395
    manually to something larger, TextInput will always be top aligned
 
396
    vertically. You can use anchors to align it however you want within
 
397
    another item.
 
398
 
 
399
    The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
 
400
    \c TextInput.AlignHCenter.
 
401
 
 
402
    Valid values for \c verticalAlignment are \c TextInput.AlignTop (default),
 
403
    \c TextInput.AlignBottom \c TextInput.AlignVCenter.
 
404
 
 
405
    When using the attached property LayoutMirroring::enabled to mirror application
 
406
    layouts, the horizontal alignment of text will also be mirrored. However, the property
 
407
    \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
 
408
    of TextInput, use the read-only property \c effectiveHorizontalAlignment.
 
409
*/
 
410
QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
 
411
{
 
412
    Q_D(const QQuickTextInput);
 
413
    return d->hAlign;
 
414
}
 
415
 
 
416
void QQuickTextInput::setHAlign(HAlignment align)
 
417
{
 
418
    Q_D(QQuickTextInput);
 
419
    bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
 
420
    d->hAlignImplicit = false;
 
421
    if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
 
422
        d->updateLayout();
 
423
        updateCursorRectangle();
 
424
    }
 
425
}
 
426
 
 
427
void QQuickTextInput::resetHAlign()
 
428
{
 
429
    Q_D(QQuickTextInput);
 
430
    d->hAlignImplicit = true;
 
431
    if (d->determineHorizontalAlignment() && isComponentComplete()) {
 
432
        d->updateLayout();
 
433
        updateCursorRectangle();
 
434
    }
 
435
}
 
436
 
 
437
QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
 
438
{
 
439
    Q_D(const QQuickTextInput);
 
440
    QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
 
441
    if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
 
442
        switch (d->hAlign) {
 
443
        case QQuickTextInput::AlignLeft:
 
444
            effectiveAlignment = QQuickTextInput::AlignRight;
 
445
            break;
 
446
        case QQuickTextInput::AlignRight:
 
447
            effectiveAlignment = QQuickTextInput::AlignLeft;
 
448
            break;
 
449
        default:
 
450
            break;
 
451
        }
 
452
    }
 
453
    return effectiveAlignment;
 
454
}
 
455
 
 
456
bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
 
457
{
 
458
    Q_Q(QQuickTextInput);
 
459
    if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
 
460
        QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
 
461
        hAlign = alignment;
 
462
        emit q->horizontalAlignmentChanged(alignment);
 
463
        if (oldEffectiveHAlign != q->effectiveHAlign())
 
464
            emit q->effectiveHorizontalAlignmentChanged();
 
465
        return true;
 
466
    }
 
467
    return false;
 
468
}
 
469
 
 
470
bool QQuickTextInputPrivate::determineHorizontalAlignment()
 
471
{
 
472
    if (hAlignImplicit) {
 
473
        // if no explicit alignment has been set, follow the natural layout direction of the text
 
474
        QString text = q_func()->text();
 
475
        if (text.isEmpty())
 
476
            text = m_textLayout.preeditAreaText();
 
477
        bool isRightToLeft = text.isEmpty() ? qApp->inputMethod()->inputDirection() == Qt::RightToLeft
 
478
                                            : text.isRightToLeft();
 
479
        return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
 
480
    }
 
481
    return false;
 
482
}
 
483
 
 
484
QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
 
485
{
 
486
    Q_D(const QQuickTextInput);
 
487
    return d->vAlign;
 
488
}
 
489
 
 
490
void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
 
491
{
 
492
    Q_D(QQuickTextInput);
 
493
    if (alignment == d->vAlign)
 
494
        return;
 
495
    d->vAlign = alignment;
 
496
    emit verticalAlignmentChanged(d->vAlign);
 
497
    if (isComponentComplete()) {
 
498
        updateCursorRectangle();
 
499
    }
 
500
}
 
501
 
 
502
/*!
 
503
    \qmlproperty enumeration QtQuick2::TextInput::wrapMode
 
504
 
 
505
    Set this property to wrap the text to the TextInput item's width.
 
506
    The text will only wrap if an explicit width has been set.
 
507
 
 
508
    \list
 
509
    \li TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
 
510
    \li TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
 
511
    \li TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
 
512
    \li TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
 
513
    \endlist
 
514
 
 
515
    The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
 
516
*/
 
517
QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
 
518
{
 
519
    Q_D(const QQuickTextInput);
 
520
    return d->wrapMode;
 
521
}
 
522
 
 
523
void QQuickTextInput::setWrapMode(WrapMode mode)
 
524
{
 
525
    Q_D(QQuickTextInput);
 
526
    if (mode == d->wrapMode)
 
527
        return;
 
528
    d->wrapMode = mode;
 
529
    d->updateLayout();
 
530
    updateCursorRectangle();
 
531
    emit wrapModeChanged();
 
532
}
 
533
 
 
534
void QQuickTextInputPrivate::mirrorChange()
 
535
{
 
536
    Q_Q(QQuickTextInput);
 
537
    if (q->isComponentComplete()) {
 
538
        if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
 
539
            q->updateCursorRectangle();
 
540
            emit q->effectiveHorizontalAlignmentChanged();
 
541
        }
 
542
    }
 
543
}
 
544
 
 
545
/*!
 
546
    \qmlproperty bool QtQuick2::TextInput::readOnly
 
547
 
 
548
    Sets whether user input can modify the contents of the TextInput.
 
549
 
 
550
    If readOnly is set to true, then user input will not affect the text
 
551
    property. Any bindings or attempts to set the text property will still
 
552
    work.
 
553
*/
 
554
bool QQuickTextInput::isReadOnly() const
 
555
{
 
556
    Q_D(const QQuickTextInput);
 
557
    return d->m_readOnly;
 
558
}
 
559
 
 
560
void QQuickTextInput::setReadOnly(bool ro)
 
561
{
 
562
    Q_D(QQuickTextInput);
 
563
    if (d->m_readOnly == ro)
 
564
        return;
 
565
 
 
566
    setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
 
567
    d->m_readOnly = ro;
 
568
    if (!ro)
 
569
        d->setCursorPosition(d->end());
 
570
    updateInputMethod(Qt::ImEnabled);
 
571
    q_canPasteChanged();
 
572
    d->emitUndoRedoChanged();
 
573
    emit readOnlyChanged(ro);
 
574
}
 
575
 
 
576
/*!
 
577
    \qmlproperty int QtQuick2::TextInput::maximumLength
 
578
    The maximum permitted length of the text in the TextInput.
 
579
 
 
580
    If the text is too long, it is truncated at the limit.
 
581
 
 
582
    By default, this property contains a value of 32767.
 
583
*/
 
584
int QQuickTextInput::maxLength() const
 
585
{
 
586
    Q_D(const QQuickTextInput);
 
587
    return d->m_maxLength;
 
588
}
 
589
 
 
590
void QQuickTextInput::setMaxLength(int ml)
 
591
{
 
592
    Q_D(QQuickTextInput);
 
593
    if (d->m_maxLength == ml || d->m_maskData)
 
594
        return;
 
595
 
 
596
    d->m_maxLength = ml;
 
597
    d->internalSetText(d->m_text, -1, false);
 
598
 
 
599
    emit maximumLengthChanged(ml);
 
600
}
 
601
 
 
602
/*!
 
603
    \qmlproperty bool QtQuick2::TextInput::cursorVisible
 
604
    Set to true when the TextInput shows a cursor.
 
605
 
 
606
    This property is set and unset when the TextInput gets active focus, so that other
 
607
    properties can be bound to whether the cursor is currently showing. As it
 
608
    gets set and unset automatically, when you set the value yourself you must
 
609
    keep in mind that your value may be overwritten.
 
610
 
 
611
    It can be set directly in script, for example if a KeyProxy might
 
612
    forward keys to it and you desire it to look active when this happens
 
613
    (but without actually giving it active focus).
 
614
 
 
615
    It should not be set directly on the element, like in the below QML,
 
616
    as the specified value will be overridden an lost on focus changes.
 
617
 
 
618
    \code
 
619
    TextInput {
 
620
        text: "Text"
 
621
        cursorVisible: false
 
622
    }
 
623
    \endcode
 
624
 
 
625
    In the above snippet the cursor will still become visible when the
 
626
    TextInput gains active focus.
 
627
*/
 
628
bool QQuickTextInput::isCursorVisible() const
 
629
{
 
630
    Q_D(const QQuickTextInput);
 
631
    return d->cursorVisible;
 
632
}
 
633
 
 
634
void QQuickTextInput::setCursorVisible(bool on)
 
635
{
 
636
    Q_D(QQuickTextInput);
 
637
    if (d->cursorVisible == on)
 
638
        return;
 
639
    d->cursorVisible = on;
 
640
    d->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
 
641
    d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
 
642
    update();
 
643
    emit cursorVisibleChanged(d->cursorVisible);
 
644
}
 
645
 
 
646
/*!
 
647
    \qmlproperty int QtQuick2::TextInput::cursorPosition
 
648
    The position of the cursor in the TextInput.
 
649
*/
 
650
int QQuickTextInput::cursorPosition() const
 
651
{
 
652
    Q_D(const QQuickTextInput);
 
653
    return d->m_cursor;
 
654
}
 
655
 
 
656
void QQuickTextInput::setCursorPosition(int cp)
 
657
{
 
658
    Q_D(QQuickTextInput);
 
659
    if (cp < 0 || cp > text().length())
 
660
        return;
 
661
    d->moveCursor(cp);
 
662
}
 
663
 
 
664
/*!
 
665
    \qmlproperty rectangle QtQuick2::TextInput::cursorRectangle
 
666
 
 
667
    The rectangle where the standard text cursor is rendered within the text input.  Read only.
 
668
 
 
669
    The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
 
670
    automatically when it changes.  The width of the delegate is unaffected by changes in the
 
671
    cursor rectangle.
 
672
*/
 
673
 
 
674
QRectF QQuickTextInput::cursorRectangle() const
 
675
{
 
676
    Q_D(const QQuickTextInput);
 
677
 
 
678
    int c = d->m_cursor + d->m_preeditCursor;
 
679
    if (d->m_echoMode == NoEcho)
 
680
        c = 0;
 
681
    QTextLine l = d->m_textLayout.lineForTextPosition(c);
 
682
    if (!l.isValid())
 
683
        return QRectF();
 
684
    return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
 
685
}
 
686
 
 
687
/*!
 
688
    \qmlproperty int QtQuick2::TextInput::selectionStart
 
689
 
 
690
    The cursor position before the first character in the current selection.
 
691
 
 
692
    This property is read-only. To change the selection, use select(start,end),
 
693
    selectAll(), or selectWord().
 
694
 
 
695
    \sa selectionEnd, cursorPosition, selectedText
 
696
*/
 
697
int QQuickTextInput::selectionStart() const
 
698
{
 
699
    Q_D(const QQuickTextInput);
 
700
    return d->lastSelectionStart;
 
701
}
 
702
/*!
 
703
    \qmlproperty int QtQuick2::TextInput::selectionEnd
 
704
 
 
705
    The cursor position after the last character in the current selection.
 
706
 
 
707
    This property is read-only. To change the selection, use select(start,end),
 
708
    selectAll(), or selectWord().
 
709
 
 
710
    \sa selectionStart, cursorPosition, selectedText
 
711
*/
 
712
int QQuickTextInput::selectionEnd() const
 
713
{
 
714
    Q_D(const QQuickTextInput);
 
715
    return d->lastSelectionEnd;
 
716
}
 
717
/*!
 
718
    \qmlmethod void QtQuick2::TextInput::select(int start, int end)
 
719
 
 
720
    Causes the text from \a start to \a end to be selected.
 
721
 
 
722
    If either start or end is out of range, the selection is not changed.
 
723
 
 
724
    After calling this, selectionStart will become the lesser
 
725
    and selectionEnd will become the greater (regardless of the order passed
 
726
    to this method).
 
727
 
 
728
    \sa selectionStart, selectionEnd
 
729
*/
 
730
void QQuickTextInput::select(int start, int end)
 
731
{
 
732
    Q_D(QQuickTextInput);
 
733
    if (start < 0 || end < 0 || start > d->m_text.length() || end > d->m_text.length())
 
734
        return;
 
735
    d->setSelection(start, end-start);
 
736
}
 
737
 
 
738
/*!
 
739
    \qmlproperty string QtQuick2::TextInput::selectedText
 
740
 
 
741
    This read-only property provides the text currently selected in the
 
742
    text input.
 
743
 
 
744
    It is equivalent to the following snippet, but is faster and easier
 
745
    to use.
 
746
 
 
747
    \js
 
748
    myTextInput.text.toString().substring(myTextInput.selectionStart,
 
749
        myTextInput.selectionEnd);
 
750
    \endjs
 
751
*/
 
752
QString QQuickTextInput::selectedText() const
 
753
{
 
754
    Q_D(const QQuickTextInput);
 
755
    return d->selectedText();
 
756
}
 
757
 
 
758
/*!
 
759
    \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
 
760
 
 
761
    Whether the TextInput should gain active focus on a mouse press. By default this is
 
762
    set to true.
 
763
*/
 
764
bool QQuickTextInput::focusOnPress() const
 
765
{
 
766
    Q_D(const QQuickTextInput);
 
767
    return d->focusOnPress;
 
768
}
 
769
 
 
770
void QQuickTextInput::setFocusOnPress(bool b)
 
771
{
 
772
    Q_D(QQuickTextInput);
 
773
    if (d->focusOnPress == b)
 
774
        return;
 
775
 
 
776
    d->focusOnPress = b;
 
777
 
 
778
    emit activeFocusOnPressChanged(d->focusOnPress);
 
779
}
 
780
/*!
 
781
    \qmlproperty bool QtQuick2::TextInput::autoScroll
 
782
 
 
783
    Whether the TextInput should scroll when the text is longer than the width. By default this is
 
784
    set to true.
 
785
*/
 
786
bool QQuickTextInput::autoScroll() const
 
787
{
 
788
    Q_D(const QQuickTextInput);
 
789
    return d->autoScroll;
 
790
}
 
791
 
 
792
void QQuickTextInput::setAutoScroll(bool b)
 
793
{
 
794
    Q_D(QQuickTextInput);
 
795
    if (d->autoScroll == b)
 
796
        return;
 
797
 
 
798
    d->autoScroll = b;
 
799
    //We need to repaint so that the scrolling is taking into account.
 
800
    updateCursorRectangle();
 
801
    emit autoScrollChanged(d->autoScroll);
 
802
}
 
803
 
 
804
#ifndef QT_NO_VALIDATOR
 
805
 
 
806
/*!
 
807
    \qmlclass IntValidator QIntValidator
 
808
    \inqmlmodule QtQuick 2
 
809
    \ingroup qml-basic-visual-elements
 
810
 
 
811
    This element provides a validator for integer values.
 
812
 
 
813
    If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to
 
814
    interpret the number and will accept locale specific digits, group separators, and positive
 
815
    and negative signs.  In addition, IntValidator is always guaranteed to accept a number
 
816
    formatted according to the "C" locale.
 
817
*/
 
818
 
 
819
 
 
820
QQuickIntValidator::QQuickIntValidator(QObject *parent)
 
821
    : QIntValidator(parent)
 
822
{
 
823
}
 
824
 
 
825
/*!
 
826
    \qmlproperty string QtQuick2::IntValidator::locale
 
827
 
 
828
    This property holds the name of the locale used to interpret the number.
 
829
 
 
830
    \sa QML:Qt::locale()
 
831
*/
 
832
 
 
833
QString QQuickIntValidator::localeName() const
 
834
{
 
835
    return locale().name();
 
836
}
 
837
 
 
838
void QQuickIntValidator::setLocaleName(const QString &name)
 
839
{
 
840
    if (locale().name() != name) {
 
841
        setLocale(QLocale(name));
 
842
        emit localeNameChanged();
 
843
    }
 
844
}
 
845
 
 
846
void QQuickIntValidator::resetLocaleName()
 
847
{
 
848
    QLocale defaultLocale;
 
849
    if (locale() != defaultLocale) {
 
850
        setLocale(defaultLocale);
 
851
        emit localeNameChanged();
 
852
    }
 
853
}
 
854
 
 
855
/*!
 
856
    \qmlproperty int QtQuick2::IntValidator::top
 
857
 
 
858
    This property holds the validator's highest acceptable value.
 
859
    By default, this property's value is derived from the highest signed integer available (typically 2147483647).
 
860
*/
 
861
/*!
 
862
    \qmlproperty int QtQuick2::IntValidator::bottom
 
863
 
 
864
    This property holds the validator's lowest acceptable value.
 
865
    By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
 
866
*/
 
867
 
 
868
/*!
 
869
    \qmlclass DoubleValidator QDoubleValidator
 
870
    \inqmlmodule QtQuick 2
 
871
    \ingroup qml-basic-visual-elements
 
872
 
 
873
    This element provides a validator for non-integer numbers.
 
874
 
 
875
    Input is accepted if it contains a double that is within the valid range
 
876
    and is in the  correct format.
 
877
 
 
878
    Input is accepected but invalid if it contains a double that is outside
 
879
    the range or is in the wrong format; e.g. with too many digits after the
 
880
    decimal point or is empty.
 
881
 
 
882
    Input is rejected if it is not a double.
 
883
 
 
884
    Note: If the valid range consists of just positive doubles (e.g. 0.0 to
 
885
    100.0) and input is a negative double then it is rejected. If \l notation
 
886
    is set to DoubleValidator.StandardNotation, and  the input contains more
 
887
    digits before the decimal point than a double in the valid range may have,
 
888
    it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
 
889
    and the input is not in the valid range, it is accecpted but invalid. The
 
890
    value may yet become valid by changing the exponent.
 
891
*/
 
892
 
 
893
QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
 
894
    : QDoubleValidator(parent)
 
895
{
 
896
}
 
897
 
 
898
/*!
 
899
    \qmlproperty string QtQuick2::DoubleValidator::locale
 
900
 
 
901
    This property holds the name of the locale used to interpret the number.
 
902
 
 
903
    \sa QML:Qt::locale()
 
904
*/
 
905
 
 
906
QString QQuickDoubleValidator::localeName() const
 
907
{
 
908
    return locale().name();
 
909
}
 
910
 
 
911
void QQuickDoubleValidator::setLocaleName(const QString &name)
 
912
{
 
913
    if (locale().name() != name) {
 
914
        setLocale(QLocale(name));
 
915
        emit localeNameChanged();
 
916
    }
 
917
}
 
918
 
 
919
void QQuickDoubleValidator::resetLocaleName()
 
920
{
 
921
    QLocale defaultLocale;
 
922
    if (locale() != defaultLocale) {
 
923
        setLocale(defaultLocale);
 
924
        emit localeNameChanged();
 
925
    }
 
926
}
 
927
 
 
928
/*!
 
929
    \qmlproperty real QtQuick2::DoubleValidator::top
 
930
 
 
931
    This property holds the validator's maximum acceptable value.
 
932
    By default, this property contains a value of infinity.
 
933
*/
 
934
/*!
 
935
    \qmlproperty real QtQuick2::DoubleValidator::bottom
 
936
 
 
937
    This property holds the validator's minimum acceptable value.
 
938
    By default, this property contains a value of -infinity.
 
939
*/
 
940
/*!
 
941
    \qmlproperty int QtQuick2::DoubleValidator::decimals
 
942
 
 
943
    This property holds the validator's maximum number of digits after the decimal point.
 
944
    By default, this property contains a value of 1000.
 
945
*/
 
946
/*!
 
947
    \qmlproperty enumeration QtQuick2::DoubleValidator::notation
 
948
    This property holds the notation of how a string can describe a number.
 
949
 
 
950
    The possible values for this property are:
 
951
 
 
952
    \list
 
953
    \li DoubleValidator.StandardNotation
 
954
    \li DoubleValidator.ScientificNotation (default)
 
955
    \endlist
 
956
 
 
957
    If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
 
958
*/
 
959
 
 
960
/*!
 
961
    \qmlclass RegExpValidator QRegExpValidator
 
962
    \inqmlmodule QtQuick 2
 
963
    \ingroup qml-basic-visual-elements
 
964
 
 
965
    This element provides a validator, which counts as valid any string which
 
966
    matches a specified regular expression.
 
967
*/
 
968
/*!
 
969
   \qmlproperty regExp QtQuick2::RegExpValidator::regExp
 
970
 
 
971
   This property holds the regular expression used for validation.
 
972
 
 
973
   Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
 
974
   matching "a".
 
975
 
 
976
   By default, this property contains a regular expression with the pattern .* that matches any string.
 
977
*/
 
978
 
 
979
/*!
 
980
    \qmlproperty Validator QtQuick2::TextInput::validator
 
981
 
 
982
    Allows you to set a validator on the TextInput. When a validator is set
 
983
    the TextInput will only accept input which leaves the text property in
 
984
    an acceptable or intermediate state. The accepted signal will only be sent
 
985
    if the text is in an acceptable state when enter is pressed.
 
986
 
 
987
    Currently supported validators are IntValidator, DoubleValidator and
 
988
    RegExpValidator. An example of using validators is shown below, which allows
 
989
    input of integers between 11 and 31 into the text input:
 
990
 
 
991
    \code
 
992
    import QtQuick 2.0
 
993
    TextInput{
 
994
        validator: IntValidator{bottom: 11; top: 31;}
 
995
        focus: true
 
996
    }
 
997
    \endcode
 
998
 
 
999
    \sa acceptableInput, inputMask
 
1000
*/
 
1001
 
 
1002
QValidator* QQuickTextInput::validator() const
 
1003
{
 
1004
    Q_D(const QQuickTextInput);
 
1005
    return d->m_validator;
 
1006
}
 
1007
 
 
1008
void QQuickTextInput::setValidator(QValidator* v)
 
1009
{
 
1010
    Q_D(QQuickTextInput);
 
1011
    if (d->m_validator == v)
 
1012
        return;
 
1013
 
 
1014
    d->m_validator = v;
 
1015
 
 
1016
    if (isComponentComplete())
 
1017
        d->checkIsValid();
 
1018
 
 
1019
    emit validatorChanged();
 
1020
}
 
1021
 
 
1022
#endif // QT_NO_VALIDATOR
 
1023
 
 
1024
void QQuickTextInputPrivate::checkIsValid()
 
1025
{
 
1026
    Q_Q(QQuickTextInput);
 
1027
 
 
1028
    ValidatorState state = hasAcceptableInput(m_text);
 
1029
    m_validInput = state != InvalidInput;
 
1030
    if (state != AcceptableInput) {
 
1031
        if (m_acceptableInput) {
 
1032
            m_acceptableInput = false;
 
1033
            emit q->acceptableInputChanged();
 
1034
        }
 
1035
    } else if (!m_acceptableInput) {
 
1036
        m_acceptableInput = true;
 
1037
        emit q->acceptableInputChanged();
 
1038
    }
 
1039
}
 
1040
 
 
1041
/*!
 
1042
    \qmlproperty string QtQuick2::TextInput::inputMask
 
1043
 
 
1044
    Allows you to set an input mask on the TextInput, restricting the allowable
 
1045
    text inputs. See QLineEdit::inputMask for further details, as the exact
 
1046
    same mask strings are used by TextInput.
 
1047
 
 
1048
    \sa acceptableInput, validator
 
1049
*/
 
1050
QString QQuickTextInput::inputMask() const
 
1051
{
 
1052
    Q_D(const QQuickTextInput);
 
1053
    return d->inputMask();
 
1054
}
 
1055
 
 
1056
void QQuickTextInput::setInputMask(const QString &im)
 
1057
{
 
1058
    Q_D(QQuickTextInput);
 
1059
    if (d->inputMask() == im)
 
1060
        return;
 
1061
 
 
1062
    d->setInputMask(im);
 
1063
    emit inputMaskChanged(d->inputMask());
 
1064
}
 
1065
 
 
1066
/*!
 
1067
    \qmlproperty bool QtQuick2::TextInput::acceptableInput
 
1068
 
 
1069
    This property is always true unless a validator or input mask has been set.
 
1070
    If a validator or input mask has been set, this property will only be true
 
1071
    if the current text is acceptable to the validator or input mask as a final
 
1072
    string (not as an intermediate string).
 
1073
*/
 
1074
bool QQuickTextInput::hasAcceptableInput() const
 
1075
{
 
1076
    Q_D(const QQuickTextInput);
 
1077
    return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
 
1078
}
 
1079
 
 
1080
/*!
 
1081
    \qmlsignal QtQuick2::TextInput::onAccepted()
 
1082
 
 
1083
    This handler is called when the Return or Enter key is pressed.
 
1084
    Note that if there is a \l validator or \l inputMask set on the text
 
1085
    input, the handler will only be emitted if the input is in an acceptable
 
1086
    state.
 
1087
*/
 
1088
 
 
1089
Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
 
1090
{
 
1091
    Qt::InputMethodHints hints = inputMethodHints;
 
1092
    if (m_echoMode == QQuickTextInput::Password || m_echoMode == QQuickTextInput::NoEcho)
 
1093
        hints |= Qt::ImhHiddenText;
 
1094
    else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit)
 
1095
        hints &= ~Qt::ImhHiddenText;
 
1096
    if (m_echoMode != QQuickTextInput::Normal)
 
1097
        hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData);
 
1098
    return hints;
 
1099
}
 
1100
/*!
 
1101
    \qmlproperty enumeration QtQuick2::TextInput::echoMode
 
1102
 
 
1103
    Specifies how the text should be displayed in the TextInput.
 
1104
    \list
 
1105
    \li TextInput.Normal - Displays the text as it is. (Default)
 
1106
    \li TextInput.Password - Displays asterisks instead of characters.
 
1107
    \li TextInput.NoEcho - Displays nothing.
 
1108
    \li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
 
1109
    while editing, otherwise displays asterisks.
 
1110
    \endlist
 
1111
*/
 
1112
QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
 
1113
{
 
1114
    Q_D(const QQuickTextInput);
 
1115
    return QQuickTextInput::EchoMode(d->m_echoMode);
 
1116
}
 
1117
 
 
1118
void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
 
1119
{
 
1120
    Q_D(QQuickTextInput);
 
1121
    if (echoMode() == echo)
 
1122
        return;
 
1123
    d->cancelPasswordEchoTimer();
 
1124
    d->m_echoMode = echo;
 
1125
    d->m_passwordEchoEditing = false;
 
1126
    updateInputMethod(Qt::ImHints);
 
1127
    d->updateDisplayText();
 
1128
    updateCursorRectangle();
 
1129
 
 
1130
    emit echoModeChanged(echoMode());
 
1131
}
 
1132
 
 
1133
/*!
 
1134
    \qmlproperty enumeration QtQuick2::TextInput::inputMethodHints
 
1135
 
 
1136
    Provides hints to the input method about the expected content of the text input and how it
 
1137
    should operate.
 
1138
 
 
1139
    The value is a bit-wise combination of flags, or Qt.ImhNone if no hints are set.
 
1140
 
 
1141
    Flags that alter behaviour are:
 
1142
 
 
1143
    \list
 
1144
    \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
 
1145
            This is automatically set when setting echoMode to \c TextInput.Password.
 
1146
    \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
 
1147
            in any persistent storage like predictive user dictionary.
 
1148
    \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
 
1149
            when a sentence ends.
 
1150
    \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
 
1151
    \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
 
1152
    \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
 
1153
    \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
 
1154
 
 
1155
    \li Qt.ImhDate - The text editor functions as a date field.
 
1156
    \li Qt.ImhTime - The text editor functions as a time field.
 
1157
    \endlist
 
1158
 
 
1159
    Flags that restrict input (exclusive flags) are:
 
1160
 
 
1161
    \list
 
1162
    \li Qt.ImhDigitsOnly - Only digits are allowed.
 
1163
    \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
 
1164
    \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
 
1165
    \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
 
1166
    \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
 
1167
    \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
 
1168
    \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
 
1169
    \endlist
 
1170
 
 
1171
    Masks:
 
1172
 
 
1173
    \list
 
1174
    \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
 
1175
    \endlist
 
1176
*/
 
1177
 
 
1178
Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
 
1179
{
 
1180
    Q_D(const QQuickTextInput);
 
1181
    return d->inputMethodHints;
 
1182
}
 
1183
 
 
1184
void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
 
1185
{
 
1186
    Q_D(QQuickTextInput);
 
1187
 
 
1188
    if (hints == d->inputMethodHints)
 
1189
        return;
 
1190
 
 
1191
    d->inputMethodHints = hints;
 
1192
    updateInputMethod(Qt::ImHints);
 
1193
    emit inputMethodHintsChanged();
 
1194
}
 
1195
 
 
1196
/*!
 
1197
    \qmlproperty Component QtQuick2::TextInput::cursorDelegate
 
1198
    The delegate for the cursor in the TextInput.
 
1199
 
 
1200
    If you set a cursorDelegate for a TextInput, this delegate will be used for
 
1201
    drawing the cursor instead of the standard cursor. An instance of the
 
1202
    delegate will be created and managed by the TextInput when a cursor is
 
1203
    needed, and the x property of delegate instance will be set so as
 
1204
    to be one pixel before the top left of the current character.
 
1205
 
 
1206
    Note that the root item of the delegate component must be a QQuickItem or
 
1207
    QQuickItem derived item.
 
1208
*/
 
1209
QQmlComponent* QQuickTextInput::cursorDelegate() const
 
1210
{
 
1211
    Q_D(const QQuickTextInput);
 
1212
    return d->cursorComponent;
 
1213
}
 
1214
 
 
1215
void QQuickTextInput::setCursorDelegate(QQmlComponent* c)
 
1216
{
 
1217
    Q_D(QQuickTextInput);
 
1218
    if (d->cursorComponent == c)
 
1219
        return;
 
1220
 
 
1221
    d->cursorComponent = c;
 
1222
    if (!c) {
 
1223
        //note that the components are owned by something else
 
1224
        delete d->cursorItem;
 
1225
        d->cursorItem = 0;
 
1226
    } else {
 
1227
        d->startCreatingCursor();
 
1228
    }
 
1229
 
 
1230
    emit cursorDelegateChanged();
 
1231
}
 
1232
 
 
1233
void QQuickTextInputPrivate::startCreatingCursor()
 
1234
{
 
1235
    Q_Q(QQuickTextInput);
 
1236
    if (cursorComponent->isReady()) {
 
1237
        q->createCursor();
 
1238
    } else if (cursorComponent->isLoading()) {
 
1239
        q->connect(cursorComponent, SIGNAL(statusChanged(int)),
 
1240
                q, SLOT(createCursor()));
 
1241
    } else { // isError
 
1242
        qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
 
1243
    }
 
1244
}
 
1245
 
 
1246
void QQuickTextInput::createCursor()
 
1247
{
 
1248
    Q_D(QQuickTextInput);
 
1249
    if (!isComponentComplete())
 
1250
        return;
 
1251
 
 
1252
    if (d->cursorComponent->isError()) {
 
1253
        qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
 
1254
        return;
 
1255
    }
 
1256
 
 
1257
    if (!d->cursorComponent->isReady())
 
1258
        return;
 
1259
 
 
1260
    if (d->cursorItem)
 
1261
        delete d->cursorItem;
 
1262
    QQmlContext *creationContext = d->cursorComponent->creationContext();
 
1263
    QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
 
1264
    d->cursorItem = qobject_cast<QQuickItem*>(object);
 
1265
    if (!d->cursorItem) {
 
1266
        delete object;
 
1267
        qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
 
1268
        return;
 
1269
    }
 
1270
 
 
1271
    QRectF r = cursorRectangle();
 
1272
 
 
1273
    QQml_setParent_noEvent(d->cursorItem, this);
 
1274
    d->cursorItem->setParentItem(this);
 
1275
    d->cursorItem->setPos(r.topLeft());
 
1276
    d->cursorItem->setHeight(r.height());
 
1277
}
 
1278
 
 
1279
/*!
 
1280
    \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
 
1281
 
 
1282
    This function takes a character position and returns the rectangle that the
 
1283
    cursor would occupy, if it was placed at that character position.
 
1284
 
 
1285
    This is similar to setting the cursorPosition, and then querying the cursor
 
1286
    rectangle, but the cursorPosition is not changed.
 
1287
*/
 
1288
QRectF QQuickTextInput::positionToRectangle(int pos) const
 
1289
{
 
1290
    Q_D(const QQuickTextInput);
 
1291
    if (d->m_echoMode == NoEcho)
 
1292
        pos = 0;
 
1293
    else if (pos > d->m_cursor)
 
1294
        pos += d->preeditAreaText().length();
 
1295
    QTextLine l = d->m_textLayout.lineForTextPosition(pos);
 
1296
    return l.isValid()
 
1297
            ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
 
1298
            : QRectF();
 
1299
}
 
1300
 
 
1301
/*!
 
1302
    \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
 
1303
 
 
1304
    This function returns the character position at
 
1305
    x and y pixels from the top left  of the textInput. Position 0 is before the
 
1306
    first character, position 1 is after the first character but before the second,
 
1307
    and so on until position text.length, which is after all characters.
 
1308
 
 
1309
    This means that for all x values before the first character this function returns 0,
 
1310
    and for all x values after the last character this function returns text.length.  If
 
1311
    the y value is above the text the position will be that of the nearest character on
 
1312
    the first line line and if it is below the text the position of the nearest character
 
1313
    on the last line will be returned.
 
1314
 
 
1315
    The cursor position type specifies how the cursor position should be resolved.
 
1316
 
 
1317
    \list
 
1318
    \li TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
 
1319
    \li TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
 
1320
    \endlist
 
1321
*/
 
1322
 
 
1323
void QQuickTextInput::positionAt(QQmlV8Function *args) const
 
1324
{
 
1325
    Q_D(const QQuickTextInput);
 
1326
 
 
1327
    qreal x = 0;
 
1328
    qreal y = 0;
 
1329
    QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
 
1330
 
 
1331
    if (args->Length() < 1)
 
1332
        return;
 
1333
 
 
1334
    int i = 0;
 
1335
    v8::Local<v8::Value> arg = (*args)[i];
 
1336
    x = arg->NumberValue();
 
1337
 
 
1338
    if (++i < args->Length()) {
 
1339
        arg = (*args)[i];
 
1340
        y = arg->NumberValue();
 
1341
    }
 
1342
 
 
1343
    if (++i < args->Length()) {
 
1344
        arg = (*args)[i];
 
1345
        position = QTextLine::CursorPosition(arg->Int32Value());
 
1346
    }
 
1347
 
 
1348
    int pos = d->positionAt(x, y, position);
 
1349
    const int cursor = d->m_cursor;
 
1350
    if (pos > cursor) {
 
1351
        const int preeditLength = d->preeditAreaText().length();
 
1352
        pos = pos > cursor + preeditLength
 
1353
                ? pos - preeditLength
 
1354
                : cursor;
 
1355
    }
 
1356
    args->returnValue(v8::Int32::New(pos));
 
1357
}
 
1358
 
 
1359
int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
 
1360
{
 
1361
    x += hscroll;
 
1362
    y += vscroll;
 
1363
    QTextLine line = m_textLayout.lineAt(0);
 
1364
    for (int i = 1; i < m_textLayout.lineCount(); ++i) {
 
1365
        QTextLine nextLine = m_textLayout.lineAt(i);
 
1366
 
 
1367
        if (y < (line.rect().bottom() + nextLine.y()) / 2)
 
1368
            break;
 
1369
        line = nextLine;
 
1370
    }
 
1371
    return line.isValid() ? line.xToCursor(x, position) : 0;
 
1372
}
 
1373
 
 
1374
void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
 
1375
{
 
1376
    Q_D(QQuickTextInput);
 
1377
    // Don't allow MacOSX up/down support, and we don't allow a completer.
 
1378
    bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
 
1379
    if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
 
1380
        // Ignore when moving off the end unless there is a selection,
 
1381
        // because then moving will do something (deselect).
 
1382
        int cursorPosition = d->m_cursor;
 
1383
        if (cursorPosition == 0)
 
1384
            ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
 
1385
        if (cursorPosition == text().length())
 
1386
            ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
 
1387
    }
 
1388
    if (ignore) {
 
1389
        ev->ignore();
 
1390
    } else {
 
1391
        d->processKeyEvent(ev);
 
1392
    }
 
1393
    if (!ev->isAccepted())
 
1394
        QQuickImplicitSizeItem::keyPressEvent(ev);
 
1395
}
 
1396
 
 
1397
void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
 
1398
{
 
1399
    Q_D(QQuickTextInput);
 
1400
    const bool wasComposing = d->hasImState;
 
1401
    if (d->m_readOnly) {
 
1402
        ev->ignore();
 
1403
    } else {
 
1404
        d->processInputMethodEvent(ev);
 
1405
    }
 
1406
    if (!ev->isAccepted())
 
1407
        QQuickImplicitSizeItem::inputMethodEvent(ev);
 
1408
 
 
1409
    if (wasComposing != d->hasImState)
 
1410
        emit inputMethodComposingChanged();
 
1411
}
 
1412
 
 
1413
void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
 
1414
{
 
1415
    Q_D(QQuickTextInput);
 
1416
 
 
1417
    if (d->selectByMouse && event->button() == Qt::LeftButton) {
 
1418
        d->commitPreedit();
 
1419
        int cursor = d->positionAt(event->localPos());
 
1420
        d->selectWordAtPos(cursor);
 
1421
        event->setAccepted(true);
 
1422
        if (!d->hasPendingTripleClick()) {
 
1423
            d->tripleClickStartPoint = event->localPos();
 
1424
            d->tripleClickTimer.start();
 
1425
        }
 
1426
    } else {
 
1427
        if (d->sendMouseEventToInputContext(event))
 
1428
            return;
 
1429
        QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
 
1430
    }
 
1431
}
 
1432
 
 
1433
void QQuickTextInput::mousePressEvent(QMouseEvent *event)
 
1434
{
 
1435
    Q_D(QQuickTextInput);
 
1436
 
 
1437
    d->pressPos = event->localPos();
 
1438
 
 
1439
    if (d->sendMouseEventToInputContext(event))
 
1440
        return;
 
1441
 
 
1442
    if (d->selectByMouse) {
 
1443
        setKeepMouseGrab(false);
 
1444
        d->selectPressed = true;
 
1445
        QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
 
1446
        if (d->hasPendingTripleClick()
 
1447
            && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
 
1448
            event->setAccepted(true);
 
1449
            selectAll();
 
1450
            return;
 
1451
        }
 
1452
    }
 
1453
 
 
1454
    bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
 
1455
    int cursor = d->positionAt(event->localPos());
 
1456
    d->moveCursor(cursor, mark);
 
1457
 
 
1458
    if (d->focusOnPress) {
 
1459
        bool hadActiveFocus = hasActiveFocus();
 
1460
        forceActiveFocus();
 
1461
        // re-open input panel on press if already focused
 
1462
        if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
 
1463
            openSoftwareInputPanel();
 
1464
    }
 
1465
 
 
1466
    event->setAccepted(true);
 
1467
}
 
1468
 
 
1469
void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
 
1470
{
 
1471
    Q_D(QQuickTextInput);
 
1472
 
 
1473
    if (d->selectPressed) {
 
1474
        if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
 
1475
            setKeepMouseGrab(true);
 
1476
 
 
1477
        if (d->composeMode()) {
 
1478
            // start selection
 
1479
            int startPos = d->positionAt(d->pressPos);
 
1480
            int currentPos = d->positionAt(event->localPos());
 
1481
            if (startPos != currentPos)
 
1482
                d->setSelection(startPos, currentPos - startPos);
 
1483
        } else {
 
1484
            moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
 
1485
        }
 
1486
        event->setAccepted(true);
 
1487
    } else {
 
1488
        QQuickImplicitSizeItem::mouseMoveEvent(event);
 
1489
    }
 
1490
}
 
1491
 
 
1492
void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
 
1493
{
 
1494
    Q_D(QQuickTextInput);
 
1495
    if (d->sendMouseEventToInputContext(event))
 
1496
        return;
 
1497
    if (d->selectPressed) {
 
1498
        d->selectPressed = false;
 
1499
        setKeepMouseGrab(false);
 
1500
    }
 
1501
#ifndef QT_NO_CLIPBOARD
 
1502
    if (QGuiApplication::clipboard()->supportsSelection()) {
 
1503
        if (event->button() == Qt::LeftButton) {
 
1504
            d->copy(QClipboard::Selection);
 
1505
        } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
 
1506
            d->deselect();
 
1507
            d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
 
1508
        }
 
1509
    }
 
1510
#endif
 
1511
    if (!event->isAccepted())
 
1512
        QQuickImplicitSizeItem::mouseReleaseEvent(event);
 
1513
}
 
1514
 
 
1515
bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
 
1516
{
 
1517
#if !defined QT_NO_IM
 
1518
    if (composeMode()) {
 
1519
        int tmp_cursor = positionAt(event->localPos());
 
1520
        int mousePos = tmp_cursor - m_cursor;
 
1521
        if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
 
1522
            if (event->type() == QEvent::MouseButtonRelease) {
 
1523
                qApp->inputMethod()->invokeAction(QInputMethod::Click, mousePos);
 
1524
            }
 
1525
            return true;
 
1526
        }
 
1527
    }
 
1528
#else
 
1529
    Q_UNUSED(event);
 
1530
    Q_UNUSED(eventType)
 
1531
#endif
 
1532
 
 
1533
    return false;
 
1534
}
 
1535
 
 
1536
void QQuickTextInput::mouseUngrabEvent()
 
1537
{
 
1538
    Q_D(QQuickTextInput);
 
1539
    d->selectPressed = false;
 
1540
    setKeepMouseGrab(false);
 
1541
}
 
1542
 
 
1543
bool QQuickTextInput::event(QEvent* ev)
 
1544
{
 
1545
#ifndef QT_NO_SHORTCUT
 
1546
    Q_D(QQuickTextInput);
 
1547
    if (ev->type() == QEvent::ShortcutOverride) {
 
1548
        if (d->m_readOnly)
 
1549
            return false;
 
1550
        QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
 
1551
        if (ke == QKeySequence::Copy
 
1552
            || ke == QKeySequence::Paste
 
1553
            || ke == QKeySequence::Cut
 
1554
            || ke == QKeySequence::Redo
 
1555
            || ke == QKeySequence::Undo
 
1556
            || ke == QKeySequence::MoveToNextWord
 
1557
            || ke == QKeySequence::MoveToPreviousWord
 
1558
            || ke == QKeySequence::MoveToStartOfDocument
 
1559
            || ke == QKeySequence::MoveToEndOfDocument
 
1560
            || ke == QKeySequence::SelectNextWord
 
1561
            || ke == QKeySequence::SelectPreviousWord
 
1562
            || ke == QKeySequence::SelectStartOfLine
 
1563
            || ke == QKeySequence::SelectEndOfLine
 
1564
            || ke == QKeySequence::SelectStartOfBlock
 
1565
            || ke == QKeySequence::SelectEndOfBlock
 
1566
            || ke == QKeySequence::SelectStartOfDocument
 
1567
            || ke == QKeySequence::SelectAll
 
1568
            || ke == QKeySequence::SelectEndOfDocument) {
 
1569
            ke->accept();
 
1570
        } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
 
1571
                   || ke->modifiers() == Qt::KeypadModifier) {
 
1572
            if (ke->key() < Qt::Key_Escape) {
 
1573
                ke->accept();
 
1574
                return true;
 
1575
            } else {
 
1576
                switch (ke->key()) {
 
1577
                case Qt::Key_Delete:
 
1578
                case Qt::Key_Home:
 
1579
                case Qt::Key_End:
 
1580
                case Qt::Key_Backspace:
 
1581
                case Qt::Key_Left:
 
1582
                case Qt::Key_Right:
 
1583
                    return true;
 
1584
                default:
 
1585
                    break;
 
1586
                }
 
1587
            }
 
1588
        }
 
1589
    }
 
1590
#endif
 
1591
 
 
1592
    return QQuickImplicitSizeItem::event(ev);
 
1593
}
 
1594
 
 
1595
void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
 
1596
                                  const QRectF &oldGeometry)
 
1597
{
 
1598
    Q_D(QQuickTextInput);
 
1599
    if (!d->inLayout) {
 
1600
        if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
 
1601
            d->updateLayout();
 
1602
        updateCursorRectangle();
 
1603
    }
 
1604
    QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
 
1605
}
 
1606
 
 
1607
void QQuickTextInputPrivate::updateHorizontalScroll()
 
1608
{
 
1609
    Q_Q(QQuickTextInput);
 
1610
    QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
 
1611
    const int preeditLength = m_textLayout.preeditAreaText().length();
 
1612
    const qreal width = qMax<qreal>(0, q->width());
 
1613
    qreal cix = 0;
 
1614
    qreal widthUsed = 0;
 
1615
    if (currentLine.isValid()) {
 
1616
        cix = currentLine.cursorToX(m_cursor + preeditLength);
 
1617
        const qreal cursorWidth = cix >= 0 ? cix : width - cix;
 
1618
        widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
 
1619
    }
 
1620
    int previousScroll = hscroll;
 
1621
 
 
1622
    if (!autoScroll || widthUsed <=  width || m_echoMode == QQuickTextInput::NoEcho) {
 
1623
        hscroll = 0;
 
1624
    } else {
 
1625
        Q_ASSERT(currentLine.isValid());
 
1626
        if (cix - hscroll >= width) {
 
1627
            // text doesn't fit, cursor is to the right of br (scroll right)
 
1628
            hscroll = cix - width;
 
1629
        } else if (cix - hscroll < 0 && hscroll < widthUsed) {
 
1630
            // text doesn't fit, cursor is to the left of br (scroll left)
 
1631
            hscroll = cix;
 
1632
        } else if (widthUsed - hscroll < width) {
 
1633
            // text doesn't fit, text document is to the left of br; align
 
1634
            // right
 
1635
            hscroll = widthUsed - width;
 
1636
        } else if (width - hscroll > widthUsed) {
 
1637
            // text doesn't fit, text document is to the right of br; align
 
1638
            // left
 
1639
            hscroll = width - widthUsed;
 
1640
        }
 
1641
        if (preeditLength > 0) {
 
1642
            // check to ensure long pre-edit text doesn't push the cursor
 
1643
            // off to the left
 
1644
             cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
 
1645
             if (cix < hscroll)
 
1646
                 hscroll = cix;
 
1647
        }
 
1648
    }
 
1649
    if (previousScroll != hscroll)
 
1650
        textLayoutDirty = true;
 
1651
}
 
1652
 
 
1653
void QQuickTextInputPrivate::updateVerticalScroll()
 
1654
{
 
1655
    Q_Q(QQuickTextInput);
 
1656
    const int preeditLength = m_textLayout.preeditAreaText().length();
 
1657
    const qreal height = qMax<qreal>(0, q->height());
 
1658
    qreal heightUsed = boundingRect.height();
 
1659
    qreal previousScroll = vscroll;
 
1660
 
 
1661
    if (!autoScroll || heightUsed <=  height) {
 
1662
        // text fits in br; use vscroll for alignment
 
1663
        switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
 
1664
        case Qt::AlignBottom:
 
1665
            vscroll = heightUsed - height;
 
1666
            break;
 
1667
        case Qt::AlignVCenter:
 
1668
            vscroll = (heightUsed - height) / 2;
 
1669
            break;
 
1670
        default:
 
1671
            // Top
 
1672
            vscroll = 0;
 
1673
            break;
 
1674
        }
 
1675
    } else {
 
1676
        QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
 
1677
        QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
 
1678
        qreal top = r.top();
 
1679
        int bottom = r.bottom();
 
1680
 
 
1681
        if (bottom - vscroll >= height) {
 
1682
            // text doesn't fit, cursor is to the below the br (scroll down)
 
1683
            vscroll = bottom - height;
 
1684
        } else if (top - vscroll < 0 && vscroll < heightUsed) {
 
1685
            // text doesn't fit, cursor is above br (scroll up)
 
1686
            vscroll = top;
 
1687
        } else if (heightUsed - vscroll < height) {
 
1688
            // text doesn't fit, text document is to the left of br; align
 
1689
            // right
 
1690
            vscroll = heightUsed - height;
 
1691
        }
 
1692
        if (preeditLength > 0) {
 
1693
            // check to ensure long pre-edit text doesn't push the cursor
 
1694
            // off the top
 
1695
            currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
 
1696
            top = currentLine.isValid() ? currentLine.rect().top() : 0;
 
1697
            if (top < vscroll)
 
1698
                vscroll = top;
 
1699
        }
 
1700
    }
 
1701
    if (previousScroll != vscroll)
 
1702
        textLayoutDirty = true;
 
1703
}
 
1704
 
 
1705
void QQuickTextInput::triggerPreprocess()
 
1706
{
 
1707
    Q_D(QQuickTextInput);
 
1708
    if (d->updateType == QQuickTextInputPrivate::UpdateNone)
 
1709
        d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
 
1710
    update();
 
1711
}
 
1712
 
 
1713
QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
 
1714
{
 
1715
    Q_UNUSED(data);
 
1716
    Q_D(QQuickTextInput);
 
1717
 
 
1718
    if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
 
1719
        // Update done in preprocess() in the nodes
 
1720
        d->updateType = QQuickTextInputPrivate::UpdateNone;
 
1721
        return oldNode;
 
1722
    }
 
1723
 
 
1724
    d->updateType = QQuickTextInputPrivate::UpdateNone;
 
1725
 
 
1726
    QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
 
1727
    if (node == 0)
 
1728
        node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
 
1729
    d->textNode = node;
 
1730
 
 
1731
    if (!d->textLayoutDirty) {
 
1732
        QSGSimpleRectNode *cursorNode = node->cursorNode();
 
1733
        if (cursorNode != 0 && !isReadOnly()) {
 
1734
            cursorNode->setRect(cursorRectangle());
 
1735
 
 
1736
            if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
 
1737
                d->hideCursor();
 
1738
            } else {
 
1739
                d->showCursor();
 
1740
            }
 
1741
        }
 
1742
    } else {
 
1743
        node->deleteContent();
 
1744
        node->setMatrix(QMatrix4x4());
 
1745
 
 
1746
        QPointF offset(0, 0);
 
1747
        if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
 
1748
            QFontMetricsF fm(d->font);
 
1749
            // the y offset is there to keep the baseline constant in case we have script changes in the text.
 
1750
            offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
 
1751
        } else {
 
1752
            offset = -QPoint(d->hscroll, d->vscroll);
 
1753
        }
 
1754
 
 
1755
        if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
 
1756
            node->addTextLayout(offset, &d->m_textLayout, d->color,
 
1757
                                QQuickText::Normal, QColor(), QColor(),
 
1758
                                d->selectionColor, d->selectedTextColor,
 
1759
                                d->selectionStart(),
 
1760
                                d->selectionEnd() - 1); // selectionEnd() returns first char after
 
1761
                                                                 // selection
 
1762
        }
 
1763
 
 
1764
        if (!isReadOnly() && d->cursorItem == 0) {
 
1765
            node->setCursor(cursorRectangle(), d->color);
 
1766
            if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
 
1767
                d->hideCursor();
 
1768
            } else {
 
1769
                d->showCursor();
 
1770
            }
 
1771
        }
 
1772
 
 
1773
        d->textLayoutDirty = false;
 
1774
    }
 
1775
 
 
1776
    return node;
 
1777
}
 
1778
 
 
1779
QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
 
1780
{
 
1781
    Q_D(const QQuickTextInput);
 
1782
    switch (property) {
 
1783
    case Qt::ImEnabled:
 
1784
        return QVariant((bool)(flags() & ItemAcceptsInputMethod));
 
1785
    case Qt::ImHints:
 
1786
        return QVariant((int) d->effectiveInputMethodHints());
 
1787
    case Qt::ImCursorRectangle:
 
1788
        return cursorRectangle();
 
1789
    case Qt::ImFont:
 
1790
        return font();
 
1791
    case Qt::ImCursorPosition:
 
1792
        return QVariant(d->m_cursor);
 
1793
    case Qt::ImSurroundingText:
 
1794
        if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
 
1795
            return QVariant(displayText());
 
1796
        } else {
 
1797
            return QVariant(d->realText());
 
1798
        }
 
1799
    case Qt::ImCurrentSelection:
 
1800
        return QVariant(selectedText());
 
1801
    case Qt::ImMaximumTextLength:
 
1802
        return QVariant(maxLength());
 
1803
    case Qt::ImAnchorPosition:
 
1804
        if (d->selectionStart() == d->selectionEnd())
 
1805
            return QVariant(d->m_cursor);
 
1806
        else if (d->selectionStart() == d->m_cursor)
 
1807
            return QVariant(d->selectionEnd());
 
1808
        else
 
1809
            return QVariant(d->selectionStart());
 
1810
    default:
 
1811
        return QVariant();
 
1812
    }
 
1813
}
 
1814
 
 
1815
/*!
 
1816
    \qmlmethod void QtQuick2::TextInput::deselect()
 
1817
 
 
1818
    Removes active text selection.
 
1819
*/
 
1820
void QQuickTextInput::deselect()
 
1821
{
 
1822
    Q_D(QQuickTextInput);
 
1823
    d->deselect();
 
1824
}
 
1825
 
 
1826
/*!
 
1827
    \qmlmethod void QtQuick2::TextInput::selectAll()
 
1828
 
 
1829
    Causes all text to be selected.
 
1830
*/
 
1831
void QQuickTextInput::selectAll()
 
1832
{
 
1833
    Q_D(QQuickTextInput);
 
1834
    d->setSelection(0, text().length());
 
1835
}
 
1836
 
 
1837
/*!
 
1838
    \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
 
1839
 
 
1840
    Returns true if the natural reading direction of the editor text
 
1841
    found between positions \a start and \a end is right to left.
 
1842
*/
 
1843
bool QQuickTextInput::isRightToLeft(int start, int end)
 
1844
{
 
1845
    if (start > end) {
 
1846
        qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
 
1847
        return false;
 
1848
    } else {
 
1849
        return text().mid(start, end - start).isRightToLeft();
 
1850
    }
 
1851
}
 
1852
 
 
1853
#ifndef QT_NO_CLIPBOARD
 
1854
/*!
 
1855
    \qmlmethod QtQuick2::TextInput::cut()
 
1856
 
 
1857
    Moves the currently selected text to the system clipboard.
 
1858
*/
 
1859
void QQuickTextInput::cut()
 
1860
{
 
1861
    Q_D(QQuickTextInput);
 
1862
    d->copy();
 
1863
    d->del();
 
1864
}
 
1865
 
 
1866
/*!
 
1867
    \qmlmethod QtQuick2::TextInput::copy()
 
1868
 
 
1869
    Copies the currently selected text to the system clipboard.
 
1870
*/
 
1871
void QQuickTextInput::copy()
 
1872
{
 
1873
    Q_D(QQuickTextInput);
 
1874
    d->copy();
 
1875
}
 
1876
 
 
1877
/*!
 
1878
    \qmlmethod QtQuick2::TextInput::paste()
 
1879
 
 
1880
    Replaces the currently selected text by the contents of the system clipboard.
 
1881
*/
 
1882
void QQuickTextInput::paste()
 
1883
{
 
1884
    Q_D(QQuickTextInput);
 
1885
    if (!d->m_readOnly)
 
1886
        d->paste();
 
1887
}
 
1888
#endif // QT_NO_CLIPBOARD
 
1889
 
 
1890
/*!
 
1891
    Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
 
1892
    current selection, and updates the selection start to the current cursor
 
1893
    position.
 
1894
*/
 
1895
 
 
1896
void QQuickTextInput::undo()
 
1897
{
 
1898
    Q_D(QQuickTextInput);
 
1899
    if (!d->m_readOnly) {
 
1900
        d->internalUndo();
 
1901
        d->finishChange(-1, true);
 
1902
    }
 
1903
}
 
1904
 
 
1905
/*!
 
1906
    Redoes the last operation if redo is \l {canRedo}{available}.
 
1907
*/
 
1908
 
 
1909
void QQuickTextInput::redo()
 
1910
{
 
1911
    Q_D(QQuickTextInput);
 
1912
    if (!d->m_readOnly) {
 
1913
        d->internalRedo();
 
1914
        d->finishChange();
 
1915
    }
 
1916
}
 
1917
 
 
1918
/*!
 
1919
    \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
 
1920
 
 
1921
    Inserts \a text into the TextInput at position.
 
1922
*/
 
1923
 
 
1924
void QQuickTextInput::insert(int position, const QString &text)
 
1925
{
 
1926
    Q_D(QQuickTextInput);
 
1927
    if (d->m_echoMode == QQuickTextInput::Password) {
 
1928
        int delay = qGuiApp->styleHints()->passwordMaskDelay();
 
1929
        if (delay > 0)
 
1930
            d->m_passwordEchoTimer.start(delay, this);
 
1931
    }
 
1932
    if (position < 0 || position > d->m_text.length())
 
1933
        return;
 
1934
 
 
1935
    const int priorState = d->m_undoState;
 
1936
 
 
1937
    QString insertText = text;
 
1938
 
 
1939
    if (d->hasSelectedText()) {
 
1940
        d->addCommand(QQuickTextInputPrivate::Command(
 
1941
                QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
 
1942
    }
 
1943
    if (d->m_maskData) {
 
1944
        insertText = d->maskString(position, insertText);
 
1945
        for (int i = 0; i < insertText.length(); ++i) {
 
1946
            d->addCommand(QQuickTextInputPrivate::Command(
 
1947
                    QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
 
1948
            d->addCommand(QQuickTextInputPrivate::Command(
 
1949
                    QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
 
1950
        }
 
1951
        d->m_text.replace(position, insertText.length(), insertText);
 
1952
        if (!insertText.isEmpty())
 
1953
            d->m_textDirty = true;
 
1954
        if (position < d->m_selend && position + insertText.length() > d->m_selstart)
 
1955
            d->m_selDirty = true;
 
1956
    } else {
 
1957
        int remaining = d->m_maxLength - d->m_text.length();
 
1958
        if (remaining != 0) {
 
1959
            insertText = insertText.left(remaining);
 
1960
            d->m_text.insert(position, insertText);
 
1961
            for (int i = 0; i < insertText.length(); ++i)
 
1962
               d->addCommand(QQuickTextInputPrivate::Command(
 
1963
                    QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
 
1964
            if (d->m_cursor >= position)
 
1965
                d->m_cursor += insertText.length();
 
1966
            if (d->m_selstart >= position)
 
1967
                d->m_selstart += insertText.length();
 
1968
            if (d->m_selend >= position)
 
1969
                d->m_selend += insertText.length();
 
1970
            d->m_textDirty = true;
 
1971
            if (position >= d->m_selstart && position <= d->m_selend)
 
1972
                d->m_selDirty = true;
 
1973
        }
 
1974
    }
 
1975
 
 
1976
    d->addCommand(QQuickTextInputPrivate::Command(
 
1977
            QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
 
1978
    d->finishChange(priorState);
 
1979
 
 
1980
    if (d->lastSelectionStart != d->lastSelectionEnd) {
 
1981
        if (d->m_selstart != d->lastSelectionStart) {
 
1982
            d->lastSelectionStart = d->m_selstart;
 
1983
            emit selectionStartChanged();
 
1984
        }
 
1985
        if (d->m_selend != d->lastSelectionEnd) {
 
1986
            d->lastSelectionEnd = d->m_selend;
 
1987
            emit selectionEndChanged();
 
1988
        }
 
1989
    }
 
1990
}
 
1991
 
 
1992
/*!
 
1993
    \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
 
1994
 
 
1995
    Removes the section of text that is between the \a start and \a end positions from the TextInput.
 
1996
*/
 
1997
 
 
1998
void QQuickTextInput::remove(int start, int end)
 
1999
{
 
2000
    Q_D(QQuickTextInput);
 
2001
 
 
2002
    start = qBound(0, start, d->m_text.length());
 
2003
    end = qBound(0, end, d->m_text.length());
 
2004
 
 
2005
    if (start > end)
 
2006
        qSwap(start, end);
 
2007
    else if (start == end)
 
2008
        return;
 
2009
 
 
2010
    if (start < d->m_selend && end > d->m_selstart)
 
2011
        d->m_selDirty = true;
 
2012
 
 
2013
    const int priorState = d->m_undoState;
 
2014
 
 
2015
    d->addCommand(QQuickTextInputPrivate::Command(
 
2016
            QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
 
2017
 
 
2018
    if (start <= d->m_cursor && d->m_cursor < end) {
 
2019
        // cursor is within the selection. Split up the commands
 
2020
        // to be able to restore the correct cursor position
 
2021
        for (int i = d->m_cursor; i >= start; --i) {
 
2022
            d->addCommand(QQuickTextInputPrivate::Command(
 
2023
                    QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
 
2024
        }
 
2025
        for (int i = end - 1; i > d->m_cursor; --i) {
 
2026
            d->addCommand(QQuickTextInputPrivate::Command(
 
2027
                    QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
 
2028
        }
 
2029
    } else {
 
2030
        for (int i = end - 1; i >= start; --i) {
 
2031
            d->addCommand(QQuickTextInputPrivate::Command(
 
2032
                    QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
 
2033
        }
 
2034
    }
 
2035
    if (d->m_maskData) {
 
2036
        d->m_text.replace(start, end - start,  d->clearString(start, end - start));
 
2037
        for (int i = 0; i < end - start; ++i) {
 
2038
            d->addCommand(QQuickTextInputPrivate::Command(
 
2039
                    QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
 
2040
        }
 
2041
    } else {
 
2042
        d->m_text.remove(start, end - start);
 
2043
 
 
2044
        if (d->m_cursor > start)
 
2045
            d->m_cursor -= qMin(d->m_cursor, end) - start;
 
2046
        if (d->m_selstart > start)
 
2047
            d->m_selstart -= qMin(d->m_selstart, end) - start;
 
2048
        if (d->m_selend > end)
 
2049
            d->m_selend -= qMin(d->m_selend, end) - start;
 
2050
    }
 
2051
    d->addCommand(QQuickTextInputPrivate::Command(
 
2052
            QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
 
2053
 
 
2054
    d->m_textDirty = true;
 
2055
    d->finishChange(priorState);
 
2056
 
 
2057
    if (d->lastSelectionStart != d->lastSelectionEnd) {
 
2058
        if (d->m_selstart != d->lastSelectionStart) {
 
2059
            d->lastSelectionStart = d->m_selstart;
 
2060
            emit selectionStartChanged();
 
2061
        }
 
2062
        if (d->m_selend != d->lastSelectionEnd) {
 
2063
            d->lastSelectionEnd = d->m_selend;
 
2064
            emit selectionEndChanged();
 
2065
        }
 
2066
    }
 
2067
}
 
2068
 
 
2069
 
 
2070
/*!
 
2071
    \qmlmethod void QtQuick2::TextInput::selectWord()
 
2072
 
 
2073
    Causes the word closest to the current cursor position to be selected.
 
2074
*/
 
2075
void QQuickTextInput::selectWord()
 
2076
{
 
2077
    Q_D(QQuickTextInput);
 
2078
    d->selectWordAtPos(d->m_cursor);
 
2079
}
 
2080
 
 
2081
/*!
 
2082
    \qmlproperty bool QtQuick2::TextInput::smooth
 
2083
 
 
2084
    This property holds whether the text is smoothly scaled or transformed.
 
2085
 
 
2086
    Smooth filtering gives better visual quality, but is slower.  If
 
2087
    the item is displayed at its natural size, this property has no visual or
 
2088
    performance effect.
 
2089
 
 
2090
    \note Generally scaling artifacts are only visible if the item is stationary on
 
2091
    the screen.  A common pattern when animating an item is to disable smooth
 
2092
    filtering at the beginning of the animation and reenable it at the conclusion.
 
2093
*/
 
2094
 
 
2095
/*!
 
2096
   \qmlproperty string QtQuick2::TextInput::passwordCharacter
 
2097
 
 
2098
   This is the character displayed when echoMode is set to Password or
 
2099
   PasswordEchoOnEdit. By default it is an asterisk.
 
2100
 
 
2101
   If this property is set to a string with more than one character,
 
2102
   the first character is used. If the string is empty, the value
 
2103
   is ignored and the property is not set.
 
2104
*/
 
2105
QString QQuickTextInput::passwordCharacter() const
 
2106
{
 
2107
    Q_D(const QQuickTextInput);
 
2108
    return QString(d->m_passwordCharacter);
 
2109
}
 
2110
 
 
2111
void QQuickTextInput::setPasswordCharacter(const QString &str)
 
2112
{
 
2113
    Q_D(QQuickTextInput);
 
2114
    if (str.length() < 1)
 
2115
        return;
 
2116
    d->m_passwordCharacter = str.constData()[0];
 
2117
    if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
 
2118
        d->updateDisplayText();
 
2119
    emit passwordCharacterChanged();
 
2120
}
 
2121
 
 
2122
/*!
 
2123
   \qmlproperty string QtQuick2::TextInput::displayText
 
2124
 
 
2125
   This is the text displayed in the TextInput.
 
2126
 
 
2127
   If \l echoMode is set to TextInput::Normal, this holds the
 
2128
   same value as the TextInput::text property. Otherwise,
 
2129
   this property holds the text visible to the user, while
 
2130
   the \l text property holds the actual entered text.
 
2131
*/
 
2132
QString QQuickTextInput::displayText() const
 
2133
{
 
2134
    Q_D(const QQuickTextInput);
 
2135
    return d->m_textLayout.text();
 
2136
}
 
2137
 
 
2138
/*!
 
2139
    \qmlproperty bool QtQuick2::TextInput::selectByMouse
 
2140
 
 
2141
    Defaults to false.
 
2142
 
 
2143
    If true, the user can use the mouse to select text in some
 
2144
    platform-specific way. Note that for some platforms this may
 
2145
    not be an appropriate interaction (eg. may conflict with how
 
2146
    the text needs to behave inside a Flickable.
 
2147
*/
 
2148
bool QQuickTextInput::selectByMouse() const
 
2149
{
 
2150
    Q_D(const QQuickTextInput);
 
2151
    return d->selectByMouse;
 
2152
}
 
2153
 
 
2154
void QQuickTextInput::setSelectByMouse(bool on)
 
2155
{
 
2156
    Q_D(QQuickTextInput);
 
2157
    if (d->selectByMouse != on) {
 
2158
        d->selectByMouse = on;
 
2159
        emit selectByMouseChanged(on);
 
2160
    }
 
2161
}
 
2162
 
 
2163
/*!
 
2164
    \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
 
2165
 
 
2166
    Specifies how text should be selected using a mouse.
 
2167
 
 
2168
    \list
 
2169
    \li TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
 
2170
    \li TextInput.SelectWords - The selection is updated with whole words.
 
2171
    \endlist
 
2172
 
 
2173
    This property only applies when \l selectByMouse is true.
 
2174
*/
 
2175
 
 
2176
QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
 
2177
{
 
2178
    Q_D(const QQuickTextInput);
 
2179
    return d->mouseSelectionMode;
 
2180
}
 
2181
 
 
2182
void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
 
2183
{
 
2184
    Q_D(QQuickTextInput);
 
2185
    if (d->mouseSelectionMode != mode) {
 
2186
        d->mouseSelectionMode = mode;
 
2187
        emit mouseSelectionModeChanged(mode);
 
2188
    }
 
2189
}
 
2190
 
 
2191
/*!
 
2192
    \qmlproperty bool QtQuick2::TextInput::persistentSelection
 
2193
 
 
2194
    Whether the TextInput should keep its selection when it loses active focus to another
 
2195
    item in the scene. By default this is set to false;
 
2196
*/
 
2197
 
 
2198
bool QQuickTextInput::persistentSelection() const
 
2199
{
 
2200
    Q_D(const QQuickTextInput);
 
2201
    return d->persistentSelection;
 
2202
}
 
2203
 
 
2204
void QQuickTextInput::setPersistentSelection(bool on)
 
2205
{
 
2206
    Q_D(QQuickTextInput);
 
2207
    if (d->persistentSelection == on)
 
2208
        return;
 
2209
    d->persistentSelection = on;
 
2210
    emit persistentSelectionChanged();
 
2211
}
 
2212
 
 
2213
/*!
 
2214
    \qmlproperty bool QtQuick2::TextInput::canPaste
 
2215
 
 
2216
    Returns true if the TextInput is writable and the content of the clipboard is
 
2217
    suitable for pasting into the TextInput.
 
2218
*/
 
2219
bool QQuickTextInput::canPaste() const
 
2220
{
 
2221
    Q_D(const QQuickTextInput);
 
2222
    if (!d->canPasteValid) {
 
2223
        if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
 
2224
            const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
 
2225
        const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
 
2226
    }
 
2227
    return d->canPaste;
 
2228
}
 
2229
 
 
2230
/*!
 
2231
    \qmlproperty bool QtQuick2::TextInput::canUndo
 
2232
 
 
2233
    Returns true if the TextInput is writable and there are previous operations
 
2234
    that can be undone.
 
2235
*/
 
2236
 
 
2237
bool QQuickTextInput::canUndo() const
 
2238
{
 
2239
    Q_D(const QQuickTextInput);
 
2240
    return d->canUndo;
 
2241
}
 
2242
 
 
2243
/*!
 
2244
    \qmlproperty bool QtQuick2::TextInput::canRedo
 
2245
 
 
2246
    Returns true if the TextInput is writable and there are \l {undo}{undone}
 
2247
    operations that can be redone.
 
2248
*/
 
2249
 
 
2250
bool QQuickTextInput::canRedo() const
 
2251
{
 
2252
    Q_D(const QQuickTextInput);
 
2253
    return d->canRedo;
 
2254
}
 
2255
 
 
2256
/*!
 
2257
    \qmlproperty real QtQuick2::TextInput::contentWidth
 
2258
 
 
2259
    Returns the width of the text, including the width past the width
 
2260
    which is covered due to insufficient wrapping if \l wrapMode is set.
 
2261
*/
 
2262
 
 
2263
qreal QQuickTextInput::contentWidth() const
 
2264
{
 
2265
    Q_D(const QQuickTextInput);
 
2266
    return d->boundingRect.width();
 
2267
}
 
2268
 
 
2269
/*!
 
2270
    \qmlproperty real QtQuick2::TextInput::contentHeight
 
2271
 
 
2272
    Returns the height of the text, including the height past the height
 
2273
    that is covered if the text does not fit within the set height.
 
2274
*/
 
2275
 
 
2276
qreal QQuickTextInput::contentHeight() const
 
2277
{
 
2278
    Q_D(const QQuickTextInput);
 
2279
    return d->boundingRect.height();
 
2280
}
 
2281
 
 
2282
void QQuickTextInput::moveCursorSelection(int position)
 
2283
{
 
2284
    Q_D(QQuickTextInput);
 
2285
    d->moveCursor(position, true);
 
2286
}
 
2287
 
 
2288
/*!
 
2289
    \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
 
2290
 
 
2291
    Moves the cursor to \a position and updates the selection according to the optional \a mode
 
2292
    parameter.  (To only move the cursor, set the \l cursorPosition property.)
 
2293
 
 
2294
    When this method is called it additionally sets either the
 
2295
    selectionStart or the selectionEnd (whichever was at the previous cursor position)
 
2296
    to the specified position. This allows you to easily extend and contract the selected
 
2297
    text range.
 
2298
 
 
2299
    The selection mode specifies whether the selection is updated on a per character or a per word
 
2300
    basis.  If not specified the selection mode will default to TextInput.SelectCharacters.
 
2301
 
 
2302
    \list
 
2303
    \li TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
 
2304
    the previous cursor position) to the specified position.
 
2305
    \li TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
 
2306
    words between the specified position and the previous cursor position.  Words partially in the
 
2307
    range are included.
 
2308
    \endlist
 
2309
 
 
2310
    For example, take this sequence of calls:
 
2311
 
 
2312
    \code
 
2313
        cursorPosition = 5
 
2314
        moveCursorSelection(9, TextInput.SelectCharacters)
 
2315
        moveCursorSelection(7, TextInput.SelectCharacters)
 
2316
    \endcode
 
2317
 
 
2318
    This moves the cursor to position 5, extend the selection end from 5 to 9
 
2319
    and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
 
2320
    selected (the 6th and 7th characters).
 
2321
 
 
2322
    The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
 
2323
    before or on position 5 and extend the selection end to a word boundary on or past position 9.
 
2324
*/
 
2325
void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
 
2326
{
 
2327
    Q_D(QQuickTextInput);
 
2328
 
 
2329
    if (mode == SelectCharacters) {
 
2330
        d->moveCursor(pos, true);
 
2331
    } else if (pos != d->m_cursor){
 
2332
        const int cursor = d->m_cursor;
 
2333
        int anchor;
 
2334
        if (!d->hasSelectedText())
 
2335
            anchor = d->m_cursor;
 
2336
        else if (d->selectionStart() == d->m_cursor)
 
2337
            anchor = d->selectionEnd();
 
2338
        else
 
2339
            anchor = d->selectionStart();
 
2340
 
 
2341
        if (anchor < pos || (anchor == pos && cursor < pos)) {
 
2342
            const QString text = this->text();
 
2343
            QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
 
2344
            finder.setPosition(anchor);
 
2345
 
 
2346
            const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
 
2347
            if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
 
2348
                    || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
 
2349
                finder.toPreviousBoundary();
 
2350
            }
 
2351
            anchor = finder.position() != -1 ? finder.position() : 0;
 
2352
 
 
2353
            finder.setPosition(pos);
 
2354
            if (pos > 0 && !finder.boundaryReasons())
 
2355
                finder.toNextBoundary();
 
2356
            const int cursor = finder.position() != -1 ? finder.position() : text.length();
 
2357
 
 
2358
            d->setSelection(anchor, cursor - anchor);
 
2359
        } else if (anchor > pos || (anchor == pos && cursor > pos)) {
 
2360
            const QString text = this->text();
 
2361
            QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
 
2362
            finder.setPosition(anchor);
 
2363
 
 
2364
            const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
 
2365
            if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
 
2366
                    || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
 
2367
                finder.toNextBoundary();
 
2368
            }
 
2369
 
 
2370
            anchor = finder.position() != -1 ? finder.position() : text.length();
 
2371
 
 
2372
            finder.setPosition(pos);
 
2373
            if (pos < text.length() && !finder.boundaryReasons())
 
2374
                 finder.toPreviousBoundary();
 
2375
            const int cursor = finder.position() != -1 ? finder.position() : 0;
 
2376
 
 
2377
            d->setSelection(anchor, cursor - anchor);
 
2378
        }
 
2379
    }
 
2380
}
 
2381
 
 
2382
/*!
 
2383
    \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
 
2384
 
 
2385
    Opens software input panels like virtual keyboards for typing, useful for
 
2386
    customizing when you want the input keyboard to be shown and hidden in
 
2387
    your application.
 
2388
 
 
2389
    By default the opening of input panels follows the platform style. Input panels are
 
2390
    always closed if no editor has active focus.
 
2391
 
 
2392
    You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
 
2393
    and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
 
2394
    the behavior you want.
 
2395
 
 
2396
    Only relevant on platforms, which provide virtual keyboards.
 
2397
 
 
2398
    \qml
 
2399
        import QtQuick 2.0
 
2400
        TextInput {
 
2401
            id: textInput
 
2402
            text: "Hello world!"
 
2403
            activeFocusOnPress: false
 
2404
            MouseArea {
 
2405
                anchors.fill: parent
 
2406
                onClicked: {
 
2407
                    if (!textInput.activeFocus) {
 
2408
                        textInput.forceActiveFocus()
 
2409
                        textInput.openSoftwareInputPanel();
 
2410
                    } else {
 
2411
                        textInput.focus = false;
 
2412
                    }
 
2413
                }
 
2414
                onPressAndHold: textInput.closeSoftwareInputPanel();
 
2415
            }
 
2416
        }
 
2417
    \endqml
 
2418
*/
 
2419
void QQuickTextInput::openSoftwareInputPanel()
 
2420
{
 
2421
    if (qGuiApp)
 
2422
        qGuiApp->inputMethod()->show();
 
2423
}
 
2424
 
 
2425
/*!
 
2426
    \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
 
2427
 
 
2428
    Closes a software input panel like a virtual keyboard shown on the screen, useful
 
2429
    for customizing when you want the input keyboard to be shown and hidden in
 
2430
    your application.
 
2431
 
 
2432
    By default the opening of input panels follows the platform style. Input panels are
 
2433
    always closed if no editor has active focus.
 
2434
 
 
2435
    You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
 
2436
    and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
 
2437
    the behavior you want.
 
2438
 
 
2439
    Only relevant on platforms, which provide virtual keyboards.
 
2440
 
 
2441
    \qml
 
2442
        import QtQuick 2.0
 
2443
        TextInput {
 
2444
            id: textInput
 
2445
            text: "Hello world!"
 
2446
            activeFocusOnPress: false
 
2447
            MouseArea {
 
2448
                anchors.fill: parent
 
2449
                onClicked: {
 
2450
                    if (!textInput.activeFocus) {
 
2451
                        textInput.forceActiveFocus();
 
2452
                        textInput.openSoftwareInputPanel();
 
2453
                    } else {
 
2454
                        textInput.focus = false;
 
2455
                    }
 
2456
                }
 
2457
                onPressAndHold: textInput.closeSoftwareInputPanel();
 
2458
            }
 
2459
        }
 
2460
    \endqml
 
2461
*/
 
2462
void QQuickTextInput::closeSoftwareInputPanel()
 
2463
{
 
2464
    if (qGuiApp)
 
2465
        qGuiApp->inputMethod()->hide();
 
2466
}
 
2467
 
 
2468
void QQuickTextInput::focusInEvent(QFocusEvent *event)
 
2469
{
 
2470
    Q_D(const QQuickTextInput);
 
2471
    if (d->focusOnPress && !d->m_readOnly)
 
2472
        openSoftwareInputPanel();
 
2473
    QQuickImplicitSizeItem::focusInEvent(event);
 
2474
}
 
2475
 
 
2476
void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
 
2477
{
 
2478
    Q_D(QQuickTextInput);
 
2479
    if (change == ItemActiveFocusHasChanged) {
 
2480
        bool hasFocus = value.boolValue;
 
2481
        setCursorVisible(hasFocus); // ### refactor:  && d->canvas && d->canvas->hasFocus()
 
2482
        if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
 
2483
            d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
 
2484
        }
 
2485
 
 
2486
        if (!hasFocus) {
 
2487
            if (!d->persistentSelection)
 
2488
                d->deselect();
 
2489
            disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
 
2490
                       this, SLOT(q_updateAlignment()));
 
2491
        } else {
 
2492
            q_updateAlignment();
 
2493
            connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
 
2494
                    this, SLOT(q_updateAlignment()));
 
2495
        }
 
2496
    }
 
2497
    QQuickItem::itemChange(change, value);
 
2498
}
 
2499
 
 
2500
/*!
 
2501
    \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
 
2502
 
 
2503
 
 
2504
    This property holds whether the TextInput has partial text input from an
 
2505
    input method.
 
2506
 
 
2507
    While it is composing an input method may rely on mouse or key events from
 
2508
    the TextInput to edit or commit the partial text.  This property can be
 
2509
    used to determine when to disable events handlers that may interfere with
 
2510
    the correct operation of an input method.
 
2511
*/
 
2512
bool QQuickTextInput::isInputMethodComposing() const
 
2513
{
 
2514
    Q_D(const QQuickTextInput);
 
2515
    return d->hasImState;
 
2516
}
 
2517
 
 
2518
void QQuickTextInputPrivate::init()
 
2519
{
 
2520
    Q_Q(QQuickTextInput);
 
2521
    q->setSmooth(smooth);
 
2522
    q->setAcceptedMouseButtons(Qt::LeftButton);
 
2523
    q->setFlag(QQuickItem::ItemAcceptsInputMethod);
 
2524
    q->setFlag(QQuickItem::ItemHasContents);
 
2525
#ifndef QT_NO_CLIPBOARD
 
2526
    q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
 
2527
            q, SLOT(q_canPasteChanged()));
 
2528
#endif // QT_NO_CLIPBOARD
 
2529
 
 
2530
    lastSelectionStart = 0;
 
2531
    lastSelectionEnd = 0;
 
2532
    determineHorizontalAlignment();
 
2533
 
 
2534
    if (!qmlDisableDistanceField()) {
 
2535
        QTextOption option = m_textLayout.textOption();
 
2536
        option.setUseDesignMetrics(true);
 
2537
        m_textLayout.setTextOption(option);
 
2538
    }
 
2539
}
 
2540
 
 
2541
void QQuickTextInput::updateCursorRectangle()
 
2542
{
 
2543
    Q_D(QQuickTextInput);
 
2544
    if (!isComponentComplete())
 
2545
        return;
 
2546
 
 
2547
    d->updateHorizontalScroll();
 
2548
    d->updateVerticalScroll();
 
2549
    d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
 
2550
    update();
 
2551
    emit cursorRectangleChanged();
 
2552
    if (d->cursorItem) {
 
2553
        QRectF r = cursorRectangle();
 
2554
        d->cursorItem->setPos(r.topLeft());
 
2555
        d->cursorItem->setHeight(r.height());
 
2556
    }
 
2557
    updateInputMethod(Qt::ImCursorRectangle);
 
2558
}
 
2559
 
 
2560
void QQuickTextInput::selectionChanged()
 
2561
{
 
2562
    Q_D(QQuickTextInput);
 
2563
    d->textLayoutDirty = true; //TODO: Only update rect in selection
 
2564
    d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
 
2565
    update();
 
2566
    emit selectedTextChanged();
 
2567
 
 
2568
    if (d->lastSelectionStart != d->selectionStart()) {
 
2569
        d->lastSelectionStart = d->selectionStart();
 
2570
        if (d->lastSelectionStart == -1)
 
2571
            d->lastSelectionStart = d->m_cursor;
 
2572
        emit selectionStartChanged();
 
2573
    }
 
2574
    if (d->lastSelectionEnd != d->selectionEnd()) {
 
2575
        d->lastSelectionEnd = d->selectionEnd();
 
2576
        if (d->lastSelectionEnd == -1)
 
2577
            d->lastSelectionEnd = d->m_cursor;
 
2578
        emit selectionEndChanged();
 
2579
    }
 
2580
}
 
2581
 
 
2582
void QQuickTextInputPrivate::showCursor()
 
2583
{
 
2584
    if (textNode != 0 && textNode->cursorNode() != 0)
 
2585
        textNode->cursorNode()->setColor(color);
 
2586
}
 
2587
 
 
2588
void QQuickTextInputPrivate::hideCursor()
 
2589
{
 
2590
    if (textNode != 0 && textNode->cursorNode() != 0)
 
2591
        textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
 
2592
}
 
2593
 
 
2594
QRectF QQuickTextInput::boundingRect() const
 
2595
{
 
2596
    Q_D(const QQuickTextInput);
 
2597
 
 
2598
    int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
 
2599
 
 
2600
    // Could include font max left/right bearings to either side of rectangle.
 
2601
    QRectF r = QQuickImplicitSizeItem::boundingRect();
 
2602
    r.setRight(r.right() + cursorWidth);
 
2603
    return r;
 
2604
}
 
2605
 
 
2606
void QQuickTextInput::q_canPasteChanged()
 
2607
{
 
2608
    Q_D(QQuickTextInput);
 
2609
    bool old = d->canPaste;
 
2610
#ifndef QT_NO_CLIPBOARD
 
2611
    if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
 
2612
        d->canPaste = !d->m_readOnly && mimeData->hasText();
 
2613
    else
 
2614
        d->canPaste = false;
 
2615
#endif
 
2616
 
 
2617
    bool changed = d->canPaste != old || !d->canPasteValid;
 
2618
    d->canPasteValid = true;
 
2619
    if (changed)
 
2620
        emit canPasteChanged();
 
2621
 
 
2622
}
 
2623
 
 
2624
void QQuickTextInput::q_updateAlignment()
 
2625
{
 
2626
    Q_D(QQuickTextInput);
 
2627
    if (d->determineHorizontalAlignment()) {
 
2628
        d->updateLayout();
 
2629
        updateCursorRectangle();
 
2630
    }
 
2631
}
 
2632
 
 
2633
// ### these should come from QStyleHints
 
2634
const int textCursorWidth = 1;
 
2635
const bool fullWidthSelection = true;
 
2636
 
 
2637
/*!
 
2638
    \internal
 
2639
 
 
2640
    Updates the display text based of the current edit text
 
2641
    If the text has changed will emit displayTextChanged()
 
2642
*/
 
2643
void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
 
2644
{
 
2645
    QString orig = m_textLayout.text();
 
2646
    QString str;
 
2647
    if (m_echoMode == QQuickTextInput::NoEcho)
 
2648
        str = QString::fromLatin1("");
 
2649
    else
 
2650
        str = m_text;
 
2651
 
 
2652
    if (m_echoMode == QQuickTextInput::Password) {
 
2653
         str.fill(m_passwordCharacter);
 
2654
        if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
 
2655
            int cursor = m_cursor - 1;
 
2656
            QChar uc = m_text.at(cursor);
 
2657
            str[cursor] = uc;
 
2658
            if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
 
2659
                // second half of a surrogate, check if we have the first half as well,
 
2660
                // if yes restore both at once
 
2661
                uc = m_text.at(cursor - 1);
 
2662
                if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
 
2663
                    str[cursor - 1] = uc;
 
2664
            }
 
2665
        }
 
2666
    } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
 
2667
        str.fill(m_passwordCharacter);
 
2668
    }
 
2669
 
 
2670
    // replace certain non-printable characters with spaces (to avoid
 
2671
    // drawing boxes when using fonts that don't have glyphs for such
 
2672
    // characters)
 
2673
    QChar* uc = str.data();
 
2674
    for (int i = 0; i < (int)str.length(); ++i) {
 
2675
        if ((uc[i] < 0x20 && uc[i] != 0x09)
 
2676
            || uc[i] == QChar::LineSeparator
 
2677
            || uc[i] == QChar::ParagraphSeparator
 
2678
            || uc[i] == QChar::ObjectReplacementCharacter)
 
2679
            uc[i] = QChar(0x0020);
 
2680
    }
 
2681
 
 
2682
    if (str != orig || forceUpdate) {
 
2683
        m_textLayout.setText(str);
 
2684
        updateLayout(); // polish?
 
2685
        emit q_func()->displayTextChanged();
 
2686
    }
 
2687
}
 
2688
 
 
2689
qreal QQuickTextInputPrivate::getImplicitWidth() const
 
2690
{
 
2691
    Q_Q(const QQuickTextInput);
 
2692
    if (!requireImplicitWidth) {
 
2693
        QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
 
2694
        d->requireImplicitWidth = true;
 
2695
 
 
2696
        if (q->isComponentComplete()) {
 
2697
            // One time cost, only incurred if implicitWidth is first requested after
 
2698
            // componentComplete.
 
2699
            QTextLayout layout(m_text);
 
2700
 
 
2701
            QTextOption option = m_textLayout.textOption();
 
2702
            option.setTextDirection(m_layoutDirection);
 
2703
            option.setFlags(QTextOption::IncludeTrailingSpaces);
 
2704
            option.setWrapMode(QTextOption::WrapMode(wrapMode));
 
2705
            option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
 
2706
            layout.setTextOption(option);
 
2707
            layout.setFont(font);
 
2708
            layout.setPreeditArea(m_textLayout.preeditAreaPosition(), m_textLayout.preeditAreaText());
 
2709
            layout.beginLayout();
 
2710
 
 
2711
            QTextLine line = layout.createLine();
 
2712
            line.setLineWidth(INT_MAX);
 
2713
            d->implicitWidth = qCeil(line.naturalTextWidth());
 
2714
 
 
2715
            layout.endLayout();
 
2716
        }
 
2717
    }
 
2718
    return implicitWidth;
 
2719
}
 
2720
 
 
2721
void QQuickTextInputPrivate::updateLayout()
 
2722
{
 
2723
    Q_Q(QQuickTextInput);
 
2724
 
 
2725
    if (!q->isComponentComplete())
 
2726
        return;
 
2727
 
 
2728
    const QRectF previousRect = boundingRect;
 
2729
 
 
2730
    QTextOption option = m_textLayout.textOption();
 
2731
    option.setTextDirection(layoutDirection());
 
2732
    option.setWrapMode(QTextOption::WrapMode(wrapMode));
 
2733
    option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
 
2734
    m_textLayout.setTextOption(option);
 
2735
    m_textLayout.setFont(font);
 
2736
 
 
2737
    boundingRect = QRectF();
 
2738
    m_textLayout.beginLayout();
 
2739
    QTextLine line = m_textLayout.createLine();
 
2740
    if (requireImplicitWidth) {
 
2741
        line.setLineWidth(INT_MAX);
 
2742
        const bool wasInLayout = inLayout;
 
2743
        inLayout = true;
 
2744
        q->setImplicitWidth(qCeil(line.naturalTextWidth()));
 
2745
        inLayout = wasInLayout;
 
2746
        if (inLayout)       // probably the result of a binding loop, but by letting it
 
2747
            return;         // get this far we'll get a warning to that effect.
 
2748
    }
 
2749
    qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
 
2750
    qreal height = 0;
 
2751
    do {
 
2752
        line.setLineWidth(lineWidth);
 
2753
        line.setPosition(QPointF(line.position().x(), height));
 
2754
        boundingRect = boundingRect.united(line.naturalTextRect());
 
2755
 
 
2756
        height += line.height();
 
2757
        line = m_textLayout.createLine();
 
2758
    } while (line.isValid());
 
2759
    m_textLayout.endLayout();
 
2760
 
 
2761
    option.setWrapMode(QTextOption::NoWrap);
 
2762
    m_textLayout.setTextOption(option);
 
2763
 
 
2764
    textLayoutDirty = true;
 
2765
 
 
2766
    updateType = UpdatePaintNode;
 
2767
    q->update();
 
2768
 
 
2769
    if (!requireImplicitWidth && !q->widthValid())
 
2770
        q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
 
2771
    else
 
2772
        q->setImplicitHeight(qCeil(boundingRect.height()));
 
2773
 
 
2774
    if (previousRect != boundingRect)
 
2775
        emit q->contentSizeChanged();
 
2776
}
 
2777
 
 
2778
#ifndef QT_NO_CLIPBOARD
 
2779
/*!
 
2780
    \internal
 
2781
 
 
2782
    Copies the currently selected text into the clipboard using the given
 
2783
    \a mode.
 
2784
 
 
2785
    \note If the echo mode is set to a mode other than Normal then copy
 
2786
    will not work.  This is to prevent using copy as a method of bypassing
 
2787
    password features of the line control.
 
2788
*/
 
2789
void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
 
2790
{
 
2791
    QString t = selectedText();
 
2792
    if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
 
2793
        QGuiApplication::clipboard()->setText(t, mode);
 
2794
    }
 
2795
}
 
2796
 
 
2797
/*!
 
2798
    \internal
 
2799
 
 
2800
    Inserts the text stored in the application clipboard into the line
 
2801
    control.
 
2802
 
 
2803
    \sa insert()
 
2804
*/
 
2805
void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
 
2806
{
 
2807
    QString clip = QGuiApplication::clipboard()->text(clipboardMode);
 
2808
    if (!clip.isEmpty() || hasSelectedText()) {
 
2809
        separate(); //make it a separate undo/redo command
 
2810
        insert(clip);
 
2811
        separate();
 
2812
    }
 
2813
}
 
2814
 
 
2815
#endif // !QT_NO_CLIPBOARD
 
2816
 
 
2817
/*!
 
2818
    \internal
 
2819
*/
 
2820
void QQuickTextInputPrivate::commitPreedit()
 
2821
{
 
2822
    Q_Q(QQuickTextInput);
 
2823
 
 
2824
    if (!hasImState)
 
2825
        return;
 
2826
 
 
2827
    qApp->inputMethod()->commit();
 
2828
 
 
2829
    if (!hasImState)
 
2830
        return;
 
2831
 
 
2832
    QInputMethodEvent ev;
 
2833
    QCoreApplication::sendEvent(q, &ev);
 
2834
}
 
2835
 
 
2836
void QQuickTextInputPrivate::cancelPreedit()
 
2837
{
 
2838
    Q_Q(QQuickTextInput);
 
2839
 
 
2840
    if (!hasImState)
 
2841
        return;
 
2842
 
 
2843
    qApp->inputMethod()->reset();
 
2844
 
 
2845
    QInputMethodEvent ev;
 
2846
    QCoreApplication::sendEvent(q, &ev);
 
2847
}
 
2848
 
 
2849
/*!
 
2850
    \internal
 
2851
 
 
2852
    Handles the behavior for the backspace key or function.
 
2853
    Removes the current selection if there is a selection, otherwise
 
2854
    removes the character prior to the cursor position.
 
2855
 
 
2856
    \sa del()
 
2857
*/
 
2858
void QQuickTextInputPrivate::backspace()
 
2859
{
 
2860
    int priorState = m_undoState;
 
2861
    if (hasSelectedText()) {
 
2862
        removeSelectedText();
 
2863
    } else if (m_cursor) {
 
2864
            --m_cursor;
 
2865
            if (m_maskData)
 
2866
                m_cursor = prevMaskBlank(m_cursor);
 
2867
            QChar uc = m_text.at(m_cursor);
 
2868
            if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
 
2869
                // second half of a surrogate, check if we have the first half as well,
 
2870
                // if yes delete both at once
 
2871
                uc = m_text.at(m_cursor - 1);
 
2872
                if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
 
2873
                    internalDelete(true);
 
2874
                    --m_cursor;
 
2875
                }
 
2876
            }
 
2877
            internalDelete(true);
 
2878
    }
 
2879
    finishChange(priorState);
 
2880
}
 
2881
 
 
2882
/*!
 
2883
    \internal
 
2884
 
 
2885
    Handles the behavior for the delete key or function.
 
2886
    Removes the current selection if there is a selection, otherwise
 
2887
    removes the character after the cursor position.
 
2888
 
 
2889
    \sa del()
 
2890
*/
 
2891
void QQuickTextInputPrivate::del()
 
2892
{
 
2893
    int priorState = m_undoState;
 
2894
    if (hasSelectedText()) {
 
2895
        removeSelectedText();
 
2896
    } else {
 
2897
        int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
 
2898
        while (n--)
 
2899
            internalDelete();
 
2900
    }
 
2901
    finishChange(priorState);
 
2902
}
 
2903
 
 
2904
/*!
 
2905
    \internal
 
2906
 
 
2907
    Inserts the given \a newText at the current cursor position.
 
2908
    If there is any selected text it is removed prior to insertion of
 
2909
    the new text.
 
2910
*/
 
2911
void QQuickTextInputPrivate::insert(const QString &newText)
 
2912
{
 
2913
    int priorState = m_undoState;
 
2914
    removeSelectedText();
 
2915
    internalInsert(newText);
 
2916
    finishChange(priorState);
 
2917
}
 
2918
 
 
2919
/*!
 
2920
    \internal
 
2921
 
 
2922
    Clears the line control text.
 
2923
*/
 
2924
void QQuickTextInputPrivate::clear()
 
2925
{
 
2926
    int priorState = m_undoState;
 
2927
    m_selstart = 0;
 
2928
    m_selend = m_text.length();
 
2929
    removeSelectedText();
 
2930
    separate();
 
2931
    finishChange(priorState, /*update*/false, /*edited*/false);
 
2932
}
 
2933
 
 
2934
/*!
 
2935
    \internal
 
2936
 
 
2937
    Sets \a length characters from the given \a start position as selected.
 
2938
    The given \a start position must be within the current text for
 
2939
    the line control.  If \a length characters cannot be selected, then
 
2940
    the selection will extend to the end of the current text.
 
2941
*/
 
2942
void QQuickTextInputPrivate::setSelection(int start, int length)
 
2943
{
 
2944
    Q_Q(QQuickTextInput);
 
2945
    commitPreedit();
 
2946
 
 
2947
    if (start < 0 || start > (int)m_text.length()){
 
2948
        qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
 
2949
        return;
 
2950
    }
 
2951
 
 
2952
    if (length > 0) {
 
2953
        if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
 
2954
            return;
 
2955
        m_selstart = start;
 
2956
        m_selend = qMin(start + length, (int)m_text.length());
 
2957
        m_cursor = m_selend;
 
2958
    } else if (length < 0){
 
2959
        if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
 
2960
            return;
 
2961
        m_selstart = qMax(start + length, 0);
 
2962
        m_selend = start;
 
2963
        m_cursor = m_selstart;
 
2964
    } else if (m_selstart != m_selend) {
 
2965
        m_selstart = 0;
 
2966
        m_selend = 0;
 
2967
        m_cursor = start;
 
2968
    } else {
 
2969
        m_cursor = start;
 
2970
        emitCursorPositionChanged();
 
2971
        return;
 
2972
    }
 
2973
    emit q->selectionChanged();
 
2974
    emitCursorPositionChanged();
 
2975
    q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
 
2976
                        | Qt::ImCursorPosition | Qt::ImCurrentSelection);
 
2977
}
 
2978
 
 
2979
/*!
 
2980
    \internal
 
2981
 
 
2982
    Sets the password echo editing to \a editing.  If password echo editing
 
2983
    is true, then the text of the password is displayed even if the echo
 
2984
    mode is set to QLineEdit::PasswordEchoOnEdit.  Password echoing editing
 
2985
    does not affect other echo modes.
 
2986
*/
 
2987
void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
 
2988
{
 
2989
    cancelPasswordEchoTimer();
 
2990
    m_passwordEchoEditing = editing;
 
2991
    updateDisplayText();
 
2992
}
 
2993
 
 
2994
/*!
 
2995
    \internal
 
2996
 
 
2997
    Fixes the current text so that it is valid given any set validators.
 
2998
 
 
2999
    Returns true if the text was changed.  Otherwise returns false.
 
3000
*/
 
3001
bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
 
3002
{
 
3003
#ifndef QT_NO_VALIDATOR
 
3004
    if (m_validator) {
 
3005
        QString textCopy = m_text;
 
3006
        int cursorCopy = m_cursor;
 
3007
        m_validator->fixup(textCopy);
 
3008
        if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
 
3009
            if (textCopy != m_text || cursorCopy != m_cursor)
 
3010
                internalSetText(textCopy, cursorCopy);
 
3011
            return true;
 
3012
        }
 
3013
    }
 
3014
#endif
 
3015
    return false;
 
3016
}
 
3017
 
 
3018
/*!
 
3019
    \internal
 
3020
 
 
3021
    Moves the cursor to the given position \a pos.   If \a mark is true will
 
3022
    adjust the currently selected text.
 
3023
*/
 
3024
void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
 
3025
{
 
3026
    Q_Q(QQuickTextInput);
 
3027
    commitPreedit();
 
3028
 
 
3029
    if (pos != m_cursor) {
 
3030
        separate();
 
3031
        if (m_maskData)
 
3032
            pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
 
3033
    }
 
3034
    if (mark) {
 
3035
        int anchor;
 
3036
        if (m_selend > m_selstart && m_cursor == m_selstart)
 
3037
            anchor = m_selend;
 
3038
        else if (m_selend > m_selstart && m_cursor == m_selend)
 
3039
            anchor = m_selstart;
 
3040
        else
 
3041
            anchor = m_cursor;
 
3042
        m_selstart = qMin(anchor, pos);
 
3043
        m_selend = qMax(anchor, pos);
 
3044
    } else {
 
3045
        internalDeselect();
 
3046
    }
 
3047
    m_cursor = pos;
 
3048
    if (mark || m_selDirty) {
 
3049
        m_selDirty = false;
 
3050
        emit q->selectionChanged();
 
3051
    }
 
3052
    emitCursorPositionChanged();
 
3053
    q->updateInputMethod();
 
3054
}
 
3055
 
 
3056
/*!
 
3057
    \internal
 
3058
 
 
3059
    Applies the given input method event \a event to the text of the line
 
3060
    control
 
3061
*/
 
3062
void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
 
3063
{
 
3064
    Q_Q(QQuickTextInput);
 
3065
 
 
3066
    int priorState = -1;
 
3067
    bool isGettingInput = !event->commitString().isEmpty()
 
3068
            || event->preeditString() != preeditAreaText()
 
3069
            || event->replacementLength() > 0;
 
3070
    bool cursorPositionChanged = false;
 
3071
    bool selectionChange = false;
 
3072
    m_preeditDirty = event->preeditString() != preeditAreaText();
 
3073
 
 
3074
    if (isGettingInput) {
 
3075
        // If any text is being input, remove selected text.
 
3076
        priorState = m_undoState;
 
3077
        if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
 
3078
            updatePasswordEchoEditing(true);
 
3079
            m_selstart = 0;
 
3080
            m_selend = m_text.length();
 
3081
        }
 
3082
        removeSelectedText();
 
3083
    }
 
3084
 
 
3085
    int c = m_cursor; // cursor position after insertion of commit string
 
3086
    if (event->replacementStart() <= 0)
 
3087
        c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
 
3088
 
 
3089
    m_cursor += event->replacementStart();
 
3090
    if (m_cursor < 0)
 
3091
        m_cursor = 0;
 
3092
 
 
3093
    // insert commit string
 
3094
    if (event->replacementLength()) {
 
3095
        m_selstart = m_cursor;
 
3096
        m_selend = m_selstart + event->replacementLength();
 
3097
        m_selend = qMin(m_selend, m_text.length());
 
3098
        removeSelectedText();
 
3099
    }
 
3100
    if (!event->commitString().isEmpty()) {
 
3101
        internalInsert(event->commitString());
 
3102
        cursorPositionChanged = true;
 
3103
    }
 
3104
 
 
3105
    m_cursor = qBound(0, c, m_text.length());
 
3106
 
 
3107
    for (int i = 0; i < event->attributes().size(); ++i) {
 
3108
        const QInputMethodEvent::Attribute &a = event->attributes().at(i);
 
3109
        if (a.type == QInputMethodEvent::Selection) {
 
3110
            m_cursor = qBound(0, a.start + a.length, m_text.length());
 
3111
            if (a.length) {
 
3112
                m_selstart = qMax(0, qMin(a.start, m_text.length()));
 
3113
                m_selend = m_cursor;
 
3114
                if (m_selend < m_selstart) {
 
3115
                    qSwap(m_selstart, m_selend);
 
3116
                }
 
3117
                selectionChange = true;
 
3118
            } else {
 
3119
                m_selstart = m_selend = 0;
 
3120
            }
 
3121
            cursorPositionChanged = true;
 
3122
        }
 
3123
    }
 
3124
#ifndef QT_NO_IM
 
3125
    m_textLayout.setPreeditArea(m_cursor, event->preeditString());
 
3126
#endif //QT_NO_IM
 
3127
    const int oldPreeditCursor = m_preeditCursor;
 
3128
    const bool oldCursorVisible = cursorVisible;
 
3129
    m_preeditCursor = event->preeditString().length();
 
3130
    hasImState = !event->preeditString().isEmpty();
 
3131
    cursorVisible = true;
 
3132
    QList<QTextLayout::FormatRange> formats;
 
3133
    for (int i = 0; i < event->attributes().size(); ++i) {
 
3134
        const QInputMethodEvent::Attribute &a = event->attributes().at(i);
 
3135
        if (a.type == QInputMethodEvent::Cursor) {
 
3136
            hasImState = true;
 
3137
            m_preeditCursor = a.start;
 
3138
            cursorVisible = a.length != 0;
 
3139
        } else if (a.type == QInputMethodEvent::TextFormat) {
 
3140
            hasImState = true;
 
3141
            QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
 
3142
            if (f.isValid()) {
 
3143
                QTextLayout::FormatRange o;
 
3144
                o.start = a.start + m_cursor;
 
3145
                o.length = a.length;
 
3146
                o.format = f;
 
3147
                formats.append(o);
 
3148
            }
 
3149
        }
 
3150
    }
 
3151
    m_textLayout.setAdditionalFormats(formats);
 
3152
 
 
3153
    updateDisplayText(/*force*/ true);
 
3154
    if (cursorPositionChanged) {
 
3155
        emitCursorPositionChanged();
 
3156
    } else if (m_preeditCursor != oldPreeditCursor) {
 
3157
        q->updateCursorRectangle();
 
3158
    }
 
3159
 
 
3160
    if (isGettingInput)
 
3161
        finishChange(priorState);
 
3162
 
 
3163
    if (cursorVisible != oldCursorVisible)
 
3164
        emit q->cursorVisibleChanged(cursorVisible);
 
3165
 
 
3166
    if (selectionChange) {
 
3167
        emit q->selectionChanged();
 
3168
        q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
 
3169
                            | Qt::ImCursorPosition | Qt::ImCurrentSelection);
 
3170
    }
 
3171
}
 
3172
 
 
3173
/*!
 
3174
    \internal
 
3175
 
 
3176
    Sets the selection to cover the word at the given cursor position.
 
3177
    The word boundaries are defined by the behavior of QTextLayout::SkipWords
 
3178
    cursor mode.
 
3179
*/
 
3180
void QQuickTextInputPrivate::selectWordAtPos(int cursor)
 
3181
{
 
3182
    int next = cursor + 1;
 
3183
    if (next > end())
 
3184
        --next;
 
3185
    int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
 
3186
    moveCursor(c, false);
 
3187
    // ## text layout should support end of words.
 
3188
    int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
 
3189
    while (end > cursor && m_text[end-1].isSpace())
 
3190
        --end;
 
3191
    moveCursor(end, true);
 
3192
}
 
3193
 
 
3194
/*!
 
3195
    \internal
 
3196
 
 
3197
    Completes a change to the line control text.  If the change is not valid
 
3198
    will undo the line control state back to the given \a validateFromState.
 
3199
 
 
3200
    If \a edited is true and the change is valid, will emit textEdited() in
 
3201
    addition to textChanged().  Otherwise only emits textChanged() on a valid
 
3202
    change.
 
3203
 
 
3204
    The \a update value is currently unused.
 
3205
*/
 
3206
bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
 
3207
{
 
3208
    Q_Q(QQuickTextInput);
 
3209
 
 
3210
    Q_UNUSED(update)
 
3211
    bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
 
3212
    bool alignmentChanged = false;
 
3213
 
 
3214
    if (m_textDirty) {
 
3215
        // do validation
 
3216
        bool wasValidInput = m_validInput;
 
3217
        bool wasAcceptable = m_acceptableInput;
 
3218
        m_validInput = true;
 
3219
        m_acceptableInput = true;
 
3220
#ifndef QT_NO_VALIDATOR
 
3221
        if (m_validator) {
 
3222
            QString textCopy = m_text;
 
3223
            int cursorCopy = m_cursor;
 
3224
            QValidator::State state = m_validator->validate(textCopy, cursorCopy);
 
3225
            m_validInput = state != QValidator::Invalid;
 
3226
            m_acceptableInput = state == QValidator::Acceptable;
 
3227
            if (m_validInput) {
 
3228
                if (m_text != textCopy) {
 
3229
                    internalSetText(textCopy, cursorCopy);
 
3230
                    return true;
 
3231
                }
 
3232
                m_cursor = cursorCopy;
 
3233
            }
 
3234
        }
 
3235
#endif
 
3236
        if (validateFromState >= 0 && wasValidInput && !m_validInput) {
 
3237
            if (m_transactions.count())
 
3238
                return false;
 
3239
            internalUndo(validateFromState);
 
3240
            m_history.resize(m_undoState);
 
3241
            m_validInput = true;
 
3242
            m_acceptableInput = wasAcceptable;
 
3243
            m_textDirty = false;
 
3244
        }
 
3245
 
 
3246
        if (m_textDirty) {
 
3247
            m_textDirty = false;
 
3248
            m_preeditDirty = false;
 
3249
            alignmentChanged = determineHorizontalAlignment();
 
3250
            emit q->textChanged();
 
3251
        }
 
3252
 
 
3253
        updateDisplayText(alignmentChanged);
 
3254
 
 
3255
        if (m_acceptableInput != wasAcceptable)
 
3256
            emit q->acceptableInputChanged();
 
3257
    }
 
3258
    if (m_preeditDirty) {
 
3259
        m_preeditDirty = false;
 
3260
        if (determineHorizontalAlignment()) {
 
3261
            alignmentChanged = true;
 
3262
            updateLayout();
 
3263
        }
 
3264
    }
 
3265
 
 
3266
    if (m_selDirty) {
 
3267
        m_selDirty = false;
 
3268
        emit q->selectionChanged();
 
3269
    }
 
3270
 
 
3271
    inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
 
3272
    if (inputMethodAttributesChanged)
 
3273
        q->updateInputMethod();
 
3274
    emitUndoRedoChanged();
 
3275
 
 
3276
    if (!emitCursorPositionChanged() && alignmentChanged)
 
3277
        q->updateCursorRectangle();
 
3278
 
 
3279
    return true;
 
3280
}
 
3281
 
 
3282
/*!
 
3283
    \internal
 
3284
 
 
3285
    An internal function for setting the text of the line control.
 
3286
*/
 
3287
void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
 
3288
{
 
3289
    Q_Q(QQuickTextInput);
 
3290
    internalDeselect();
 
3291
    QString oldText = m_text;
 
3292
    if (m_maskData) {
 
3293
        m_text = maskString(0, txt, true);
 
3294
        m_text += clearString(m_text.length(), m_maxLength - m_text.length());
 
3295
    } else {
 
3296
        m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
 
3297
    }
 
3298
    m_history.clear();
 
3299
    m_undoState = 0;
 
3300
    m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
 
3301
    m_textDirty = (oldText != m_text);
 
3302
 
 
3303
    bool changed = finishChange(-1, true, edited);
 
3304
#ifdef QT_NO_ACCESSIBILITY
 
3305
    Q_UNUSED(changed)
 
3306
#else
 
3307
    if (changed) {
 
3308
        QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
 
3309
        QAccessible::updateAccessibility(&ev);
 
3310
    }
 
3311
#endif
 
3312
}
 
3313
 
 
3314
 
 
3315
/*!
 
3316
    \internal
 
3317
 
 
3318
    Adds the given \a command to the undo history
 
3319
    of the line control.  Does not apply the command.
 
3320
*/
 
3321
void QQuickTextInputPrivate::addCommand(const Command &cmd)
 
3322
{
 
3323
    if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
 
3324
        m_history.resize(m_undoState + 2);
 
3325
        m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
 
3326
    } else {
 
3327
        m_history.resize(m_undoState + 1);
 
3328
    }
 
3329
    m_separator = false;
 
3330
    m_history[m_undoState++] = cmd;
 
3331
}
 
3332
 
 
3333
/*!
 
3334
    \internal
 
3335
 
 
3336
    Inserts the given string \a s into the line
 
3337
    control.
 
3338
 
 
3339
    Also adds the appropriate commands into the undo history.
 
3340
    This function does not call finishChange(), and may leave the text
 
3341
    in an invalid state.
 
3342
*/
 
3343
void QQuickTextInputPrivate::internalInsert(const QString &s)
 
3344
{
 
3345
    Q_Q(QQuickTextInput);
 
3346
    if (m_echoMode == QQuickTextInput::Password) {
 
3347
        int delay = qGuiApp->styleHints()->passwordMaskDelay();
 
3348
        if (delay > 0)
 
3349
            m_passwordEchoTimer.start(delay, q);
 
3350
    }
 
3351
    if (hasSelectedText())
 
3352
        addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
 
3353
    if (m_maskData) {
 
3354
        QString ms = maskString(m_cursor, s);
 
3355
        for (int i = 0; i < (int) ms.length(); ++i) {
 
3356
            addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
 
3357
            addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
 
3358
        }
 
3359
        m_text.replace(m_cursor, ms.length(), ms);
 
3360
        m_cursor += ms.length();
 
3361
        m_cursor = nextMaskBlank(m_cursor);
 
3362
        m_textDirty = true;
 
3363
    } else {
 
3364
        int remaining = m_maxLength - m_text.length();
 
3365
        if (remaining != 0) {
 
3366
            m_text.insert(m_cursor, s.left(remaining));
 
3367
            for (int i = 0; i < (int) s.left(remaining).length(); ++i)
 
3368
               addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
 
3369
            m_textDirty = true;
 
3370
        }
 
3371
    }
 
3372
}
 
3373
 
 
3374
/*!
 
3375
    \internal
 
3376
 
 
3377
    deletes a single character from the current text.  If \a wasBackspace,
 
3378
    the character prior to the cursor is removed.  Otherwise the character
 
3379
    after the cursor is removed.
 
3380
 
 
3381
    Also adds the appropriate commands into the undo history.
 
3382
    This function does not call finishChange(), and may leave the text
 
3383
    in an invalid state.
 
3384
*/
 
3385
void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
 
3386
{
 
3387
    if (m_cursor < (int) m_text.length()) {
 
3388
        cancelPasswordEchoTimer();
 
3389
        if (hasSelectedText())
 
3390
            addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
 
3391
        addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
 
3392
                   m_cursor, m_text.at(m_cursor), -1, -1));
 
3393
        if (m_maskData) {
 
3394
            m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
 
3395
            addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
 
3396
        } else {
 
3397
            m_text.remove(m_cursor, 1);
 
3398
        }
 
3399
        m_textDirty = true;
 
3400
    }
 
3401
}
 
3402
 
 
3403
/*!
 
3404
    \internal
 
3405
 
 
3406
    removes the currently selected text from the line control.
 
3407
 
 
3408
    Also adds the appropriate commands into the undo history.
 
3409
    This function does not call finishChange(), and may leave the text
 
3410
    in an invalid state.
 
3411
*/
 
3412
void QQuickTextInputPrivate::removeSelectedText()
 
3413
{
 
3414
    if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
 
3415
        cancelPasswordEchoTimer();
 
3416
        separate();
 
3417
        int i ;
 
3418
        addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
 
3419
        if (m_selstart <= m_cursor && m_cursor < m_selend) {
 
3420
            // cursor is within the selection. Split up the commands
 
3421
            // to be able to restore the correct cursor position
 
3422
            for (i = m_cursor; i >= m_selstart; --i)
 
3423
                addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
 
3424
            for (i = m_selend - 1; i > m_cursor; --i)
 
3425
                addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
 
3426
        } else {
 
3427
            for (i = m_selend-1; i >= m_selstart; --i)
 
3428
                addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
 
3429
        }
 
3430
        if (m_maskData) {
 
3431
            m_text.replace(m_selstart, m_selend - m_selstart,  clearString(m_selstart, m_selend - m_selstart));
 
3432
            for (int i = 0; i < m_selend - m_selstart; ++i)
 
3433
                addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
 
3434
        } else {
 
3435
            m_text.remove(m_selstart, m_selend - m_selstart);
 
3436
        }
 
3437
        if (m_cursor > m_selstart)
 
3438
            m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
 
3439
        internalDeselect();
 
3440
        m_textDirty = true;
 
3441
    }
 
3442
}
 
3443
 
 
3444
/*!
 
3445
    \internal
 
3446
 
 
3447
    Parses the input mask specified by \a maskFields to generate
 
3448
    the mask data used to handle input masks.
 
3449
*/
 
3450
void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
 
3451
{
 
3452
    int delimiter = maskFields.indexOf(QLatin1Char(';'));
 
3453
    if (maskFields.isEmpty() || delimiter == 0) {
 
3454
        if (m_maskData) {
 
3455
            delete [] m_maskData;
 
3456
            m_maskData = 0;
 
3457
            m_maxLength = 32767;
 
3458
            internalSetText(QString());
 
3459
        }
 
3460
        return;
 
3461
    }
 
3462
 
 
3463
    if (delimiter == -1) {
 
3464
        m_blank = QLatin1Char(' ');
 
3465
        m_inputMask = maskFields;
 
3466
    } else {
 
3467
        m_inputMask = maskFields.left(delimiter);
 
3468
        m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
 
3469
    }
 
3470
 
 
3471
    // calculate m_maxLength / m_maskData length
 
3472
    m_maxLength = 0;
 
3473
    QChar c = 0;
 
3474
    for (int i=0; i<m_inputMask.length(); i++) {
 
3475
        c = m_inputMask.at(i);
 
3476
        if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
 
3477
            m_maxLength++;
 
3478
            continue;
 
3479
        }
 
3480
        if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
 
3481
             c != QLatin1Char('<') && c != QLatin1Char('>') &&
 
3482
             c != QLatin1Char('{') && c != QLatin1Char('}') &&
 
3483
             c != QLatin1Char('[') && c != QLatin1Char(']'))
 
3484
            m_maxLength++;
 
3485
    }
 
3486
 
 
3487
    delete [] m_maskData;
 
3488
    m_maskData = new MaskInputData[m_maxLength];
 
3489
 
 
3490
    MaskInputData::Casemode m = MaskInputData::NoCaseMode;
 
3491
    c = 0;
 
3492
    bool s;
 
3493
    bool escape = false;
 
3494
    int index = 0;
 
3495
    for (int i = 0; i < m_inputMask.length(); i++) {
 
3496
        c = m_inputMask.at(i);
 
3497
        if (escape) {
 
3498
            s = true;
 
3499
            m_maskData[index].maskChar = c;
 
3500
            m_maskData[index].separator = s;
 
3501
            m_maskData[index].caseMode = m;
 
3502
            index++;
 
3503
            escape = false;
 
3504
        } else if (c == QLatin1Char('<')) {
 
3505
                m = MaskInputData::Lower;
 
3506
        } else if (c == QLatin1Char('>')) {
 
3507
            m = MaskInputData::Upper;
 
3508
        } else if (c == QLatin1Char('!')) {
 
3509
            m = MaskInputData::NoCaseMode;
 
3510
        } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
 
3511
            switch (c.unicode()) {
 
3512
            case 'A':
 
3513
            case 'a':
 
3514
            case 'N':
 
3515
            case 'n':
 
3516
            case 'X':
 
3517
            case 'x':
 
3518
            case '9':
 
3519
            case '0':
 
3520
            case 'D':
 
3521
            case 'd':
 
3522
            case '#':
 
3523
            case 'H':
 
3524
            case 'h':
 
3525
            case 'B':
 
3526
            case 'b':
 
3527
                s = false;
 
3528
                break;
 
3529
            case '\\':
 
3530
                escape = true;
 
3531
            default:
 
3532
                s = true;
 
3533
                break;
 
3534
            }
 
3535
 
 
3536
            if (!escape) {
 
3537
                m_maskData[index].maskChar = c;
 
3538
                m_maskData[index].separator = s;
 
3539
                m_maskData[index].caseMode = m;
 
3540
                index++;
 
3541
            }
 
3542
        }
 
3543
    }
 
3544
    internalSetText(m_text);
 
3545
}
 
3546
 
 
3547
 
 
3548
/*!
 
3549
    \internal
 
3550
 
 
3551
    checks if the key is valid compared to the inputMask
 
3552
*/
 
3553
bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
 
3554
{
 
3555
    switch (mask.unicode()) {
 
3556
    case 'A':
 
3557
        if (key.isLetter())
 
3558
            return true;
 
3559
        break;
 
3560
    case 'a':
 
3561
        if (key.isLetter() || key == m_blank)
 
3562
            return true;
 
3563
        break;
 
3564
    case 'N':
 
3565
        if (key.isLetterOrNumber())
 
3566
            return true;
 
3567
        break;
 
3568
    case 'n':
 
3569
        if (key.isLetterOrNumber() || key == m_blank)
 
3570
            return true;
 
3571
        break;
 
3572
    case 'X':
 
3573
        if (key.isPrint())
 
3574
            return true;
 
3575
        break;
 
3576
    case 'x':
 
3577
        if (key.isPrint() || key == m_blank)
 
3578
            return true;
 
3579
        break;
 
3580
    case '9':
 
3581
        if (key.isNumber())
 
3582
            return true;
 
3583
        break;
 
3584
    case '0':
 
3585
        if (key.isNumber() || key == m_blank)
 
3586
            return true;
 
3587
        break;
 
3588
    case 'D':
 
3589
        if (key.isNumber() && key.digitValue() > 0)
 
3590
            return true;
 
3591
        break;
 
3592
    case 'd':
 
3593
        if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
 
3594
            return true;
 
3595
        break;
 
3596
    case '#':
 
3597
        if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
 
3598
            return true;
 
3599
        break;
 
3600
    case 'B':
 
3601
        if (key == QLatin1Char('0') || key == QLatin1Char('1'))
 
3602
            return true;
 
3603
        break;
 
3604
    case 'b':
 
3605
        if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
 
3606
            return true;
 
3607
        break;
 
3608
    case 'H':
 
3609
        if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
 
3610
            return true;
 
3611
        break;
 
3612
    case 'h':
 
3613
        if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
 
3614
            return true;
 
3615
        break;
 
3616
    default:
 
3617
        break;
 
3618
    }
 
3619
    return false;
 
3620
}
 
3621
 
 
3622
/*!
 
3623
    \internal
 
3624
 
 
3625
    Returns true if the given text \a str is valid for any
 
3626
    validator or input mask set for the line control.
 
3627
 
 
3628
    Otherwise returns false
 
3629
*/
 
3630
QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
 
3631
{
 
3632
#ifndef QT_NO_VALIDATOR
 
3633
    QString textCopy = str;
 
3634
    int cursorCopy = m_cursor;
 
3635
    if (m_validator) {
 
3636
        QValidator::State state = m_validator->validate(textCopy, cursorCopy);
 
3637
        if (state != QValidator::Acceptable)
 
3638
            return ValidatorState(state);
 
3639
    }
 
3640
#endif
 
3641
 
 
3642
    if (!m_maskData)
 
3643
        return AcceptableInput;
 
3644
 
 
3645
    if (str.length() != m_maxLength)
 
3646
        return InvalidInput;
 
3647
 
 
3648
    for (int i=0; i < m_maxLength; ++i) {
 
3649
        if (m_maskData[i].separator) {
 
3650
            if (str.at(i) != m_maskData[i].maskChar)
 
3651
                return InvalidInput;
 
3652
        } else {
 
3653
            if (!isValidInput(str.at(i), m_maskData[i].maskChar))
 
3654
                return InvalidInput;
 
3655
        }
 
3656
    }
 
3657
    return AcceptableInput;
 
3658
}
 
3659
 
 
3660
/*!
 
3661
    \internal
 
3662
 
 
3663
    Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
 
3664
    specifies from where characters should be gotten when a separator is met in \a str - true means
 
3665
    that blanks will be used, false that previous input is used.
 
3666
    Calling this when no inputMask is set is undefined.
 
3667
*/
 
3668
QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
 
3669
{
 
3670
    if (pos >= (uint)m_maxLength)
 
3671
        return QString::fromLatin1("");
 
3672
 
 
3673
    QString fill;
 
3674
    fill = clear ? clearString(0, m_maxLength) : m_text;
 
3675
 
 
3676
    int strIndex = 0;
 
3677
    QString s = QString::fromLatin1("");
 
3678
    int i = pos;
 
3679
    while (i < m_maxLength) {
 
3680
        if (strIndex < str.length()) {
 
3681
            if (m_maskData[i].separator) {
 
3682
                s += m_maskData[i].maskChar;
 
3683
                if (str[(int)strIndex] == m_maskData[i].maskChar)
 
3684
                    strIndex++;
 
3685
                ++i;
 
3686
            } else {
 
3687
                if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
 
3688
                    switch (m_maskData[i].caseMode) {
 
3689
                    case MaskInputData::Upper:
 
3690
                        s += str[(int)strIndex].toUpper();
 
3691
                        break;
 
3692
                    case MaskInputData::Lower:
 
3693
                        s += str[(int)strIndex].toLower();
 
3694
                        break;
 
3695
                    default:
 
3696
                        s += str[(int)strIndex];
 
3697
                    }
 
3698
                    ++i;
 
3699
                } else {
 
3700
                    // search for separator first
 
3701
                    int n = findInMask(i, true, true, str[(int)strIndex]);
 
3702
                    if (n != -1) {
 
3703
                        if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
 
3704
                            s += fill.mid(i, n-i+1);
 
3705
                            i = n + 1; // update i to find + 1
 
3706
                        }
 
3707
                    } else {
 
3708
                        // search for valid m_blank if not
 
3709
                        n = findInMask(i, true, false, str[(int)strIndex]);
 
3710
                        if (n != -1) {
 
3711
                            s += fill.mid(i, n-i);
 
3712
                            switch (m_maskData[n].caseMode) {
 
3713
                            case MaskInputData::Upper:
 
3714
                                s += str[(int)strIndex].toUpper();
 
3715
                                break;
 
3716
                            case MaskInputData::Lower:
 
3717
                                s += str[(int)strIndex].toLower();
 
3718
                                break;
 
3719
                            default:
 
3720
                                s += str[(int)strIndex];
 
3721
                            }
 
3722
                            i = n + 1; // updates i to find + 1
 
3723
                        }
 
3724
                    }
 
3725
                }
 
3726
                ++strIndex;
 
3727
            }
 
3728
        } else
 
3729
            break;
 
3730
    }
 
3731
 
 
3732
    return s;
 
3733
}
 
3734
 
 
3735
 
 
3736
 
 
3737
/*!
 
3738
    \internal
 
3739
 
 
3740
    Returns a "cleared" string with only separators and blank chars.
 
3741
    Calling this when no inputMask is set is undefined.
 
3742
*/
 
3743
QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
 
3744
{
 
3745
    if (pos >= (uint)m_maxLength)
 
3746
        return QString();
 
3747
 
 
3748
    QString s;
 
3749
    int end = qMin((uint)m_maxLength, pos + len);
 
3750
    for (int i = pos; i < end; ++i)
 
3751
        if (m_maskData[i].separator)
 
3752
            s += m_maskData[i].maskChar;
 
3753
        else
 
3754
            s += m_blank;
 
3755
 
 
3756
    return s;
 
3757
}
 
3758
 
 
3759
/*!
 
3760
    \internal
 
3761
 
 
3762
    Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
 
3763
    separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
 
3764
*/
 
3765
QString QQuickTextInputPrivate::stripString(const QString &str) const
 
3766
{
 
3767
    if (!m_maskData)
 
3768
        return str;
 
3769
 
 
3770
    QString s;
 
3771
    int end = qMin(m_maxLength, (int)str.length());
 
3772
    for (int i = 0; i < end; ++i) {
 
3773
        if (m_maskData[i].separator)
 
3774
            s += m_maskData[i].maskChar;
 
3775
        else if (str[i] != m_blank)
 
3776
            s += str[i];
 
3777
    }
 
3778
 
 
3779
    return s;
 
3780
}
 
3781
 
 
3782
/*!
 
3783
    \internal
 
3784
    searches forward/backward in m_maskData for either a separator or a m_blank
 
3785
*/
 
3786
int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
 
3787
{
 
3788
    if (pos >= m_maxLength || pos < 0)
 
3789
        return -1;
 
3790
 
 
3791
    int end = forward ? m_maxLength : -1;
 
3792
    int step = forward ? 1 : -1;
 
3793
    int i = pos;
 
3794
 
 
3795
    while (i != end) {
 
3796
        if (findSeparator) {
 
3797
            if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
 
3798
                return i;
 
3799
        } else {
 
3800
            if (!m_maskData[i].separator) {
 
3801
                if (searchChar.isNull())
 
3802
                    return i;
 
3803
                else if (isValidInput(searchChar, m_maskData[i].maskChar))
 
3804
                    return i;
 
3805
            }
 
3806
        }
 
3807
        i += step;
 
3808
    }
 
3809
    return -1;
 
3810
}
 
3811
 
 
3812
void QQuickTextInputPrivate::internalUndo(int until)
 
3813
{
 
3814
    if (!isUndoAvailable())
 
3815
        return;
 
3816
    cancelPasswordEchoTimer();
 
3817
    internalDeselect();
 
3818
    while (m_undoState && m_undoState > until) {
 
3819
        Command& cmd = m_history[--m_undoState];
 
3820
        switch (cmd.type) {
 
3821
        case Insert:
 
3822
            m_text.remove(cmd.pos, 1);
 
3823
            m_cursor = cmd.pos;
 
3824
            break;
 
3825
        case SetSelection:
 
3826
            m_selstart = cmd.selStart;
 
3827
            m_selend = cmd.selEnd;
 
3828
            m_cursor = cmd.pos;
 
3829
            break;
 
3830
        case Remove:
 
3831
        case RemoveSelection:
 
3832
            m_text.insert(cmd.pos, cmd.uc);
 
3833
            m_cursor = cmd.pos + 1;
 
3834
            break;
 
3835
        case Delete:
 
3836
        case DeleteSelection:
 
3837
            m_text.insert(cmd.pos, cmd.uc);
 
3838
            m_cursor = cmd.pos;
 
3839
            break;
 
3840
        case Separator:
 
3841
            continue;
 
3842
        }
 
3843
        if (until < 0 && m_undoState) {
 
3844
            Command& next = m_history[m_undoState-1];
 
3845
            if (next.type != cmd.type && next.type < RemoveSelection
 
3846
                 && (cmd.type < RemoveSelection || next.type == Separator))
 
3847
                break;
 
3848
        }
 
3849
    }
 
3850
    m_textDirty = true;
 
3851
}
 
3852
 
 
3853
void QQuickTextInputPrivate::internalRedo()
 
3854
{
 
3855
    if (!isRedoAvailable())
 
3856
        return;
 
3857
    internalDeselect();
 
3858
    while (m_undoState < (int)m_history.size()) {
 
3859
        Command& cmd = m_history[m_undoState++];
 
3860
        switch (cmd.type) {
 
3861
        case Insert:
 
3862
            m_text.insert(cmd.pos, cmd.uc);
 
3863
            m_cursor = cmd.pos + 1;
 
3864
            break;
 
3865
        case SetSelection:
 
3866
            m_selstart = cmd.selStart;
 
3867
            m_selend = cmd.selEnd;
 
3868
            m_cursor = cmd.pos;
 
3869
            break;
 
3870
        case Remove:
 
3871
        case Delete:
 
3872
        case RemoveSelection:
 
3873
        case DeleteSelection:
 
3874
            m_text.remove(cmd.pos, 1);
 
3875
            m_selstart = cmd.selStart;
 
3876
            m_selend = cmd.selEnd;
 
3877
            m_cursor = cmd.pos;
 
3878
            break;
 
3879
        case Separator:
 
3880
            m_selstart = cmd.selStart;
 
3881
            m_selend = cmd.selEnd;
 
3882
            m_cursor = cmd.pos;
 
3883
            break;
 
3884
        }
 
3885
        if (m_undoState < (int)m_history.size()) {
 
3886
            Command& next = m_history[m_undoState];
 
3887
            if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
 
3888
                 && (next.type < RemoveSelection || cmd.type == Separator))
 
3889
                break;
 
3890
        }
 
3891
    }
 
3892
    m_textDirty = true;
 
3893
}
 
3894
 
 
3895
void QQuickTextInputPrivate::emitUndoRedoChanged()
 
3896
{
 
3897
    Q_Q(QQuickTextInput);
 
3898
    const bool previousUndo = canUndo;
 
3899
    const bool previousRedo = canRedo;
 
3900
 
 
3901
    canUndo = isUndoAvailable();
 
3902
    canRedo = isRedoAvailable();
 
3903
 
 
3904
    if (previousUndo != canUndo)
 
3905
        emit q->canUndoChanged();
 
3906
    if (previousRedo != canRedo)
 
3907
        emit q->canRedoChanged();
 
3908
}
 
3909
 
 
3910
/*!
 
3911
    \internal
 
3912
 
 
3913
    If the current cursor position differs from the last emitted cursor
 
3914
    position, emits cursorPositionChanged().
 
3915
*/
 
3916
bool QQuickTextInputPrivate::emitCursorPositionChanged()
 
3917
{
 
3918
    Q_Q(QQuickTextInput);
 
3919
    if (m_cursor != m_lastCursorPos) {
 
3920
        m_lastCursorPos = m_cursor;
 
3921
 
 
3922
        q->updateCursorRectangle();
 
3923
        emit q->cursorPositionChanged();
 
3924
 
 
3925
        if (!hasSelectedText()) {
 
3926
            if (lastSelectionStart != m_cursor) {
 
3927
                lastSelectionStart = m_cursor;
 
3928
                emit q->selectionStartChanged();
 
3929
            }
 
3930
            if (lastSelectionEnd != m_cursor) {
 
3931
                lastSelectionEnd = m_cursor;
 
3932
                emit q->selectionEndChanged();
 
3933
            }
 
3934
        }
 
3935
 
 
3936
#ifndef QT_NO_ACCESSIBILITY
 
3937
        QAccessibleTextCursorEvent ev(q, m_cursor);
 
3938
        QAccessible::updateAccessibility(&ev);
 
3939
#endif
 
3940
 
 
3941
        return true;
 
3942
    }
 
3943
    return false;
 
3944
}
 
3945
 
 
3946
 
 
3947
void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
 
3948
{
 
3949
    Q_Q(QQuickTextInput);
 
3950
    if (msec == m_blinkPeriod)
 
3951
        return;
 
3952
    if (m_blinkTimer) {
 
3953
        q->killTimer(m_blinkTimer);
 
3954
    }
 
3955
    if (msec) {
 
3956
        m_blinkTimer = q->startTimer(msec / 2);
 
3957
        m_blinkStatus = 1;
 
3958
    } else {
 
3959
        m_blinkTimer = 0;
 
3960
        if (m_blinkStatus == 1) {
 
3961
            updateType = UpdatePaintNode;
 
3962
            q->update();
 
3963
        }
 
3964
    }
 
3965
    m_blinkPeriod = msec;
 
3966
}
 
3967
 
 
3968
void QQuickTextInput::timerEvent(QTimerEvent *event)
 
3969
{
 
3970
    Q_D(QQuickTextInput);
 
3971
    if (event->timerId() == d->m_blinkTimer) {
 
3972
        d->m_blinkStatus = !d->m_blinkStatus;
 
3973
        d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
 
3974
        update();
 
3975
    } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
 
3976
        d->m_passwordEchoTimer.stop();
 
3977
        d->updateDisplayText();
 
3978
    }
 
3979
}
 
3980
 
 
3981
void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
 
3982
{
 
3983
    Q_Q(QQuickTextInput);
 
3984
    bool inlineCompletionAccepted = false;
 
3985
 
 
3986
    if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
 
3987
        if (hasAcceptableInput(m_text) || fixup()) {
 
3988
            emit q->accepted();
 
3989
        }
 
3990
        if (inlineCompletionAccepted)
 
3991
            event->accept();
 
3992
        else
 
3993
            event->ignore();
 
3994
        return;
 
3995
    }
 
3996
 
 
3997
    if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
 
3998
        && !m_passwordEchoEditing
 
3999
        && !m_readOnly
 
4000
        && !event->text().isEmpty()
 
4001
        && !(event->modifiers() & Qt::ControlModifier)) {
 
4002
        // Clear the edit and reset to normal echo mode while editing; the
 
4003
        // echo mode switches back when the edit loses focus
 
4004
        // ### resets current content.  dubious code; you can
 
4005
        // navigate with keys up, down, back, and select(?), but if you press
 
4006
        // "left" or "right" it clears?
 
4007
        updatePasswordEchoEditing(true);
 
4008
        clear();
 
4009
    }
 
4010
 
 
4011
    bool unknown = false;
 
4012
    bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
 
4013
 
 
4014
    if (false) {
 
4015
    }
 
4016
#ifndef QT_NO_SHORTCUT
 
4017
    else if (event == QKeySequence::Undo) {
 
4018
        q->undo();
 
4019
    }
 
4020
    else if (event == QKeySequence::Redo) {
 
4021
        q->redo();
 
4022
    }
 
4023
    else if (event == QKeySequence::SelectAll) {
 
4024
        selectAll();
 
4025
    }
 
4026
#ifndef QT_NO_CLIPBOARD
 
4027
    else if (event == QKeySequence::Copy) {
 
4028
        copy();
 
4029
    }
 
4030
    else if (event == QKeySequence::Paste) {
 
4031
        if (!m_readOnly) {
 
4032
            QClipboard::Mode mode = QClipboard::Clipboard;
 
4033
            paste(mode);
 
4034
        }
 
4035
    }
 
4036
    else if (event == QKeySequence::Cut) {
 
4037
        if (!m_readOnly) {
 
4038
            copy();
 
4039
            del();
 
4040
        }
 
4041
    }
 
4042
    else if (event == QKeySequence::DeleteEndOfLine) {
 
4043
        if (!m_readOnly) {
 
4044
            setSelection(m_cursor, end());
 
4045
            copy();
 
4046
            del();
 
4047
        }
 
4048
    }
 
4049
#endif //QT_NO_CLIPBOARD
 
4050
    else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
 
4051
        home(0);
 
4052
    }
 
4053
    else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
 
4054
        end(0);
 
4055
    }
 
4056
    else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
 
4057
        home(1);
 
4058
    }
 
4059
    else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
 
4060
        end(1);
 
4061
    }
 
4062
    else if (event == QKeySequence::MoveToNextChar) {
 
4063
        if (hasSelectedText()) {
 
4064
            moveCursor(selectionEnd(), false);
 
4065
        } else {
 
4066
            cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
 
4067
        }
 
4068
    }
 
4069
    else if (event == QKeySequence::SelectNextChar) {
 
4070
        cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
 
4071
    }
 
4072
    else if (event == QKeySequence::MoveToPreviousChar) {
 
4073
        if (hasSelectedText()) {
 
4074
            moveCursor(selectionStart(), false);
 
4075
        } else {
 
4076
            cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
 
4077
        }
 
4078
    }
 
4079
    else if (event == QKeySequence::SelectPreviousChar) {
 
4080
        cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
 
4081
    }
 
4082
    else if (event == QKeySequence::MoveToNextWord) {
 
4083
        if (m_echoMode == QQuickTextInput::Normal)
 
4084
            layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
 
4085
        else
 
4086
            layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
 
4087
    }
 
4088
    else if (event == QKeySequence::MoveToPreviousWord) {
 
4089
        if (m_echoMode == QQuickTextInput::Normal)
 
4090
            layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
 
4091
        else if (!m_readOnly) {
 
4092
            layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
 
4093
        }
 
4094
    }
 
4095
    else if (event == QKeySequence::SelectNextWord) {
 
4096
        if (m_echoMode == QQuickTextInput::Normal)
 
4097
            layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
 
4098
        else
 
4099
            layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
 
4100
    }
 
4101
    else if (event == QKeySequence::SelectPreviousWord) {
 
4102
        if (m_echoMode == QQuickTextInput::Normal)
 
4103
            layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
 
4104
        else
 
4105
            layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
 
4106
    }
 
4107
    else if (event == QKeySequence::Delete) {
 
4108
        if (!m_readOnly)
 
4109
            del();
 
4110
    }
 
4111
    else if (event == QKeySequence::DeleteEndOfWord) {
 
4112
        if (!m_readOnly) {
 
4113
            cursorWordForward(true);
 
4114
            del();
 
4115
        }
 
4116
    }
 
4117
    else if (event == QKeySequence::DeleteStartOfWord) {
 
4118
        if (!m_readOnly) {
 
4119
            cursorWordBackward(true);
 
4120
            del();
 
4121
        }
 
4122
    }
 
4123
#endif // QT_NO_SHORTCUT
 
4124
    else {
 
4125
        bool handled = false;
 
4126
        if (event->modifiers() & Qt::ControlModifier) {
 
4127
            switch (event->key()) {
 
4128
            case Qt::Key_Backspace:
 
4129
                if (!m_readOnly) {
 
4130
                    cursorWordBackward(true);
 
4131
                    del();
 
4132
                }
 
4133
                break;
 
4134
            default:
 
4135
                if (!handled)
 
4136
                    unknown = true;
 
4137
            }
 
4138
        } else { // ### check for *no* modifier
 
4139
            switch (event->key()) {
 
4140
            case Qt::Key_Backspace:
 
4141
                if (!m_readOnly) {
 
4142
                    backspace();
 
4143
                }
 
4144
                break;
 
4145
            default:
 
4146
                if (!handled)
 
4147
                    unknown = true;
 
4148
            }
 
4149
        }
 
4150
    }
 
4151
 
 
4152
    if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
 
4153
        setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
 
4154
        unknown = false;
 
4155
    }
 
4156
 
 
4157
    if (unknown && !m_readOnly) {
 
4158
        QString t = event->text();
 
4159
        if (!t.isEmpty() && t.at(0).isPrint()) {
 
4160
            insert(t);
 
4161
            event->accept();
 
4162
            return;
 
4163
        }
 
4164
    }
 
4165
 
 
4166
    if (unknown)
 
4167
        event->ignore();
 
4168
    else
 
4169
        event->accept();
 
4170
}
 
4171
 
 
4172
 
 
4173
QT_END_NAMESPACE
 
4174