components for android added
[mardrone] / mardrone / imports / Qt / labs / components / native / TextArea.qml
diff --git a/mardrone/imports/Qt/labs/components/native/TextArea.qml b/mardrone/imports/Qt/labs/components/native/TextArea.qml
new file mode 100644 (file)
index 0000000..88df502
--- /dev/null
@@ -0,0 +1,545 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.0
+import Qt.labs.components 1.1
+import "UIConstants.js" as UI
+import "EditBubble.js" as Popup
+import "TextAreaHelper.js" as TextAreaHelper
+import "Magnifier.js" as MagnifierPopup
+
+FocusScope {
+    id: root
+
+    // Common public API
+    property alias text: textEdit.text
+    property alias placeholderText: prompt.text
+
+    property alias font: textEdit.font
+    property alias cursorPosition: textEdit.cursorPosition
+    property alias readOnly: textEdit.readOnly
+
+    property alias horizontalAlignment: textEdit.horizontalAlignment
+    property alias verticalAlignment: textEdit.verticalAlignment
+
+    property alias selectedText: textEdit.selectedText
+    property alias selectionStart: textEdit.selectionStart
+    property alias selectionEnd: textEdit.selectionEnd
+
+    property alias wrapMode: textEdit.wrapMode
+    property alias textFormat: textEdit.textFormat
+    // Property enableSoftwareInputPanel is DEPRECATED
+    property alias enableSoftwareInputPanel: textEdit.activeFocusOnPress
+
+    property alias inputMethodHints: textEdit.inputMethodHints
+
+    property bool errorHighlight: false
+
+    property Item platformSipAttributes
+
+    property bool platformEnableEditBubble: true
+
+    property Item platformStyle: TextAreaStyle {}
+    property alias style: root.platformStyle
+
+    property alias platformPreedit: inputMethodObserver.preedit
+
+    onPlatformSipAttributesChanged: {
+        platformSipAttributes.registerInputElement(textEdit)
+    }
+
+    function copy() {
+        textEdit.copy()
+    }
+
+    function paste() {
+        textEdit.paste()
+    }
+
+    function cut() {
+        textEdit.cut()
+    }
+
+    // ensure propagation of forceActiveFocus
+    function forceActiveFocus() {
+        textEdit.forceActiveFocus()
+    }
+
+    function select(start, end) {
+        textEdit.select(start, end)
+    }
+
+    function selectAll() {
+        textEdit.selectAll()
+    }
+
+    function selectWord() {
+        textEdit.selectWord()
+    }
+
+    function positionAt(x, y) {
+        var p = mapToItem(textEdit, x, y);
+        return textEdit.positionAt(p.x, p.y)
+    }
+
+    function positionToRectangle(pos) {
+        var rect = textEdit.positionToRectangle(pos)
+        var point = mapFromItem(textEdit, rect.x, rect.y)
+        rect.x = point.x; rect.y = point.y
+        return rect;
+    }
+
+    function closeSoftwareInputPanel() {
+        console.log("TextArea's function closeSoftwareInputPanel is deprecated. Use function platformCloseSoftwareInputPanel instead.")
+        platformCloseSoftwareInputPanel()
+    }
+
+    function platformCloseSoftwareInputPanel() {
+        inputContext.simulateSipClose();
+        textEdit.closeSoftwareInputPanel();
+    }
+
+    function openSoftwareInputPanel() {
+        console.log("TextArea's function openSoftwareInputPanel is deprecated. Use function platformOpenSoftwareInputPanel instead.")
+        platformOpenSoftwareInputPanel()
+    }
+
+    function platformOpenSoftwareInputPanel() {
+        inputContext.simulateSipOpen();
+        textEdit.openSoftwareInputPanel();
+    }
+
+    Connections {
+        target: platformWindow
+
+        onActiveChanged: {
+            if(platformWindow.active) {
+                if (!readOnly) {
+                    if (activeFocus) {
+                        platformOpenSoftwareInputPanel();
+                        repositionTimer.running = true;
+                    }
+                }
+            } else {
+                if (activeFocus) {
+                    platformCloseSoftwareInputPanel();
+                    Popup.close(textEdit);
+                }
+            }
+        }
+
+        onAnimatingChanged: {
+            if (!platformWindow.animating && root.activeFocus) {
+                TextAreaHelper.repositionFlickable(contentMovingAnimation);
+            }
+        }
+    }
+
+    // private
+    property int __preeditDisabledMask: Qt.ImhHiddenText|                       
+                                        Qt.ImhNoPredictiveText|                
+                                        Qt.ImhDigitsOnly|                      
+                                        Qt.ImhFormattedNumbersOnly|             
+                                        Qt.ImhDialableCharactersOnly|           
+                                        Qt.ImhEmailCharactersOnly|              
+                                        Qt.ImhUrlCharactersOnly 
+
+    implicitWidth: platformStyle.defaultWidth
+    implicitHeight: Math.max (UI.FIELD_DEFAULT_HEIGHT,
+                              textEdit.height + (UI.FIELD_DEFAULT_HEIGHT - font.pixelSize))
+
+    onActiveFocusChanged: {
+        if (activeFocus &&
+            !readOnly) {
+            platformOpenSoftwareInputPanel();
+            repositionTimer.running = true;
+        } else if (!activeFocus) {
+            if (!readOnly)
+                platformCloseSoftwareInputPanel();
+
+            Popup.close(textEdit);            
+        }
+    }
+
+    BorderImage {
+        id: background
+       source: errorHighlight?
+                platformStyle.backgroundError:
+            readOnly?
+                platformStyle.backgroundDisabled:
+            textEdit.activeFocus? 
+                platformStyle.backgroundSelected:
+                platformStyle.background
+
+        anchors.fill: parent
+        border.left: root.platformStyle.backgroundCornerMargin; border.top: root.platformStyle.backgroundCornerMargin
+        border.right: root.platformStyle.backgroundCornerMargin; border.bottom: root.platformStyle.backgroundCornerMargin
+    }
+
+    Text {
+        id: prompt
+
+        anchors.fill: parent
+        anchors.leftMargin: UI.PADDING_XLARGE
+        anchors.rightMargin: UI.PADDING_XLARGE
+        anchors.topMargin: (UI.FIELD_DEFAULT_HEIGHT - font.pixelSize) / 2
+        anchors.bottomMargin: (UI.FIELD_DEFAULT_HEIGHT - font.pixelSize) / 2
+
+        font: root.platformStyle.textFont
+        color: root.platformStyle.promptTextColor
+        elide: Text.ElideRight
+
+        // opacity for default state
+        opacity:  0.0
+
+        states: [
+            State {
+                name: "unfocused"
+                // memory allocation optimization: cursorPosition is checked to minimize displayText evaluations
+                when: !root.activeFocus && textEdit.cursorPosition == 0 && !textEdit.text && prompt.text && !textEdit.inputMethodComposing
+                PropertyChanges { target: prompt; opacity: 1.0; }
+            },
+            State {
+                name: "focused"
+                // memory allocation optimization: cursorPosition is checked to minimize displayText evaluations
+                when: root.activeFocus && textEdit.cursorPosition == 0 && !textEdit.text && prompt.text && !textEdit.inputMethodComposing
+                PropertyChanges { target: prompt; opacity: 0.6; }
+            }
+        ]
+
+        transitions: [
+            Transition {
+                from: "unfocused"; to: "focused";
+                reversible: true
+                SequentialAnimation {
+                    PauseAnimation { duration: 60 }
+                    NumberAnimation { target: prompt; properties: "opacity"; duration: 150 }
+                }
+            },
+            Transition {
+                from: "focused"; to: "";
+                reversible: true
+                SequentialAnimation {
+                    PauseAnimation { duration:  60 }
+                    NumberAnimation { target: prompt; properties: "opacity"; duration: 100 }
+                }
+            }
+        ]
+    }
+
+    MouseArea {
+        enabled: !textEdit.activeFocus
+        z: enabled?1:0
+        anchors.fill: parent
+        anchors.margins: UI.TOUCH_EXPANSION_MARGIN
+        onClicked: {
+            if (!textEdit.activeFocus) {
+                textEdit.forceActiveFocus();
+
+                // activate to preedit and/or move the cursor
+                var preeditDisabled = root.inputMethodHints &                   
+                                      root.__preeditDisabledMask
+                var injectionSucceeded = false;
+                var mappedMousePos = mapToItem(textEdit, mouseX, mouseY);
+                var newCursorPosition = textEdit.positionAt(mappedMousePos.x, mappedMousePos.y, TextInput.CursorOnCharacter);
+                if (!preeditDisabled
+                        && !TextAreaHelper.atSpace(newCursorPosition)
+                        && newCursorPosition != textEdit.text.length
+                        && !(newCursorPosition == 0 || TextAreaHelper.atSpace(newCursorPosition - 1))) {
+                    injectionSucceeded = TextAreaHelper.injectWordToPreedit(newCursorPosition);
+                }
+                if (!injectionSucceeded) {
+                    textEdit.cursorPosition=newCursorPosition;
+                }
+            }
+        }
+    }
+
+    TextEdit {
+        id: textEdit
+
+        // Exposed for the edit bubble
+        property alias preedit: inputMethodObserver.preedit
+        property alias preeditCursorPosition: inputMethodObserver.preeditCursorPosition
+
+        x: UI.PADDING_XLARGE
+        y: (UI.FIELD_DEFAULT_HEIGHT - font.pixelSize) / 2
+        width: parent.width - UI.PADDING_XLARGE * 2
+
+        font: root.platformStyle.textFont
+        color: root.platformStyle.textColor
+        selectByMouse: false
+        selectedTextColor: root.platformStyle.selectedTextColor
+        selectionColor: root.platformStyle.selectionColor
+        mouseSelectionMode: TextInput.SelectWords
+        wrapMode: TextEdit.Wrap
+        persistentSelection: false
+        focus: true
+
+        function updateMagnifierPosition(posX, posY) {
+            var yAdjustment = 0
+            var magnifier = MagnifierPopup.popup;
+            var cursorHeight = textEdit.positionToRectangle(0,0).height;
+            var mappedPos =  mapToItem(magnifier.parent, posX - magnifier.width / 2,
+                                       posY - magnifier.height / 2 - cursorHeight - 70);
+
+            magnifier.xCenter = mapToItem(magnifier.sourceItem, posX, 0).x;
+            magnifier.x = mappedPos.x;
+            if (-root.mapFromItem(magnifier.__rootElement(), 0,0).y - (posY - cursorHeight) < (magnifier.height / 1.5)) {
+                yAdjustment = Math.max(0,(magnifier.height / 1.5) + root.mapFromItem(magnifier.__rootElement(), 0,0).y - (posY - cursorHeight));
+            } else {
+                yAdjustment = 0;
+            }
+            magnifier.yCenter = mapToItem(magnifier.sourceItem, 0, posY - cursorHeight + 50).y
+            magnifier.y = mappedPos.y + yAdjustment;
+        }
+
+        Component.onDestruction: {
+            Popup.close(textEdit);
+        }
+
+        onTextChanged: {
+            if(root.activeFocus) {
+                TextAreaHelper.repositionFlickable(contentMovingAnimation);
+            }
+
+            if (textEdit.preedit == "" && Popup.isOpened(textEdit) && !Popup.isChangingInput())
+                Popup.close(textEdit);
+        }
+
+        Connections {
+            target: TextAreaHelper.findFlickable(root.parent)
+
+            onContentYChanged: if (root.activeFocus) TextAreaHelper.filteredInputContextUpdate();
+            onContentXChanged: if (root.activeFocus) TextAreaHelper.filteredInputContextUpdate();
+            onMovementEnded: inputContext.update();
+        }
+
+        Connections {
+            target: inputContext
+
+            onSoftwareInputPanelVisibleChanged: {
+                if (activeFocus)
+                    TextAreaHelper.repositionFlickable(contentMovingAnimation);
+            }
+
+            onSoftwareInputPanelRectChanged: {
+                if (activeFocus)
+                    TextAreaHelper.repositionFlickable(contentMovingAnimation);
+            }
+        }
+
+        onCursorPositionChanged: {
+            if(!MagnifierPopup.isOpened() && activeFocus) {
+                TextAreaHelper.repositionFlickable(contentMovingAnimation)
+            }
+
+           if (MagnifierPopup.isOpened() &&
+               Popup.isOpened(textEdit)) {
+               Popup.close(textEdit);
+           } else if ((!mouseFilter.attemptToActivate ||
+                textEdit.cursorPosition == textEdit.text.length) &&
+                Popup.isOpened(textEdit)) {
+                Popup.close(textEdit);
+                Popup.open(textEdit,
+                           textEdit.positionToRectangle(textEdit.cursorPosition));
+            }
+        }
+
+        onSelectedTextChanged: {
+            if (Popup.isOpened(textEdit) && !Popup.isChangingInput()) {
+                Popup.close(textEdit);
+            }
+        }
+
+        InputMethodObserver {
+            id: inputMethodObserver
+
+            onPreeditChanged: {
+                if (Popup.isOpened(textEdit) && !Popup.isChangingInput()) {
+                    Popup.close(textEdit);
+                }
+            }
+
+        }
+
+        Timer {
+            id: repositionTimer
+            interval: 350
+            onTriggered: TextAreaHelper.repositionFlickable(contentMovingAnimation)
+        }
+
+        PropertyAnimation {
+            id: contentMovingAnimation
+            property: "contentY"
+            duration: 200
+            easing.type: Easing.InOutCubic
+        }
+
+        MouseFilter {
+            id: mouseFilter
+            anchors.fill: parent
+            anchors.leftMargin:  UI.TOUCH_EXPANSION_MARGIN - UI.PADDING_XLARGE
+            anchors.rightMargin:  UI.TOUCH_EXPANSION_MARGIN - UI.PADDING_MEDIUM
+            anchors.topMargin: UI.TOUCH_EXPANSION_MARGIN - (UI.FIELD_DEFAULT_HEIGHT - font.pixelSize) / 2
+            anchors.bottomMargin:  UI.TOUCH_EXPANSION_MARGIN - (UI.FIELD_DEFAULT_HEIGHT - font.pixelSize) / 2
+
+            property bool attemptToActivate: false
+            property bool pressOnPreedit
+
+           property variant editBubblePosition: Qt.point(0,0) 
+
+            onPressed: {
+                var mousePosition = textEdit.positionAt(mouse.x,mouse.y,TextEdit.CursorOnCharacter);
+                pressOnPreedit = textEdit.cursorPosition==mousePosition
+                var preeditDisabled = root.inputMethodHints &                  
+                                      root.__preeditDisabledMask
+
+                attemptToActivate = !pressOnPreedit && !root.readOnly && !preeditDisabled && root.activeFocus &&
+                                    !(mousePosition == 0 || TextAreaHelper.atSpace(mousePosition - 1) || TextAreaHelper.atSpace(mousePosition));
+                mouse.filtered = true;
+            }
+
+            onHorizontalDrag: {
+                // possible pre-edit word have to be committed before selection
+                if (root.activeFocus || root.readOnly) {
+                    inputContext.reset()                    
+                    parent.selectByMouse = true
+                    attemptToActivate = false
+                }
+            }
+
+            onPressAndHold:{
+                // possible pre-edit word have to be commited before showing the magnifier
+                if ((root.text != "" || inputMethodObserver.preedit != "") && root.activeFocus) {
+                    inputContext.reset()
+                    attemptToActivate = false
+                    parent.selectByMouse = false
+                    MagnifierPopup.open(root);
+                    var magnifier = MagnifierPopup.popup;
+                    parent.cursorPosition = parent.positionAt(mouse.x,mouse.y)
+                    parent.updateMagnifierPosition(mouse.x,mouse.y)
+                    root.z = Number.MAX_VALUE
+                }
+            }
+
+            onReleased:{                
+                if (MagnifierPopup.isOpened()) {
+                    MagnifierPopup.close();
+                    TextAreaHelper.repositionFlickable(contentMovingAnimation);
+                }
+
+                if (attemptToActivate)
+                    inputContext.reset();
+
+                var newCursorPosition = textEdit.positionAt(mouse.x,mouse.y,TextEdit.CursorOnCharacter);
+                editBubblePosition = textEdit.positionToRectangle(newCursorPosition);
+
+                if (attemptToActivate) {
+                    var beforeText = textEdit.text;
+
+                    textEdit.cursorPosition = newCursorPosition;
+                    var injectionSucceeded = false;
+
+                    if (!TextAreaHelper.atSpace(newCursorPosition)                             
+                             && newCursorPosition != textEdit.text.length) {
+                        injectionSucceeded = TextAreaHelper.injectWordToPreedit(newCursorPosition);
+                    }
+                    if (injectionSucceeded) {
+                        mouse.filtered=true;
+                        if (textEdit.preedit.length >=1 && textEdit.preedit.length <= 4)
+                            editBubblePosition = textEdit.positionToRectangle(textEdit.cursorPosition);
+                    } else {
+                        textEdit.text=beforeText;
+                        textEdit.cursorPosition=newCursorPosition;
+                    }
+                    attemptToActivate = false;
+                } else if (!parent.selectByMouse) {
+                    if (!pressOnPreedit) inputContext.reset();
+                    textEdit.cursorPosition = textEdit.positionAt(mouse.x,mouse.y,TextEdit.CursorOnCharacter);
+                }
+                parent.selectByMouse = false;
+            }
+            onFinished: {
+                if (root.activeFocus && platformEnableEditBubble) {
+                    if (textEdit.preedit.length == 0)
+                        editBubblePosition = textEdit.positionToRectangle(textEdit.cursorPosition);
+                    Popup.open(textEdit,editBubblePosition);
+                }
+            }
+            onMousePositionChanged: {
+               if (MagnifierPopup.isOpened() && !parent.selectByMouse) {
+                    var pos = textEdit.positionAt (mouse.x,mouse.y)
+                    var posNextLine = textEdit.positionAt (mouse.x, mouse.y + 1)
+                    var posPrevLine = textEdit.positionAt (mouse.x, mouse.y - 1)
+                    if (!(Math.abs(posNextLine - pos) > 1 ||
+                        Math.abs(posPrevLine - pos) > 1)) {
+                        parent.cursorPosition = pos
+                    }
+                    parent.updateMagnifierPosition(mouse.x,mouse.y);
+                }
+            }
+            onDoubleClicked: {
+                // possible pre-edit word have to be committed before selection
+                inputContext.reset()
+                parent.selectByMouse = true
+                attemptToActivate = false
+            }
+        }
+    }
+
+
+
+    InverseMouseArea {
+        anchors.fill: parent
+        anchors.margins: UI.TOUCH_EXPANSION_MARGIN
+        enabled: root.activeFocus
+
+        onClickedOutside: {
+            if (Popup.isOpened(textEdit) && ((mouseX > Popup.geometry().left && mouseX < Popup.geometry().right) &&
+                                           (mouseY > Popup.geometry().top && mouseY < Popup.geometry().bottom))) {
+                return;
+            }
+
+            root.parent.focus = true;
+        }
+    }
+}