Hey,

I've worked on the editing features in the Plasma QML Components in kde-
runtime, with some pretty good success. You can find the results in kde-
runtime's sebas/editbubble branch.

The patches add -- nomen est omen -- an edit bubble to the touch version of 
the Plasma Components, which allow for basic copy and paste. Triggering is 
done on pressAndHold, the bubble moves with the cursor, so it's pretty basic 
but working quite well. (It allows the user for example to copy and paste in 
the URL bar. Obviously, this only works for our TextField and TextArea, so 
QWidgets are left out, and every other (QML) Text input should be ported to 
use Plasma Components.

For Plasma Active, I think this is quite important functionality, so I suggest 
that we ship this patch (or an improved version of it) with PA2, and then 
integrate it into kde-runtime master at the start of the next cycle.

The patch adds a MouseEventListener which is basically a MouseArea which does 
*not* intercept events (the normal MouseArea does, and it's not changable, so 
we pretty much have to do it this way). This guy moves from mobilecomponents 
into qtextra.

Note: This does not entail selection / editing for Text elements, or the 
webview itself. This is a larger issue, that we can still tackle once we're 
happy with this basic version.

Cheers,
-- 
sebas

http://www.kde.org | http://vizZzion.org | GPG Key ID: 9119 0EF9
diff --git a/plasma/declarativeimports/plasmacomponents/CMakeLists.txt b/plasma/declarativeimports/plasmacomponents/CMakeLists.txt
index 8af2dfa..bb43f9c 100644
--- a/plasma/declarativeimports/plasmacomponents/CMakeLists.txt
+++ b/plasma/declarativeimports/plasmacomponents/CMakeLists.txt
@@ -63,8 +63,8 @@ install(FILES qml/TabBar.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/t
 install(FILES qml/TabButton.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components)
 install(FILES qml/TabGroup.js DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components)
 install(FILES qml/TabGroup.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components)
-install(FILES qml/TextArea.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components)
-install(FILES qml/TextField.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components)
+#install(FILES qml/TextArea.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components)
+#install(FILES qml/TextField.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components)
 install(FILES qml/ToolBarLayout.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components)
 install(FILES qml/ToolBar.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components)
 
diff --git a/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/EditBubble.js b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/EditBubble.js
new file mode 100644
index 0000000..a8ad3ae
--- /dev/null
+++ b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/EditBubble.js
@@ -0,0 +1,23 @@
+function placeEditBubble(mouse) {
+    // Find the root item, then map our cursor position to it
+    // in order to check if the edit bubble could end up off-screen
+    var rootItem = parent;
+    while (rootItem.parent) {
+        rootItem = rootItem.parent;
+    }
+    var distanceToTop = mouseEventListener.mapToItem(rootItem, mouse.x, mouse.y);
+    print( "   distanceToTop: " + distanceToTop.x);
+    if (distanceToTop.x < editBubble.width/2) {
+        // hitting the left edge
+        //editBubble.x = mouse.x
+
+    } else {
+        editBubble.x = mouse.x-(editBubble.width/2)
+    }
+    if (distanceToTop.y > editBubble.height) {
+        editBubble.y = mouse.y-editBubble.height-8
+    } else {
+        //editBubble.y = mouse.y-(editBubble.width/2)
+    }
+
+}
diff --git a/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/EditBubble.qml b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/EditBubble.qml
new file mode 100644
index 0000000..96ca25e
--- /dev/null
+++ b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/EditBubble.qml
@@ -0,0 +1,109 @@
+/*
+*   Copyright 2011 by Sebastian Kügler <se...@kde.org>
+*
+*   This program is free software; you can redistribute it and/or modify
+*   it under the terms of the GNU Library General Public License as
+*   published by the Free Software Foundation; either version 2, or
+*   (at your option) any later version.
+*
+*   This program is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details
+*
+*   You should have received a copy of the GNU Library General Public
+*   License along with this program; if not, write to the
+*   Free Software Foundation, Inc.,
+*   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+import QtQuick 1.1
+import org.kde.plasma.core 0.1 as PlasmaCore
+import org.kde.qtextracomponents 0.1
+
+PlasmaCore.FrameSvgItem {
+    id: editBubble
+    objectName: "editBubble"
+    property int iconSize: 32;
+
+    imagePath: "dialogs/background"
+    width: (iconSize*2) + iconSize
+    height: iconSize*2
+    z: 100000
+    //anchors { top: parent.bottom; right: parent.right; topMargin: -(iconSize/4); }
+
+    // fully dynamic show / hide
+    //state: (textInput.activeFocus && (textInput.selectedText != "" || textInput.canPaste)) ? "expanded" : "collapsed";
+    // state controlled externally
+    state: "collapsed"
+
+    Row {
+        id: buttonRow
+        spacing: 4
+        anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter; margins: 8; }
+        height: editBubble.iconSize
+        QIconItem {
+            id: pasteIcon
+            icon: QIcon("edit-paste")
+            width: editBubble.iconSize
+            height: editBubble.iconSize
+            enabled: textInput.canPaste
+            MouseArea {
+                anchors.fill: parent;
+                onClicked: { textField.paste(); editBubble.state = "collapsed"; }
+                onPressed: PropertyAnimation {  target: pasteIcon; properties: "scale";
+                                                from: 1.0; to: 0.9;
+                                                duration: 175; easing.type: Easing.OutExpo; }
+                onReleased: PropertyAnimation { target: pasteIcon; properties: "scale";
+                                                from: 0.9; to: 1.0;
+                                                duration: 175; easing.type: Easing.OutExpo; }
+            }
+        }
+        QIconItem {
+            id: copyIcon
+            icon: QIcon("edit-copy")
+            width: editBubble.iconSize
+            height: editBubble.iconSize
+            enabled: textInput.selectedText != ""
+            MouseArea {
+                anchors.fill: parent;
+                onClicked: { textField.copy(); editBubble.state = "collapsed"; }
+                onPressed: PropertyAnimation {  target: copyIcon; properties: "scale";
+                                                from: 1.0; to: 0.9;
+                                                duration: 175; easing.type: Easing.OutExpo; }
+                onReleased: PropertyAnimation { target: copyIcon; properties: "scale";
+                                                from: 0.9; to: 1.0;
+                                                duration: 175; easing.type: Easing.OutExpo; }
+            }
+        }
+    }
+    states: [
+        State {
+            id: expanded
+            name: "expanded";
+            PropertyChanges { target: editBubble; opacity: 1.0; scale: 1.0 }
+        },
+        State {
+            id: collapsed
+            name: "collapsed";
+            PropertyChanges { target: editBubble; opacity: 0; scale: 0.9 }
+        }
+    ]
+
+    transitions: [
+        Transition {
+            from: "collapsed"; to: "expanded"
+            ParallelAnimation {
+                PropertyAnimation { properties: "opacity"; duration: 175; easing.type: Easing.InExpo; }
+                PropertyAnimation { properties: "scale"; duration: 175; easing.type: Easing.InExpo; }
+            }
+        },
+        Transition {
+            from: "expanded"; to: "collapsed"
+            ParallelAnimation {
+                PropertyAnimation { properties: "opacity"; duration: 175; easing.type: Easing.OutExpo; }
+                PropertyAnimation { properties: "scale"; duration: 100; easing.type: Easing.OutExpo; }
+            }
+        }
+    ]
+}
diff --git a/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/TextArea.qml b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/TextArea.qml
new file mode 100644
index 0000000..71e14ca
--- /dev/null
+++ b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/TextArea.qml
@@ -0,0 +1,247 @@
+/*
+*   Copyright (C) 2011 by Daker Fernandes Pinheiro <dake...@gmail.com>
+*
+*   This program is free software; you can redistribute it and/or modify
+*   it under the terms of the GNU Library General Public License as
+*   published by the Free Software Foundation; either version 2, or
+*   (at your option) any later version.
+*
+*   This program is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details
+*
+*   You should have received a copy of the GNU Library General Public
+*   License along with this program; if not, write to the
+*   Free Software Foundation, Inc.,
+*   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+import QtQuick 1.1
+import org.kde.plasma.core 0.1 as PlasmaCore
+import org.kde.qtextracomponents 0.1
+import "EditBubble.js" as EditBubbleHelper
+
+Item {
+    id: textArea
+
+    // Common API
+    property alias font: textEdit.font // alias to textEdit.font
+    property int inputMethodHints
+    property bool errorHighlight
+    property alias cursorPosition: textEdit.cursorPosition
+    property alias horizontalAlignment: textEdit.cursorPosition
+    property alias verticalAlignment: textEdit.cursorPosition
+    property alias readOnly: textEdit.readOnly
+    property alias selectedText: textEdit.selectedText // read-only
+    property alias selectionEnd: textEdit.selectionEnd // read-only
+    property alias selectionStart: textEdit.selectionStart // read-only
+    property alias text: textEdit.text
+    property alias textFormat: textEdit.textFormat // enumeration
+    property alias wrapMode: textEdit.wrapMode // enumeration
+    property string placeholderText
+
+    property alias textField: textArea
+
+    // functions
+    function copy() {
+        textEdit.copy();
+    }
+
+    function paste() {
+        textEdit.paste();
+    }
+
+    function cut() {
+        textEdit.cut();
+    }
+
+    function select(start, end) {
+        textEdit.select(start, end);
+    }
+
+    function selectAll() {
+        textEdit.selectAll();
+    }
+
+    function selectWord() {
+        textEdit.selectWord();
+    }
+
+    function positionAt(pos) {
+        textEdit.positionAt(pos);
+    }
+
+    function positionToRectangle(pos) {
+        textEdit.positionToRectangle(pos);
+    }
+
+    // Plasma API
+    property alias interactive: flickArea.interactive
+    property alias contentMaxWidth: textEdit.width
+    property alias contentMaxHeight: textEdit.height
+    property alias textInput: textEdit
+
+    // Set active focus to it's internal textInput.
+    // Overriding QtQuick.Item forceActiveFocus function.
+    function forceActiveFocus() {
+        textEdit.forceActiveFocus();
+    }
+
+    // Overriding QtQuick.Item activeFocus property.
+    property alias activeFocus: textEdit.activeFocus
+
+    opacity: enabled ? 1.0 : 0.5
+
+    TextFieldFocus {
+        id: hover
+        state: textArea.activeFocus ? "focus" : (mouseWatcher.containsMouse ? "hover" : "hidden")
+        anchors.fill: base
+    }
+
+    MouseArea {
+        id: mouseWatcher
+        anchors.fill: hover
+        hoverEnabled: true
+    }
+
+    PlasmaCore.FrameSvgItem {
+        id: base
+
+        // TODO: see what is the best policy for margins
+        anchors {
+            fill: parent
+        }
+        imagePath: "widgets/lineedit"
+        prefix: "base"
+    }
+
+    Flickable {
+        id: flickArea
+        anchors {
+            fill: parent
+            leftMargin: 2 * base.margins.left
+            rightMargin: 2 * base.margins.right + (verticalScroll.visible ? verticalScroll.width : 0)
+            topMargin: 2 * base.margins.top
+            bottomMargin: 2 * base.margins.bottom + (horizontalScroll.visible ? verticalScroll.width : 0)
+        }
+        interactive: !verticalScroll.interactive //textArea.activeFocus
+        contentWidth: {
+            if (textEdit.wrapMode == TextEdit.NoWrap)
+                return textEdit.paintedWidth;
+
+            return Math.min(textEdit.paintedWidth, textEdit.width);
+        }
+        contentHeight: Math.min(textEdit.paintedHeight, textEdit.height)
+        clip: true
+        MouseEventListener {
+            id: mouseEventListener
+            //anchors.fill: parent
+            onPressed: forceActiveFocus();
+            //onPressed: print(" MouseEventListener Pressed");
+            onPressAndHold: {
+                print(" *** MouseEventListener PressAndHold");
+                //forceActiveFocus();
+                EditBubbleHelper.placeEditBubble(mouse);
+                editBubble.state  = (textInput.activeFocus && (textInput.selectedText != "" || textInput.canPaste)) ? "expanded" : "collapsed";
+            }
+            onPositionChanged: {
+                EditBubbleHelper.placeEditBubble(mouse);
+            }
+        }
+
+        TextEdit {
+            id: textEdit
+            parent: mouseEventListener
+            width: flickArea.width
+            height: flickArea.height
+            clip: true
+            wrapMode: TextEdit.Wrap
+            enabled: textArea.enabled
+            font.capitalization: theme.defaultFont.capitalization
+            font.family: theme.defaultFont.family
+            font.italic: theme.defaultFont.italic
+            font.letterSpacing: theme.defaultFont.letterSpacing
+            font.pointSize: theme.defaultFont.pointSize
+            font.strikeout: theme.defaultFont.strikeout
+            font.underline: theme.defaultFont.underline
+            font.weight: theme.defaultFont.weight
+            font.wordSpacing: theme.defaultFont.wordSpacing
+            color: theme.viewTextColor
+            selectByMouse: verticalScroll.interactive
+
+            onCursorPositionChanged: {
+                if (cursorRectangle.x < flickArea.contentX) {
+                    flickArea.contentX = cursorRectangle.x;
+                    return;
+                }
+
+                if (cursorRectangle.x > flickArea.contentX +
+                    flickArea.width - cursorRectangle.width) {
+                    flickArea.contentX = cursorRectangle.x -
+                        cursorRectangle.width;
+                    return;
+                }
+
+                if (cursorRectangle.y < flickArea.contentY) {
+                    flickArea.contentY = cursorRectangle.y;
+                    return;
+                }
+
+                if (cursorRectangle.y > flickArea.contentY +
+                    flickArea.height - cursorRectangle.height) {
+                    flickArea.contentY = cursorRectangle.y -
+                        cursorRectangle.height;
+                    return;
+                }
+            }
+
+            // Proxying keys events  is not required by the
+            //     common API but is desired in the plasma API.
+            Keys.onPressed: textArea.Keys.pressed(event);
+            Keys.onReleased: textArea.Keys.released(event);
+
+            Text {
+                anchors.fill: parent
+                text: textArea.placeholderText
+                visible: textEdit.text == "" && !textArea.activeFocus
+                opacity: 0.5
+            }
+        }
+    }
+
+    ScrollBar {
+        id: horizontalScroll
+        anchors {
+            bottom: parent.bottom
+            left: parent.left
+            right: flickArea.right
+        }
+        enabled: parent.enabled
+        flickableItem: flickArea
+        orientation: Qt.Horizontal
+        stepSize: textEdit.font.pixelSize
+    }
+
+    ScrollBar {
+        id: verticalScroll
+        anchors {
+            right: parent.right
+            top: parent.top
+            bottom: flickArea.bottom
+        }
+        enabled: parent.enabled
+        flickableItem: flickArea
+        orientation: Qt.Vertical
+        stepSize: textEdit.font.pixelSize
+    }
+
+    EditBubble { id: editBubble; iconSize: 32; }
+
+    onActiveFocusChanged: {
+        if (!activeFocus) {
+            editBubble.state = "collapsed";
+            //print("Hiding...");
+        }
+    }
+}
\ No newline at end of file
diff --git a/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/TextField.qml b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/TextField.qml
new file mode 100644
index 0000000..daa54ea
--- /dev/null
+++ b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/TextField.qml
@@ -0,0 +1,216 @@
+/*
+*   Copyright (C) 2011 by Daker Fernandes Pinheiro <dake...@gmail.com>
+*
+*   This program is free software; you can redistribute it and/or modify
+*   it under the terms of the GNU Library General Public License as
+*   published by the Free Software Foundation; either version 2, or
+*   (at your option) any later version.
+*
+*   This program is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details
+*
+*   You should have received a copy of the GNU Library General Public
+*   License along with this program; if not, write to the
+*   Free Software Foundation, Inc.,
+*   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+import QtQuick 1.1
+import org.kde.plasma.core 0.1 as PlasmaCore
+import org.kde.qtextracomponents 0.1
+import "EditBubble.js" as EditBubbleHelper
+
+Item {
+    id: textField
+
+    // Common API
+    property bool errorHighlight: false // TODO
+    property string placeholderText
+    property alias inputMethodHints: textInput.inputMethodHints
+    property alias font: textInput.font
+
+    property alias cursorPosition: textInput.cursorPosition
+    property alias readOnly: textInput.readOnly
+    property alias echoMode: textInput.echoMode // Supports TextInput.Normal,TextInput.Password, TextInput.NoEcho, TextInput.PasswordEchoOnEdit
+    property alias acceptableInput: textInput.acceptableInput // read-only
+    property alias inputMask: textInput.inputMask
+    property alias validator: textInput.validator
+    property alias selectedText: textInput.selectedText // read-only
+    property alias selectionEnd: textInput.selectionEnd // read-only
+    property alias selectionStart: textInput.selectionStart // read-only
+    property alias text: textInput.text
+    property alias maximumLength: textInput.maximumLength
+
+    //Plasma api
+    property bool clearButtonShown: false
+
+    function copy() {
+        textInput.copy();
+    }
+
+    function paste() {
+        textInput.paste();
+    }
+
+    function cut() {
+        textInput.cut();
+    }
+
+    function select(start, end) {
+        textInput.select(start, end);
+    }
+
+    function selectAll() {
+        textInput.selectAll();
+    }
+
+    function selectWord() {
+        textInput.selectWord();
+    }
+
+    function positionAt(pos) {
+        textInput.positionAt(pos);
+    }
+
+    function positionToRectangle(pos) {
+        textInput.positionToRectangle(pos);
+    }
+
+
+    // Set active focus to it's internal textInput.
+    // Overriding QtQuick.Item forceActiveFocus function.
+    function forceActiveFocus() {
+        textInput.forceActiveFocus();
+    }
+
+    // Overriding QtQuick.Item activeFocus property.
+    property alias activeFocus: textInput.activeFocus
+
+    // TODO: fix default size
+    implicitWidth: theme.defaultFont.mSize.width*12
+    implicitHeight: theme.defaultFont.mSize.height*1.6
+    // TODO: needs to define if there will be specific graphics for
+    //     disabled text fields
+    opacity: enabled ? 1.0 : 0.5
+
+    TextFieldFocus {
+        id: hover
+        state: textInput.activeFocus ? "focus" : (mouseWatcher.containsMouse ? "hover" : "hidden")
+        anchors.fill: base
+    }
+
+    PlasmaCore.FrameSvgItem {
+        id: base
+
+        // TODO: see what is the correct policy for margins
+        anchors.fill: parent
+        imagePath: "widgets/lineedit"
+        prefix: "base"
+    }
+
+    MouseArea {
+        id: mouseWatcher
+        anchors.fill: hover
+        hoverEnabled: false
+    }
+
+    Text {
+        anchors {
+            left: parent.left
+            right: parent.right
+            verticalCenter: parent.verticalCenter
+            leftMargin: 2 * base.margins.left
+            rightMargin: 2 * base.margins.right
+        }
+        text: placeholderText
+        visible: textInput.text == "" && !textField.activeFocus
+        // XXX: using textColor and low opacity for theming placeholderText
+        color: theme.viewTextColor
+        opacity: 0.5
+        elide: Text.ElideRight
+        clip: true
+        font.capitalization: theme.defaultFont.capitalization
+        font.family: theme.defaultFont.family
+        font.italic: theme.defaultFont.italic
+        font.letterSpacing: theme.defaultFont.letterSpacing
+        font.pointSize: theme.defaultFont.pointSize
+        font.strikeout: theme.defaultFont.strikeout
+        font.underline: theme.defaultFont.underline
+        font.weight: theme.defaultFont.weight
+        font.wordSpacing: theme.defaultFont.wordSpacing
+
+    }
+
+    EditBubble { id: editBubble; iconSize: 32 }
+
+    TextInput {
+        id: textInput
+        parent: mouseEventListener
+
+        anchors {
+            left: parent.left
+            right: parent.right
+            verticalCenter: parent.verticalCenter
+            // TODO: see what is the correct policy for margins
+            leftMargin: 2 * base.margins.left
+            rightMargin: 2 * base.margins.right
+        }
+        selectByMouse: true
+        color: theme.textColor
+        enabled: textField.enabled
+        clip: true
+
+        // Proxying keys events  is not required by the
+        //     common API but is desired in the plasma API.
+        Keys.onPressed: textField.Keys.pressed(event);
+        Keys.onReleased: textField.Keys.released(event);
+    }
+
+    PlasmaCore.SvgItem {
+        parent: mouseEventListener // reparent to the MouseFilter for MouseArea to work
+        svg: PlasmaCore.Svg {imagePath: "widgets/lineedit"}
+        elementId: "clearbutton"
+        width: textInput.height
+        height: textInput.height
+        opacity: (textInput.text != "" && clearButtonShown) ? 1 : 0
+        Behavior on opacity {
+            NumberAnimation {
+                duration: 250
+                easing.type: Easing.InOutQuad
+            }
+        }
+        anchors {
+            right: parent.right
+            rightMargin: y
+            verticalCenter: parent.verticalCenter
+        }
+        MouseArea {
+            anchors.fill: parent
+            onClicked: {
+                textInput.text = "";
+                textInput.forceActiveFocus();
+                editBubble.state = "collapsed"
+            }
+        }
+    }
+
+    MouseEventListener {
+        id: mouseEventListener
+        anchors.fill: parent
+        onPressAndHold: {
+            EditBubbleHelper.placeEditBubble(mouse);
+            editBubble.state  = (textInput.activeFocus && (textInput.selectedText != "" || textInput.canPaste)) ? "expanded" : "collapsed";
+        }
+        onPositionChanged: {
+            EditBubbleHelper.placeEditBubble(mouse);
+        }
+    }
+
+    onActiveFocusChanged: {
+        if (!activeFocus) {
+            editBubble.state = "collapsed";
+        }
+    }
+}
\ No newline at end of file
diff --git a/plasma/declarativeimports/qtextracomponents/CMakeLists.txt b/plasma/declarativeimports/qtextracomponents/CMakeLists.txt
index a78644f..05a1195 100644
--- a/plasma/declarativeimports/qtextracomponents/CMakeLists.txt
+++ b/plasma/declarativeimports/qtextracomponents/CMakeLists.txt
@@ -7,6 +7,7 @@ set(qtextracomponents_SRCS
     qpixmapitem.cpp
     qimageitem.cpp
     qiconitem.cpp
+    mouseeventlistener.cpp
     )
 
 INCLUDE_DIRECTORIES(
diff --git a/plasma/declarativeimports/qtextracomponents/mouseeventlistener.cpp b/plasma/declarativeimports/qtextracomponents/mouseeventlistener.cpp
new file mode 100644
index 0000000..3b9222f
--- /dev/null
+++ b/plasma/declarativeimports/qtextracomponents/mouseeventlistener.cpp
@@ -0,0 +1,134 @@
+/*
+    Copyright 2011 Marco Martin <notm...@gmail.com>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#include "mouseeventlistener.h"
+
+#include <QEvent>
+#include <QGraphicsSceneMouseEvent>
+#include <QtCore/QTimer>
+
+#include <KDebug>
+
+MouseEventListener::MouseEventListener(QDeclarativeItem *parent)
+    : QDeclarativeItem(parent),
+    m_pressed(false),
+    m_pressAndHoldEvent(0)
+{
+    setFiltersChildEvents(true);
+    setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton|Qt::MidButton|Qt::XButton1|Qt::XButton2);
+}
+
+MouseEventListener::~MouseEventListener()
+{
+}
+
+void MouseEventListener::mousePressEvent(QGraphicsSceneMouseEvent *me)
+{
+    //FIXME: when a popup window is visible: a click anywhere hides it: but the old qgraphicswidget will continue to think it's under the mouse
+    //doesn't seem to be any good way to properly reset this.
+    //this msolution will still caused a missed click after the popup is gone, but gets the situation unblocked.
+    if (!isUnderMouse()) {
+        me->ignore();
+        return;
+    }
+
+    QDeclarativeMouseEvent dme(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers());
+    m_pressAndHoldEvent = new QDeclarativeMouseEvent(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers());
+    kDebug() << "pressed in mousePressEvent";
+    emit pressed(&dme);
+    m_pressed = true;
+    //delete m_pressAndHoldEvent;
+    //m_pressAndHoldEvent = &dme;
+    //new QDeclarativeMouseEvent(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers());;
+    QTimer::singleShot(800, this, SLOT(handlePressAndHold()));
+}
+
+void MouseEventListener::mouseMoveEvent(QGraphicsSceneMouseEvent *me)
+{
+    QDeclarativeMouseEvent dme(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers());
+    emit positionChanged(&dme);
+}
+
+void MouseEventListener::mouseReleaseEvent(QGraphicsSceneMouseEvent *me)
+{
+    QDeclarativeMouseEvent dme(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers());
+    m_pressed = false;
+    emit released(&dme);
+}
+
+void MouseEventListener::handlePressAndHold()
+{
+    if (m_pressed) {
+        //QDeclarativeMouseEvent dme = m_pressAndHoldEvent;
+        //const QPointF myPos = m_pressAndHoldEvent->pos();
+        //QDeclarativeMouseEvent dme(myPos.x(), myPos.y(), m_pressAndHoldEvent->screenPos().x(), m_pressAndHoldEvent->screenPos().y(), m_pressAndHoldEvent->button(), m_pressAndHoldEvent->buttons(), m_pressAndHoldEvent->modifiers());
+        emit pressAndHold(m_pressAndHoldEvent);
+        //delete m_pressAndHoldEvent;
+    }
+}
+
+
+bool MouseEventListener::sceneEventFilter(QGraphicsItem *item, QEvent *event)
+{
+    if (!isEnabled()) {
+        return false;
+    }
+
+    switch (event->type()) {
+    case QEvent::GraphicsSceneMousePress: {
+        QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(event);
+        //the parent will receive events in its own coordinates
+        const QPointF myPos = item->mapToItem(this, me->pos());
+        QDeclarativeMouseEvent dme(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers());
+        m_pressAndHoldEvent = new QDeclarativeMouseEvent(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers());
+        //kDebug() << "pressed in sceneEventFilter";
+        emit pressed(&dme);
+        m_pressed = true;
+        //delete m_pressAndHoldEvent;
+        //m_pressAndHoldEvent = new QDeclarativeMouseEvent(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers());;
+        //m_pressAndHoldEvent = &dme;
+        QTimer::singleShot(800, this, SLOT(handlePressAndHold()));
+        break;
+    }
+    case QEvent::GraphicsSceneMouseMove: {
+        QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(event);
+        const QPointF myPos = item->mapToItem(this, me->pos());
+        QDeclarativeMouseEvent dme(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers());
+        //kDebug() << "positionChanged..." << dme.x() << dme.y();
+        m_pressAndHoldEvent = new QDeclarativeMouseEvent(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers());
+        emit positionChanged(&dme);
+        break;
+    }
+    case QEvent::GraphicsSceneMouseRelease: {
+        QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(event);
+        const QPointF myPos = item->mapToItem(this, me->pos());
+        QDeclarativeMouseEvent dme(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers());
+        emit released(&dme);
+        m_pressed = false;
+        break;
+    }
+    default:
+        break;
+    }
+
+    return QDeclarativeItem::sceneEventFilter(item, event);
+}
+
+#include "mouseeventlistener.moc"
+
diff --git a/plasma/declarativeimports/qtextracomponents/mouseeventlistener.h b/plasma/declarativeimports/qtextracomponents/mouseeventlistener.h
new file mode 100644
index 0000000..ef7ecf1
--- /dev/null
+++ b/plasma/declarativeimports/qtextracomponents/mouseeventlistener.h
@@ -0,0 +1,100 @@
+/*
+    Copyright 2011 Marco Martin <notm...@gmail.com>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MOUSEEVENTLISTENER_H
+#define MOUSEEVENTLISTENER_H
+
+#include <QDeclarativeItem>
+
+class QDeclarativeMouseEvent : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(int x READ x)
+    Q_PROPERTY(int y READ y)
+    Q_PROPERTY(int screenX READ screenX)
+    Q_PROPERTY(int screenY READ screenY)
+    Q_PROPERTY(int button READ button)
+    Q_PROPERTY(int buttons READ buttons)
+    Q_PROPERTY(int modifiers READ modifiers)
+
+public:
+    QDeclarativeMouseEvent(int x, int y, int screenX, int screenY,
+                           Qt::MouseButton button,
+                           Qt::MouseButtons buttons,
+                           Qt::KeyboardModifiers modifiers)
+        : m_x(x),
+          m_y(y),
+          m_screenX(screenX),
+          m_screenY(screenY),
+          m_button(button),
+          m_buttons(buttons),
+          m_modifiers(modifiers)
+    {}
+
+    int x() const { return m_x; }
+    int y() const { return m_y; }
+    int screenX() const { return m_screenX; }
+    int screenY() const { return m_screenY; }
+    int button() const { return m_button; }
+    int buttons() const { return m_buttons; }
+    int modifiers() const { return m_modifiers; }
+
+    // only for internal usage
+    void setX(int x) { m_x = x; }
+    void setY(int y) { m_y = y; }
+
+private:
+    int m_x;
+    int m_y;
+    int m_screenX;
+    int m_screenY;
+    Qt::MouseButton m_button;
+    Qt::MouseButtons m_buttons;
+    Qt::KeyboardModifiers m_modifiers;
+};
+
+class MouseEventListener : public QDeclarativeItem
+{
+    Q_OBJECT
+
+public:
+    MouseEventListener(QDeclarativeItem *parent=0);
+    ~MouseEventListener();
+
+protected:
+    void mousePressEvent(QGraphicsSceneMouseEvent *event);
+    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+    bool sceneEventFilter(QGraphicsItem *i, QEvent *e);
+
+Q_SIGNALS:
+    void pressed(QDeclarativeMouseEvent *mouse);
+    void positionChanged(QDeclarativeMouseEvent *mouse);
+    void released(QDeclarativeMouseEvent *mouse);
+    void pressAndHold(QDeclarativeMouseEvent *mouse);
+
+private Q_SLOTS:
+    void handlePressAndHold();
+private:
+    bool m_pressed;
+    QDeclarativeMouseEvent* m_pressAndHoldEvent;
+    QPointF m_pressAndHoldPosition;
+};
+
+#endif
diff --git a/plasma/declarativeimports/qtextracomponents/qtextracomponentsplugin.cpp b/plasma/declarativeimports/qtextracomponents/qtextracomponentsplugin.cpp
index c094349..429282e 100644
--- a/plasma/declarativeimports/qtextracomponents/qtextracomponentsplugin.cpp
+++ b/plasma/declarativeimports/qtextracomponents/qtextracomponentsplugin.cpp
@@ -26,6 +26,7 @@
 #include "qpixmapitem.h"
 #include "qimageitem.h"
 #include "qiconitem.h"
+#include "mouseeventlistener.h"
 
 
 void QtExtraComponentsPlugin::registerTypes(const char *uri)
@@ -35,6 +36,7 @@ void QtExtraComponentsPlugin::registerTypes(const char *uri)
     qmlRegisterType<QPixmapItem>(uri, 0, 1, "QPixmapItem");
     qmlRegisterType<QImageItem>(uri, 0, 1, "QImageItem");
     qmlRegisterType<QIconItem>(uri, 0, 1, "QIconItem");
+    qmlRegisterType<MouseEventListener>(uri, 0, 1, "MouseEventListener");
 }
 
 
diff --git a/plasma/declarativeimports/test/gallery/Gallery.qml b/plasma/declarativeimports/test/gallery/Gallery.qml
index 515b3db..b4f9f80 100644
--- a/plasma/declarativeimports/test/gallery/Gallery.qml
+++ b/plasma/declarativeimports/test/gallery/Gallery.qml
@@ -70,6 +70,10 @@ Rectangle {
                 title: "Text elements"
             }
             ListElement {
+                page: "TextEditing.qml"
+                title: "Text Editing"
+            }
+            ListElement {
                 page: "Misc.qml"
                 title: "Misc stuff"
             }
@@ -103,7 +107,7 @@ Rectangle {
             toolBar: toolBar
             width: page.width
             height: currentPage.implicitHeight
-            initialPage: Qt.createComponent("Buttons.qml")
+            initialPage: Qt.createComponent("TextEditing.qml")
         }
 
     }
diff --git a/plasma/declarativeimports/test/gallery/Misc.qml b/plasma/declarativeimports/test/gallery/Misc.qml
index aebdd73..739a0e4 100644
--- a/plasma/declarativeimports/test/gallery/Misc.qml
+++ b/plasma/declarativeimports/test/gallery/Misc.qml
@@ -181,7 +181,7 @@ Column {
         Timer {
             running: true
             repeat: true
-            interval: 25
+            interval: 100
             onTriggered: parent.value = (parent.value + 1) % 1.1
         }
     }
diff --git a/plasma/declarativeimports/test/gallery/TextEditing.qml b/plasma/declarativeimports/test/gallery/TextEditing.qml
new file mode 100644
index 0000000..edc7f15
--- /dev/null
+++ b/plasma/declarativeimports/test/gallery/TextEditing.qml
@@ -0,0 +1,69 @@
+/*
+*   Copyright (C) 2011 by Daker Fernandes Pinheiro <dake...@gmail.com>
+*
+*   This program is free software; you can redistribute it and/or modify
+*   it under the terms of the GNU Library General Public License as
+*   published by the Free Software Foundation; either version 2, or
+*   (at your option) any later version.
+*
+*   This program is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details
+*
+*   You should have received a copy of the GNU Library General Public
+*   License along with this program; if not, write to the
+*   Free Software Foundation, Inc.,
+*   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+import QtQuick 1.1
+import org.kde.plasma.components 0.1 as PlasmaComponents
+
+PlasmaComponents.Page {
+    height: editThing.height
+    property int implicitHeight: childrenRect.height
+    //scale: 1.25
+
+    tools: PlasmaComponents.ToolBarLayout {
+        spacing: 5
+        PlasmaComponents.Label {
+            text: "Text label:"
+        }
+        PlasmaComponents.ToolButton {
+            text: "ToolButton"
+        }
+        PlasmaComponents.TextField {
+            placeholderText: "Place holder text"
+        }
+        PlasmaComponents.TextField {
+            text: "Text fields page"
+        }
+    }
+    MouseArea {
+        anchors.fill: editThing
+        onClicked: editThing.forceActiveFocus();
+    }
+
+    Column {
+        id: editThing
+        anchors.top: parent.top
+        anchors.horizontalCenter: parent.horizontalCenter
+        width: 300
+        height: 300
+
+        spacing: 12
+        Item { height: 4; width: parent.width; }
+        PlasmaComponents.TextField {
+            placeholderText: "Try copy & paste"
+            text: "The cat bites into the socks"
+            width: parent.width
+            clearButtonShown: true
+        }
+        PlasmaComponents.TextArea {
+            width: parent.width
+            height: 200
+            placeholderText: "Touch copy & paste not implemented yet."
+        }
+    }
+}
diff --git a/plasma/declarativeimports/test/gallery/Texts.qml b/plasma/declarativeimports/test/gallery/Texts.qml
index 53c3993..ed4d219 100644
--- a/plasma/declarativeimports/test/gallery/Texts.qml
+++ b/plasma/declarativeimports/test/gallery/Texts.qml
@@ -59,6 +59,7 @@ PlasmaComponents.Page {
                     PlasmaComponents.TextField {
                         id: tf1
                         placeholderText: "login"
+                        clearButtonShown: true
                         Keys.onTabPressed: tf2.forceActiveFocus();
                     }
                 }
@@ -70,6 +71,7 @@ PlasmaComponents.Page {
                     }
                     PlasmaComponents.TextField {
                         id: tf2
+                        clearButtonShown: true
                         width: 120
                         echoMode: TextInput.Password
                         Keys.onTabPressed: loginButton.forceActiveFocus();
@@ -79,6 +81,7 @@ PlasmaComponents.Page {
                 PlasmaComponents.Button {
                     id: loginButton
                     text: "Login"
+                    z: -1
                     anchors {
                         right: parent.right
                         rightMargin: 0
@@ -90,6 +93,7 @@ PlasmaComponents.Page {
 
         PlasmaComponents.TextField {
             width: 120
+            clearButtonShown: true
             placeholderText: "Disabled Text Field"
             Keys.onTabPressed: loginButton.forceActiveFocus();
             enabled: false
_______________________________________________
Plasma-devel mailing list
Plasma-devel@kde.org
https://mail.kde.org/mailman/listinfo/plasma-devel

Reply via email to