ubuntu-touch-coreapps-reviewers team mailing list archive
-
ubuntu-touch-coreapps-reviewers team
-
Mailing list archive
-
Message #01874
[Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/advanced-text-editor into lp:ubuntu-docviewer-app
Stefano Verzegnassi has proposed merging lp:~verzegnassi-stefano/ubuntu-docviewer-app/advanced-text-editor into lp:ubuntu-docviewer-app.
Commit message:
Introducing a brand-new TextEditor, from DocumentViewer.Text module
Requested reviews:
Ubuntu Document Viewer Developers (ubuntu-docviewer-dev)
Related bugs:
Bug #1398773 in Ubuntu Document Viewer App: "Use a C++ class to read content from plain text files"
https://bugs.launchpad.net/ubuntu-docviewer-app/+bug/1398773
Bug #1450466 in Ubuntu Document Viewer App: "[textView] Add line numbers for TextEdit component"
https://bugs.launchpad.net/ubuntu-docviewer-app/+bug/1450466
Bug #1450467 in Ubuntu Document Viewer App: "[textView] Add textWrap option"
https://bugs.launchpad.net/ubuntu-docviewer-app/+bug/1450467
For more details, see:
https://code.launchpad.net/~verzegnassi-stefano/ubuntu-docviewer-app/advanced-text-editor/+merge/257943
- Added a new QML module that provides a new TextArea component, which will be extended in future with a syntax highlighter.
- Bumped app version to 0.4, since this update introduces a new feature.
### Details
Text files are now read by a C++ class, that works asynchronously.
Default header in TextView has been updated, and now provides a "search" action (not enabled yet), a "selection" mode and a settings page.
We provide a separated "selection" mode for the header, because of a number of issues in the UITK. See "Notes" section in this description of the change.
Text settings - the new TextEditor component supports the following settings: show line numbers, wrap text, highlight current line and show right margin at column xx.
Line numbers in TextEditor are provided by a C++ class. I preferred this implementation for keeping the code clean and fast.
DocumentHandler class is BSD licensed, and it's a fork of a demo project from Digia. BSD license is compatible with GPL v3, so there should be no issue with it.
### Notes
Here's some thoughts about the current UITK.
I had to partially fork the upstream TextArea component, because it does not provide a way to access to the "textDocument" property of the internal TextEdit (known issue).
Another issue I found is that it wasn't possible to implement the text selection used in UITK.TextArea: the components are declared as internals and/or depends on some features which are not exported via the Ubuntu.Components module.
I'd like to see the internal components of Ubuntu.Components module exposed as Ubuntu.Components.Private and/or having a blank TextEdit that uses all the goodies from UITK.
About the "text selection" mode:
There are two issues here.
A first implementation of the selection mode used the standard PageHead.actions. It seems that the actions popover in the header forwards mouse events to the component below: if an user clicks on an action (e.g. "copy), that click also affects the TextEditor below the popover, deselecting the text before it's effectively copied.
The second issue is a known one, and it's about the alignment of PageHead.contents. Actions in TextViewSelectionHeader are not aligned because of some issue in getting the parent of the layout item.
--
Your team Ubuntu Document Viewer Developers is requested to review the proposed merge of lp:~verzegnassi-stefano/ubuntu-docviewer-app/advanced-text-editor into lp:ubuntu-docviewer-app.
=== modified file 'debian/changelog'
--- debian/changelog 2015-02-23 12:49:52 +0000
+++ debian/changelog 2015-04-30 17:36:20 +0000
@@ -1,3 +1,9 @@
+ubuntu-docviewer-app (0.4.0) utopic; urgency=medium
+
+ * Improved text editor
+
+ -- Stefano Verzegnassi <verzegnassi.stefano@xxxxxxxxx> Thu, 30 Apr 2015 19:12:24 +0200
+
ubuntu-docviewer-app (0.3.0) utopic; urgency=medium
* Improved content-hub support
=== modified file 'debian/control'
--- debian/control 2015-02-23 12:49:52 +0000
+++ debian/control 2015-04-30 17:36:20 +0000
@@ -28,6 +28,7 @@
Architecture: any
Depends: qtdeclarative5-qtquick2-plugin,
qtdeclarative5-ubuntu-ui-toolkit-plugin,
+ qml-module-qt-labs-settings,
${misc:Depends}
Description: Document Viewer application
Core Document Viewer application
=== modified file 'manifest.json.in'
--- manifest.json.in 2015-02-13 15:30:01 +0000
+++ manifest.json.in 2015-04-30 17:36:20 +0000
@@ -13,7 +13,7 @@
"urls": "@URLS_FILE@"
}
},
- "version": "0.3.@BZR_REVNO@",
+ "version": "0.4.@BZR_REVNO@",
"maintainer": "Ubuntu App Cats <ubuntu-touch-coreapps@xxxxxxxxxxxxxxxxxxx>",
"x-source": {
"vcs-bzr": "@BZR_SOURCE@",
=== modified file 'po/com.ubuntu.docviewer.pot'
--- po/com.ubuntu.docviewer.pot 2015-04-27 16:02:40 +0000
+++ po/com.ubuntu.docviewer.pot 2015-04-30 17:36:20 +0000
@@ -8,7 +8,7 @@
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-04-27 18:02+0200\n"
+"POT-Creation-Date: 2015-04-30 19:09+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@xxxxxx>\n"
@@ -34,13 +34,13 @@
#: ../src/app/docviewer-application.cpp:164
#: ../src/app/qml/documentPage/DocumentPage.qml:25
-#: /home/stefano/tmp/build-ch-imported-documents-name-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
+#: /home/stefano/Progetti/doc-viewer/build-advanced-text-editor-UbuntuSDK_for_armhf_GCC_ubuntu_sdk_14_10_utopic-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
msgid "Document Viewer"
msgstr ""
#: ../src/app/qml/common/DetailsPage.qml:27
#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:97
-#: ../src/app/qml/textView/TextViewDefaultHeader.qml:83
+#: ../src/app/qml/textView/TextViewDefaultHeader.qml:104
msgid "Details"
msgstr ""
@@ -77,7 +77,7 @@
#: ../src/app/qml/common/RejectedImportDialog.qml:38
#: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:32
#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61
-#: ../src/app/qml/textView/TextViewDefaultHeader.qml:61
+#: ../src/app/qml/textView/TextViewDefaultHeader.qml:63
msgid "Close"
msgstr ""
@@ -274,7 +274,7 @@
msgstr ""
#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61
-#: ../src/app/qml/textView/TextViewDefaultHeader.qml:61
+#: ../src/app/qml/textView/TextViewDefaultHeader.qml:63
msgid "Back"
msgstr ""
@@ -283,12 +283,12 @@
msgstr ""
#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:91
-#: ../src/app/qml/textView/TextViewDefaultHeader.qml:77
+#: ../src/app/qml/textView/TextViewDefaultHeader.qml:92
msgid "Disable night mode"
msgstr ""
#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:91
-#: ../src/app/qml/textView/TextViewDefaultHeader.qml:77
+#: ../src/app/qml/textView/TextViewDefaultHeader.qml:92
msgid "Enable night mode"
msgstr ""
@@ -305,20 +305,88 @@
msgid "GO!"
msgstr ""
-#: ../src/app/qml/textView/TextView.qml:42
-msgid "Loading..."
-msgstr ""
-
-#: ../src/app/qml/ubuntu-docviewer-app.qml:183
+#: ../src/app/qml/textView/TextViewDefaultHeader.qml:86
+msgid "Enable selection mode"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewDefaultHeader.qml:98
+msgid "Settings"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewSelectionHeader.qml:36
+msgid "Select all"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewSelectionHeader.qml:42
+msgid "Paste"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewSelectionHeader.qml:48
+msgid "Cut"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewSelectionHeader.qml:54
+msgid "Copy"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewSelectionHeader.qml:60
+msgid "Redo"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewSelectionHeader.qml:67
+msgid "Undo"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewSelectionHeader.qml:75
+msgid "Exit selection mode"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewSettingsPage.qml:24
+msgid "Text settings"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewSettingsPage.qml:45
+msgid "Show line numbers"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewSettingsPage.qml:61
+msgid "Enable text wrapping"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewSettingsPage.qml:77
+msgid "Highlight current line"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewSettingsPage.qml:88
+msgid "Right margin settings"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewSettingsPage.qml:95
+msgid "Show right margin"
+msgstr ""
+
+#: ../src/app/qml/textView/TextViewSettingsPage.qml:111
+msgid "Show at column (default = 80):"
+msgstr ""
+
+#: ../src/app/qml/ubuntu-docviewer-app.qml:185
msgid "Document successfully imported!"
msgid_plural "Documents successfully imported!"
msgstr[0] ""
msgstr[1] ""
-#: ../src/app/qml/ubuntu-docviewer-app.qml:186
+#: ../src/app/qml/ubuntu-docviewer-app.qml:188
msgid "Open"
msgstr ""
-#: /home/stefano/tmp/build-ch-imported-documents-name-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
+#: ../src/plugin/text-qml-plugin/filereader.cpp:90
+msgid "Could not open file for reading."
+msgstr ""
+
+#: ../src/plugin/text-qml-plugin/filereader.cpp:107
+msgid "No file specified."
+msgstr ""
+
+#: /home/stefano/Progetti/doc-viewer/build-advanced-text-editor-UbuntuSDK_for_armhf_GCC_ubuntu_sdk_14_10_utopic-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
msgid "documents;viewer;pdf;reader;"
msgstr ""
=== modified file 'src/app/qml/textView/TextView.qml'
--- src/app/qml/textView/TextView.qml 2015-03-26 13:58:31 +0000
+++ src/app/qml/textView/TextView.qml 2015-04-30 17:36:20 +0000
@@ -16,7 +16,8 @@
import QtQuick 2.3
import Ubuntu.Components 1.1
-import Ubuntu.Components.Themes.Ambiance 0.1
+import DocumentViewer.Text 1.0
+import Qt.labs.settings 1.0
import "../common/utils.js" as Utils
@@ -24,50 +25,48 @@
id: textPage
title: Utils.getNameOfFile(file.path);
+ property bool selectionModeEnabled: false
+ property alias editor: editor
+
// Reset night mode shader settings when closing the page
// Component.onDestruction: mainView.nightModeEnabled = false
- TextArea {
- id: textAreaMain
- objectName: "textAreaMain"
-
- property bool isLoading: true
-
+ Settings {
+ property alias displayLineNumbers: editor.displayLineNumbers
+ property alias textWrap: editor.textWrap
+ property alias rightMarginAtColumn: editor.rightMarginAtColumn
+ property alias showRightMargin: editor.showRightMargin
+ property alias highlightCurrentLine: editor.highlightCurrentLine
+ }
+
+ TextReader {
+ id: reader
+ path: file.path
+
+ onErrorStringChanged: console.log(errorString)
+ }
+
+ TextEditor {
+ id: editor
anchors.fill: parent
- // FIXME: If set to true, some of the keyboard hooks are disabled
- // And it's not possible to move the cursor with arrow keys.
- readOnly: true
-
- text: i18n.tr("Loading...")
- font.family: "UbuntuMono"
-
- Component.onCompleted: {
- var xhr = new XMLHttpRequest;
-
- xhr.open("GET", file.path);
- xhr.onreadystatechange = function() {
- if (xhr.readyState === XMLHttpRequest.DONE) {
- textAreaMain.text = xhr.responseText;
- textAreaMain.isLoading = false
- }
- };
-
- xhr.send();
- }
-
- style: TextAreaStyle {
- background: Rectangle { color: "white" }
- }
+ selectionMode: textPage.selectionModeEnabled
+ text: reader.fileString
}
// *** HEADER ***
- state: "default"
states: [
TextViewDefaultHeader {
- name: "default"
- targetPage: textPage
- activityRunning: textAreaMain.isLoading
+ when: !textPage.selectionModeEnabled
+
+ targetPage: textPage
+ activityRunning: reader.status == TextReader.Loading
+ },
+
+ TextViewSelectionHeader {
+ when: textPage.selectionModeEnabled
+
+ targetPage: textPage
}
]
}
=== modified file 'src/app/qml/textView/TextViewDefaultHeader.qml'
--- src/app/qml/textView/TextViewDefaultHeader.qml 2015-03-26 13:58:31 +0000
+++ src/app/qml/textView/TextViewDefaultHeader.qml 2015-04-30 17:36:20 +0000
@@ -31,6 +31,8 @@
anchors.fill: parent
spacing: units.gu(1)
+ visible: !targetPage.selectionModeEnabled
+
ActivityIndicator { id: activity }
Column {
@@ -73,12 +75,31 @@
actions: [
Action {
+ iconName: "search"
+ // onTriggered: target.state = "search"
+ //Disable it until we provide search in Text plugin.
+ enabled: false
+ },
+
+ Action {
+ iconName: "edit-select-all"
+ text: i18n.tr("Enable selection mode")
+ onTriggered: targetPage.selectionModeEnabled = true
+ },
+
+ Action {
iconName: "night-mode"
text: mainView.nightModeEnabled ? i18n.tr("Disable night mode") : i18n.tr("Enable night mode")
onTriggered: mainView.nightModeEnabled = !mainView.nightModeEnabled
},
Action {
+ iconName: "settings"
+ text: i18n.tr("Settings")
+ onTriggered: pageStack.push(Qt.resolvedUrl("TextViewSettingsPage.qml"), { textPage: targetPage })
+ },
+
+ Action {
objectName: "detailsAction"
text: i18n.tr("Details")
iconName: "info"
=== added file 'src/app/qml/textView/TextViewSelectionHeader.qml'
--- src/app/qml/textView/TextViewSelectionHeader.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/textView/TextViewSelectionHeader.qml 2015-04-30 17:36:20 +0000
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014-2015 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * 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 General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.3
+import Ubuntu.Components 1.1
+import "../upstreamComponents"
+
+PageHeadState {
+ id: rootItem
+
+ property Page targetPage
+ head: targetPage.head
+
+ contents: Row {
+ width: parent ? parent.width : 0
+ height: parent ? parent.height : 0
+
+ layoutDirection: Qt.RightToLeft
+ visible: targetPage.selectionModeEnabled
+
+ HeaderButton {
+ iconName: "edit-select-all"
+ text: i18n.tr("Select all")
+ onTriggered: targetPage.editor.selectAll()
+ }
+
+ HeaderButton {
+ iconName: "edit-paste"
+ text: i18n.tr("Paste")
+ onTriggered: targetPage.editor.paste()
+ }
+
+ HeaderButton {
+ iconName: "edit-cut"
+ text: i18n.tr("Cut")
+ onTriggered: targetPage.editor.cut()
+ }
+
+ HeaderButton {
+ iconName: "edit-copy"
+ text: i18n.tr("Copy")
+ onTriggered: targetPage.editor.copy()
+ }
+
+ HeaderButton {
+ iconName: "edit-redo"
+ text: i18n.tr("Redo")
+ onTriggered: targetPage.editor.redo()
+ enabled: targetPage.editor.canRedo
+ }
+
+ HeaderButton {
+ iconName: "edit-undo"
+ text: i18n.tr("Undo")
+ onTriggered: targetPage.editor.undo()
+ enabled: targetPage.editor.canUndo
+ }
+ }
+
+ backAction: Action {
+ iconName: "back"
+ text: i18n.tr("Exit selection mode")
+ onTriggered: {
+ targetPage.editor.deselect()
+ targetPage.selectionModeEnabled = false;
+ }
+ }
+}
=== added file 'src/app/qml/textView/TextViewSettingsPage.qml'
--- src/app/qml/textView/TextViewSettingsPage.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/textView/TextViewSettingsPage.qml 2015-04-30 17:36:20 +0000
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2015 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * 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 General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.3
+import Ubuntu.Components 1.1
+import QtQuick.Layouts 1.1
+import Ubuntu.Components.ListItems 1.0 as ListItem
+
+Page {
+ id: textSettingsPage
+ title: i18n.tr("Text settings")
+
+ property var textPage
+
+ Component.onCompleted: {
+ // Get settings
+ lineNumbersCheckBox.checked = textPage.editor.displayLineNumbers
+ textWrapCheckbox.checked = textPage.editor.textWrap
+ highlightCurrentLineCheckbox.checked = textPage.editor.highlightCurrentLine
+ rightMarginCheckbox.checked = textPage.editor.showRightMargin
+ rightMarginTextField.text = textPage.editor.rightMarginAtColumn
+ }
+
+ Column {
+ anchors.fill: parent
+
+ ListItem.Base {
+ RowLayout {
+ anchors.fill: parent
+
+ Label {
+ text: i18n.tr("Show line numbers")
+ Layout.fillWidth: true
+ }
+
+ CheckBox {
+ id: lineNumbersCheckBox
+ onCheckedChanged: textPage.editor.displayLineNumbers = checked;
+ }
+ }
+ }
+
+ ListItem.Base {
+ RowLayout {
+ anchors.fill: parent
+
+ Label {
+ text: i18n.tr("Enable text wrapping")
+ Layout.fillWidth: true
+ }
+
+ CheckBox {
+ id: textWrapCheckbox
+ onCheckedChanged: textPage.editor.textWrap = checked
+ }
+ }
+ }
+
+ ListItem.Base {
+ RowLayout {
+ anchors.fill: parent
+
+ Label {
+ text: i18n.tr("Highlight current line")
+ Layout.fillWidth: true
+ }
+
+ CheckBox {
+ id: highlightCurrentLineCheckbox
+ onCheckedChanged: textPage.editor.highlightCurrentLine = checked
+ }
+ }
+ }
+
+ ListItem.Header { text: i18n.tr("Right margin settings") }
+
+ ListItem.Base {
+ RowLayout {
+ anchors.fill: parent
+
+ Label {
+ text: i18n.tr("Show right margin")
+ Layout.fillWidth: true
+ }
+
+ CheckBox {
+ id: rightMarginCheckbox
+ onCheckedChanged: textPage.editor.showRightMargin = checked
+ }
+ }
+ }
+
+ ListItem.Base {
+ RowLayout {
+ anchors.fill: parent
+
+ Label {
+ text: i18n.tr("Show at column (default = 80):")
+
+ Layout.fillWidth: true
+ }
+
+ TextField {
+ id: rightMarginTextField
+ implicitWidth: units.gu(12)
+ inputMethodHints: Qt.ImhDigitsOnly
+ validator: IntValidator { bottom: 1; top: 150 }
+
+ onTextChanged: textPage.editor.rightMarginAtColumn = parseInt(text)
+ }
+ }
+ }
+ }
+}
=== modified file 'src/app/qml/ubuntu-docviewer-app.qml'
--- src/app/qml/ubuntu-docviewer-app.qml 2015-04-14 14:16:16 +0000
+++ src/app/qml/ubuntu-docviewer-app.qml 2015-04-30 17:36:20 +0000
@@ -34,7 +34,9 @@
applicationName: "com.ubuntu.docviewer"
useDeprecatedToolbar: false
+
automaticOrientation: true
+ anchorToKeyboard: true
width: units.gu(50)
height: units.gu(75)
=== modified file 'src/plugin/CMakeLists.txt'
--- src/plugin/CMakeLists.txt 2014-10-20 21:38:36 +0000
+++ src/plugin/CMakeLists.txt 2015-04-30 17:36:20 +0000
@@ -1,2 +1,3 @@
add_subdirectory(file-qml-plugin)
add_subdirectory(poppler-qml-plugin)
+add_subdirectory(text-qml-plugin)
=== added directory 'src/plugin/text-qml-plugin'
=== added file 'src/plugin/text-qml-plugin/CMakeLists.txt'
--- src/plugin/text-qml-plugin/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/plugin/text-qml-plugin/CMakeLists.txt 2015-04-30 17:36:20 +0000
@@ -0,0 +1,38 @@
+set(PLUGIN_DIR DocumentViewer/Text)
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+#add QML resources
+file(GLOB_RECURSE QML_SRCS
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ *.qml *.js qmldir
+)
+
+#add the sources to compile
+set(textqmlplugin_SRCS
+ backend.cpp
+ documenthandler.cpp
+ filereader.cpp
+ ${QML_SRCS}
+)
+
+add_library(textqmlplugin MODULE ${textqmlplugin_SRCS})
+qt5_use_modules(textqmlplugin Qml Quick)
+
+# Copy the plugin, the qmldir file and other assets to the build dir for running in QtCreator
+if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
+ add_custom_command(TARGET textqmlplugin POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/qmldir ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/LineNumberColumn.qml ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/TextEditor.qml ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/TextEditorStyle.qml ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:textqmlplugin> ${CMAKE_CURRENT_BINARY_DIR}/../${PLUGIN_DIR}
+ )
+endif(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
+
+# Install plugin file
+install(TARGETS textqmlplugin DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN_DIR})
+install(FILES ${QML_SRCS} DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN_DIR})
=== added file 'src/plugin/text-qml-plugin/LineNumberColumn.qml'
--- src/plugin/text-qml-plugin/LineNumberColumn.qml 1970-01-01 00:00:00 +0000
+++ src/plugin/text-qml-plugin/LineNumberColumn.qml 2015-04-30 17:36:20 +0000
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * 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 General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.3
+import Ubuntu.Components 1.1
+
+Rectangle {
+ id: lineColumn
+
+ width: visible ? units.gu(3.5) + lineNumberRepeater.itemAt(lineNumberRepeater.count - 1).paintedWidth : 0
+
+ property int topMargin
+ property alias model: lineNumberRepeater.model
+ property var font
+
+ property alias dividerColor: divider.color
+ property alias dividerWidth: divider.width
+ property color fontColor
+
+ Rectangle {
+ id: divider
+ height: parent.height
+ anchors.right: parent.right
+ color: lineColumn.dividerColor
+ }
+
+ Column {
+ id: layout
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ topMargin: lineColumn.topMargin
+ rightMargin: units.gu(2)
+ leftMargin: units.gu(1.5)
+ }
+
+ Repeater {
+ id: lineNumberRepeater
+
+ delegate: Text {
+ width: layout.width
+ height: modelData.lineHeight
+ text: modelData.lineNumber + 1
+
+ horizontalAlignment: Text.AlignRight
+
+ font: lineColumn.font
+ color: lineColumn.fontColor
+ }
+ }
+ }
+}
=== added file 'src/plugin/text-qml-plugin/TextEditor.qml'
--- src/plugin/text-qml-plugin/TextEditor.qml 1970-01-01 00:00:00 +0000
+++ src/plugin/text-qml-plugin/TextEditor.qml 2015-04-30 17:36:20 +0000
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2015 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * 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 General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.3
+import Ubuntu.Components 1.1
+import DocumentViewer.Text 1.0
+
+StyledItem {
+ id: rootItem
+
+ property alias text: textArea.text
+ property alias readOnly: textArea.readOnly
+
+ property alias mouseSelectionMode: textArea.mouseSelectionMode
+ property alias selectionMode: textArea.selectByMouse
+
+ property bool displayLineNumbers: true
+ property bool textWrap: false
+ property int rightMarginAtColumn: 80
+ property bool showRightMargin: true
+ property bool highlightCurrentLine: false
+
+ property alias canPaste: textArea.canPaste
+ property alias canRedo: textArea.canRedo
+ property alias canUndo: textArea.canUndo
+
+ // functions
+ /*!
+ Copies the currently selected text to the system clipboard.
+ */
+ function copy()
+ {
+ textArea.copy();
+ }
+
+ /*!
+ Moves the currently selected text to the system clipboard.
+ */
+ function cut()
+ {
+ textArea.cut();
+ }
+
+ /*!
+ Removes active text selection.
+ */
+ function deselect()
+ {
+ textArea.deselect();
+ }
+
+ /*!
+ Inserts text into the TextArea at position.
+ */
+ function insert(position, text)
+ {
+ textArea.insert(position, text);
+ }
+
+ /*!
+ Returns the text position closest to pixel position (x, y).
+
+ Position 0 is before the first character, position 1 is after the first
+ character but before the second, and so on until position text.length,
+ which is after all characters.
+ */
+ function positionAt(x, y)
+ {
+ return textArea.positionAt(x, y);
+ }
+
+ /*!
+ Returns true if the natural reading direction of the textArea text found
+ between positions start and end is right to left.
+ */
+ function isRightToLeft(start, end)
+ {
+ return textArea.isRightToLeft(start, end)
+ }
+
+ /*!
+ Moves the cursor to position and updates the selection according to the
+ optional mode parameter. (To only move the cursor, set the cursorPosition
+ property.)
+
+ When this method is called it additionally sets either the selectionStart
+ or the selectionEnd (whichever was at the previous cursor position) to the
+ specified position. This allows you to easily extend and contract the selected
+ text range.
+
+ The selection mode specifies whether the selection is updated on a per character
+ or a per word basis. If not specified the selection mode will default to whatever
+ is given in the mouseSelectionMode property.
+ */
+ function moveCursorSelection(position, mode)
+ {
+ if (mode === undefined)
+ textArea.moveCursorSelection(position, mouseSelectionMode);
+ else
+ textArea.moveCursorSelection(position, mode);
+ }
+
+ /*!
+ Places the clipboard or the data given as parameter into the text input.
+ The selected text will be replaces with the data.
+ */
+ function paste(data) {
+ if ((data !== undefined) && (typeof data === "string") && !textArea.readOnly) {
+ var selTxt = textArea.selectedText;
+ var txt = textArea.text;
+ var pos = (selTxt !== "") ? txt.indexOf(selTxt) : textArea.cursorPosition
+ if (selTxt !== "") {
+ textArea.text = txt.substring(0, pos) + data + txt.substr(pos + selTxt.length);
+ } else {
+ textArea.text = txt.substring(0, pos) + data + txt.substr(pos);
+ }
+ textArea.cursorPosition = pos + data.length;
+ } else
+ textArea.paste();
+ }
+
+ /*!
+ Returns the rectangle at the given position in the text. The x, y, and height
+ properties correspond to the cursor that would describe that position.
+ */
+ function positionToRectangle(position)
+ {
+ return textArea.positionToRectangle(position);
+ }
+
+ /*!
+ Redoes the last operation if redo is \l{canRedo}{available}.
+ */
+ function redo()
+ {
+ textArea.redo();
+ }
+
+ /*!
+ Causes the text from start to end to be selected.
+
+ If either start or end is out of range, the selection is not changed.
+
+ After calling this, selectionStart will become the lesser and selectionEnd
+ will become the greater (regardless of the order passed to this method).
+
+ See also selectionStart and selectionEnd.
+ */
+ function select(start, end)
+ {
+ textArea.select(start, end);
+ }
+
+ /*!
+ Causes all text to be selected.
+ */
+ function selectAll()
+ {
+ textArea.selectAll();
+ }
+
+ /*!
+ Causes the word closest to the current cursor position to be selected.
+ */
+ function selectWord()
+ {
+ textArea.selectWord();
+ }
+
+ /*!
+ Returns the section of text that is between the start and end positions.
+
+ The returned text does not include any rich text formatting. A getText(0, length)
+ will result in the same value as displayText.
+ */
+ function getText(start, end)
+ {
+ return textArea.getText(start, end);
+ }
+
+ /*!
+ Removes the section of text that is between the start and end positions
+ from the TextEditor.
+ */
+ function remove(start, end)
+ {
+ return textArea.remove(start, end);
+ }
+
+ /*!
+ Undoes the last operation if undo is \l{canUndo}{available}. Deselects
+ any current selection, and updates the selection start to the current
+ cursor position.
+ */
+ function undo()
+ {
+ textArea.undo();
+ }
+
+ clip: true
+ style: Qt.createComponent("TextEditorStyle.qml", rootItem)
+
+ LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft
+ LayoutMirroring.childrenInherit: true
+
+ Rectangle {
+ color: rootItem.__styleInstance.backgroundColor
+ anchors.fill: parent
+
+ Rectangle {
+ visible: rootItem.showRightMargin && (rootItem.rightMarginAtColumn > 0)
+ color: rootItem.__styleInstance.secondaryBackgroundColor
+
+ anchors {
+ fill: parent
+ leftMargin: dummyFont.paintedWidth * rootItem.rightMarginAtColumn + lineColumn.width + flicker.margin - flicker.contentX
+ }
+
+ Rectangle {
+ height: parent.height
+ anchors.left: parent.left
+ width: rootItem.__styleInstance.dividerWidth
+ color: rootItem.__styleInstance.dividerColor
+ }
+ }
+
+ Rectangle {
+ width: parent.width
+ height: textArea.cursorRectangle.height
+
+ y: textArea.cursorRectangle.y + flicker.margin - flicker.contentY
+ color: rootItem.__styleInstance.currentLineHighlightColor
+ opacity: 0.3
+
+ visible: rootItem.highlightCurrentLine && textArea.cursorVisible
+ }
+ }
+
+ Flickable {
+ id: flicker
+ anchors.fill: parent
+
+ property int margin: rootItem.__styleInstance.frameSpacing
+
+ contentWidth: textArea.paintedWidth + lineColumn.width
+ contentHeight: textArea.paintedHeight + flicker.margin * 2
+
+ boundsBehavior: Flickable.StopAtBounds
+
+ LineNumberColumn {
+ id: lineColumn
+
+ color: rootItem.__styleInstance.secondaryBackgroundColor
+ dividerColor: rootItem.__styleInstance.dividerColor
+ fontColor: rootItem.__styleInstance.selectedTextColor
+ dividerWidth: rootItem.__styleInstance.dividerWidth
+
+ visible: rootItem.displayLineNumbers
+ model: documentHandler.lineBlocks
+ font: textArea.font
+
+ height: Math.max(flicker.contentHeight, flicker.height)
+ topMargin: flicker.margin
+ }
+
+ TextEdit {
+ id: textArea
+
+ focus: true
+ width: rootItem.width - lineColumn.width
+ height: Math.max(textArea.contentHeight, textArea.contentHeight)
+ anchors {
+ left: lineColumn.right
+ top: parent.top
+ margins: flicker.margin
+ }
+
+ mouseSelectionMode: TextEdit.SelectWords
+ selectByMouse: false
+ activeFocusOnPress: true
+
+ color: rootItem.__styleInstance.color
+ selectedTextColor: rootItem.__styleInstance.selectedTextColor
+ selectionColor: rootItem.__styleInstance.selectionColor
+
+ // Work as a code editor
+ textFormat: TextEdit.PlainText
+ font.family: "UbuntuMono"
+ font.pixelSize: FontUtils.sizeToPixels("medium")
+
+ wrapMode: rootItem.textWrap ? TextEdit.Wrap
+ : TextEdit.NoWrap
+ }
+ }
+
+ Label {
+ id: dummyFont
+ text: "a"
+ font: textArea.font
+ visible: false
+ }
+
+ DocumentHandler {
+ id: documentHandler
+ textEditItem: textArea
+ }
+
+ Scrollbar {
+ id: rightScrollbar
+ flickableItem: flicker
+ }
+
+ Scrollbar {
+ id: bottomScrollbar
+ flickableItem: flicker
+ align: Qt.AlignBottom
+ }
+}
+
=== added file 'src/plugin/text-qml-plugin/TextEditorStyle.qml'
--- src/plugin/text-qml-plugin/TextEditorStyle.qml 1970-01-01 00:00:00 +0000
+++ src/plugin/text-qml-plugin/TextEditorStyle.qml 2015-04-30 17:36:20 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * 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 General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.3
+import Ubuntu.Components 1.1
+
+Item {
+ id: visuals
+
+ property color backgroundColor: "white"
+ property color secondaryBackgroundColor: "#f2f2f2"
+ property color dividerColor: "#ddd"
+ property color currentLineHighlightColor: UbuntuColors.blue
+
+ property color color: styledItem.activeFocus ? Theme.palette.selected.fieldText : Theme.palette.normal.fieldText
+ property color selectedTextColor: Theme.palette.selected.foregroundText
+ property color selectionColor: Theme.palette.selected.foreground
+
+ property real frameSpacing: units.gu(1)
+ property real dividerWidth: units.gu(0.1)
+}
+
=== added file 'src/plugin/text-qml-plugin/backend.cpp'
--- src/plugin/text-qml-plugin/backend.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/text-qml-plugin/backend.cpp 2015-04-30 17:36:20 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013-2015 Canonical, Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <QtQml>
+#include <QtQml/QQmlContext>
+
+#include "backend.h"
+#include "documenthandler.h"
+#include "filereader.h"
+
+void BackendPlugin::registerTypes(const char *uri)
+{
+ Q_ASSERT(uri == QLatin1String("DocumentViewer.Text"));
+
+ //@uri DocumentViewer.Text
+ qmlRegisterType<FileReader>(uri, 1, 0, "TextReader");
+ qmlRegisterType<DocumentHandler>(uri, 1, 0, "DocumentHandler");
+}
+
+void BackendPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
+{
+ QQmlExtensionPlugin::initializeEngine(engine, uri);
+}
=== added file 'src/plugin/text-qml-plugin/backend.h'
--- src/plugin/text-qml-plugin/backend.h 1970-01-01 00:00:00 +0000
+++ src/plugin/text-qml-plugin/backend.h 2015-04-30 17:36:20 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013-2015 Canonical, Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BACKEND_PLUGIN_H
+#define BACKEND_PLUGIN_H
+
+#include <QtQml/QQmlEngine>
+#include <QtQml/QQmlExtensionPlugin>
+
+class BackendPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
+
+public:
+ void registerTypes(const char *uri);
+ void initializeEngine(QQmlEngine *engine, const char *uri);
+};
+#endif // BACKEND_PLUGIN_H
+
=== added file 'src/plugin/text-qml-plugin/documenthandler.cpp'
--- src/plugin/text-qml-plugin/documenthandler.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/text-qml-plugin/documenthandler.cpp 2015-04-30 17:36:20 +0000
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Quick Controls module of the Qt Toolkit.
+**
+** $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 Digia Plc 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$
+**
+****************************************************************************/
+
+#include "documenthandler.h"
+
+#include <QtGui/QTextDocument>
+#include <QtGui/QTextBlock>
+#include <QtGui/QTextLayout>
+
+DocumentHandler::DocumentHandler() :
+ m_textEditItem(nullptr),
+ m_doc(nullptr)
+{
+ //
+}
+
+void DocumentHandler::setTextEditItem(QQuickItem *textEditItem)
+{
+ if (textEditItem == m_textEditItem)
+ return;
+
+ QString className(textEditItem->metaObject()->className());
+ if (className != "QQuickTextEdit") {
+ qWarning() << "Item passed as argument is not a QQuickTextEdit. Aborting...";
+ return;
+ }
+
+ m_doc = nullptr;
+ m_textEditItem = textEditItem;
+
+ QVariant doc = m_textEditItem->property("textDocument");
+ if (doc.canConvert<QQuickTextDocument*>()) {
+ QQuickTextDocument *qqdoc = doc.value<QQuickTextDocument*>();
+
+ if (qqdoc) {
+ m_doc = qqdoc->textDocument();
+
+ // TODO: We can also use lengthChanged() from TextEdit?
+ connect(m_doc, SIGNAL(contentsChanged()), this, SLOT(updateLineBlocks()));
+ connect(m_textEditItem, SIGNAL(contentSizeChanged()), this, SLOT(updateLineBlocks()));
+ connect(m_textEditItem, SIGNAL(wrapModeChanged()), this, SLOT(updateLineBlocks()));
+ }
+ }
+
+ Q_EMIT textEditItemChanged();
+}
+
+void DocumentHandler::updateLineBlocks()
+{
+ m_lineBlocks.clear();
+
+ QTextBlock block = m_doc->firstBlock();
+ int blockNumber = block.blockNumber();
+ qreal blockHeight;
+
+ while (blockNumber < m_doc->blockCount()) {
+ blockHeight = block.layout()->boundingRect().height();
+
+ QVariantMap map;
+ map["lineNumber"] = blockNumber;
+ map["lineHeight"] = blockHeight;
+
+ m_lineBlocks.append(map);
+
+ block = block.next();
+ blockNumber++;
+ }
+
+ Q_EMIT lineBlocksChanged();
+}
+
=== added file 'src/plugin/text-qml-plugin/documenthandler.h'
--- src/plugin/text-qml-plugin/documenthandler.h 1970-01-01 00:00:00 +0000
+++ src/plugin/text-qml-plugin/documenthandler.h 2015-04-30 17:36:20 +0000
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Quick Controls module of the Qt Toolkit.
+**
+** $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 Digia Plc 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$
+**
+****************************************************************************/
+
+#ifndef DOCUMENTHANDLER_H
+#define DOCUMENTHANDLER_H
+
+#include <QQuickTextDocument>
+
+#include <QtGui/QTextCharFormat>
+#include <QtCore/QTextCodec>
+
+#include <qqmlfile.h>
+
+QT_BEGIN_NAMESPACE
+class QTextDocument;
+QT_END_NAMESPACE
+
+class DocumentHandler : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QQuickItem *textEditItem READ textEditItem WRITE setTextEditItem NOTIFY textEditItemChanged)
+ Q_PROPERTY(QVariantList lineBlocks READ lineBlocks NOTIFY lineBlocksChanged)
+
+public:
+ DocumentHandler();
+
+ QQuickItem *textEditItem() { return m_textEditItem; }
+ void setTextEditItem(QQuickItem *textEditItem);
+
+ QVariantList lineBlocks() { return m_lineBlocks; }
+
+Q_SIGNALS:
+ void textEditItemChanged();
+ void lineBlocksChanged();
+ void highlighterChanged();
+
+private slots:
+ void updateLineBlocks();
+
+private:
+ QQuickItem *m_textEditItem;
+ QTextDocument *m_doc;
+
+ QVariantList m_lineBlocks;
+};
+
+#endif
=== added file 'src/plugin/text-qml-plugin/filereader.cpp'
--- src/plugin/text-qml-plugin/filereader.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/text-qml-plugin/filereader.cpp 2015-04-30 17:36:20 +0000
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2013, 2015 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * 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 General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QFile>
+#include <QObject>
+#include <QDebug>
+#include <QTextStream>
+
+#include "filereader.h"
+
+FileReader::FileReader(QObject *parent) :
+ QObject(parent),
+ m_path(""),
+ m_status(Status::Null)
+{
+ qRegisterMetaType<Status>("Status");
+}
+
+FileReader::~FileReader() {
+
+}
+
+void FileReader::setPath(QString path) {
+
+ if (path == m_path && path.isEmpty())
+ return;
+
+ m_path = path;
+ Q_EMIT pathChanged();
+
+ ReaderThread *p = new ReaderThread();
+ p->setFilePath(path);
+
+ connect(p, SIGNAL(fileRead(QString)), this, SLOT(setFileString(QString)));
+ connect(p, SIGNAL(errorChanged(QString)), this, SLOT(setErrorString(QString)));
+ connect(p, SIGNAL(statusChanged(Status)), this, SLOT(setStatus(Status)));
+ connect(p, SIGNAL(finished()), p, SLOT(deleteLater()));
+
+ p->start();
+}
+
+void FileReader::setFileString(QString string)
+{
+ if (m_fileString != string) {
+ m_fileString = string;
+ Q_EMIT fileStringChanged();
+ }
+}
+
+void FileReader::setStatus(Status status)
+{
+ if (m_status != status) {
+ m_status = status;
+ Q_EMIT statusChanged();
+ }
+}
+
+void FileReader::setErrorString(QString errorString)
+{
+ if (m_errorString != errorString) {
+ m_errorString = errorString;
+ Q_EMIT errorStringChanged();
+ }
+}
+
+void ReaderThread::run() {
+ if (!m_path.isEmpty()) {
+ Q_EMIT statusChanged(Status::Loading);
+
+ QFile file(m_path);
+
+ if (!file.open(QFile::ReadOnly | QFile::Text))
+ {
+ qWarning() << "Could not open file for reading.";
+
+ Q_EMIT statusChanged(Status::Error);
+ Q_EMIT errorChanged(tr("Could not open file for reading."));
+ Q_EMIT fileRead(QString(""));
+ }
+
+ QTextStream in(&file);
+ QString text = in.readAll();
+
+ file.flush();
+ file.close();
+
+ Q_EMIT statusChanged(Status::Ready);
+ Q_EMIT errorChanged(QString(""));
+ Q_EMIT fileRead(text);
+ } else {
+ qWarning() << "No file specified.";
+
+ Q_EMIT statusChanged(Status::Error);
+ Q_EMIT errorChanged(tr("No file specified."));
+ Q_EMIT fileRead(QString(""));
+ }
+}
=== added file 'src/plugin/text-qml-plugin/filereader.h'
--- src/plugin/text-qml-plugin/filereader.h 1970-01-01 00:00:00 +0000
+++ src/plugin/text-qml-plugin/filereader.h 2015-04-30 17:36:20 +0000
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2013, 2015 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * 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 General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FILEREADER_H
+#define FILEREADER_H
+
+#include <QObject>
+#include <QThread>
+
+class FileReader: public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString path READ getPath WRITE setPath NOTIFY pathChanged)
+ Q_PROPERTY(QString fileString READ getfileString NOTIFY fileStringChanged)
+ Q_PROPERTY(Status status READ getStatus NOTIFY statusChanged)
+ Q_PROPERTY(QString errorString READ getErrorString NOTIFY errorStringChanged)
+ Q_ENUMS(Status)
+
+public:
+ explicit FileReader(QObject *parent = 0);
+ ~FileReader();
+
+ enum Status
+ {
+ Null,
+ Ready,
+ Loading,
+ Error
+ };
+
+ QString getPath() { return m_path; }
+ void setPath(QString path);
+
+ QString getErrorString() { return m_errorString; }
+
+ QString getfileString() { return m_fileString; }
+
+ Status getStatus() { return m_status; }
+
+Q_SIGNALS:
+ void pathChanged();
+ void fileStringChanged();
+ void statusChanged();
+ void errorStringChanged();
+
+private slots:
+ void setFileString(QString string);
+ void setStatus(Status status);
+ void setErrorString(QString errorString);
+
+private:
+ QString m_path;
+ QString m_fileString;
+ Status m_status;
+ QString m_errorString;
+};
+
+class ReaderThread : public QThread
+{
+ Q_OBJECT
+ Q_ENUMS(Status)
+
+public:
+ enum Status
+ {
+ Null,
+ Ready,
+ Loading,
+ Error
+ };
+
+ void run();
+ void setFilePath(QString path) { m_path = path; }
+
+Q_SIGNALS:
+ void errorChanged(QString error);
+ void fileRead(QString fileString);
+ void statusChanged(Status status);
+
+private:
+ QString m_path;
+};
+
+#endif // FILEREADER_H
=== added file 'src/plugin/text-qml-plugin/qmldir'
--- src/plugin/text-qml-plugin/qmldir 1970-01-01 00:00:00 +0000
+++ src/plugin/text-qml-plugin/qmldir 2015-04-30 17:36:20 +0000
@@ -0,0 +1,7 @@
+module DocumentViewer.Text
+plugin textqmlplugin
+
+TextEditor 1.0 TextEditor.qml
+TextEditorStyle 1.0 TextEditorStyle.qml
+
+internal LineNumberColumn LineNumberColumn.qml
References