| /**************************************************************************** |
| ** |
| ** Copyright (C) 2017 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the examples of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:BSD$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** BSD License Usage |
| ** Alternatively, 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 The Qt Company Ltd 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 2.12 |
| import QtQuick.Controls 2.12 |
| import QtQuick.Window 2.0 |
| import Qt.labs.platform 1.0 |
| |
| import io.qt.examples.texteditor 1.0 |
| |
| // TODO: |
| // - make designer-friendly |
| |
| ApplicationWindow { |
| id: window |
| width: 1024 |
| height: 600 |
| visible: true |
| title: document.fileName + " - Text Editor Example" |
| |
| Component.onCompleted: { |
| x = Screen.width / 2 - width / 2 |
| y = Screen.height / 2 - height / 2 |
| } |
| |
| Shortcut { |
| sequence: StandardKey.Open |
| onActivated: openDialog.open() |
| } |
| Shortcut { |
| sequence: StandardKey.SaveAs |
| onActivated: saveDialog.open() |
| } |
| Shortcut { |
| sequence: StandardKey.Quit |
| onActivated: close() |
| } |
| Shortcut { |
| sequence: StandardKey.Copy |
| onActivated: textArea.copy() |
| } |
| Shortcut { |
| sequence: StandardKey.Cut |
| onActivated: textArea.cut() |
| } |
| Shortcut { |
| sequence: StandardKey.Paste |
| onActivated: textArea.paste() |
| } |
| Shortcut { |
| sequence: StandardKey.Bold |
| onActivated: document.bold = !document.bold |
| } |
| Shortcut { |
| sequence: StandardKey.Italic |
| onActivated: document.italic = !document.italic |
| } |
| Shortcut { |
| sequence: StandardKey.Underline |
| onActivated: document.underline = !document.underline |
| } |
| |
| MenuBar { |
| Menu { |
| title: qsTr("&File") |
| |
| MenuItem { |
| text: qsTr("&Open") |
| onTriggered: openDialog.open() |
| } |
| MenuItem { |
| text: qsTr("&Save As...") |
| onTriggered: saveDialog.open() |
| } |
| MenuItem { |
| text: qsTr("&Quit") |
| onTriggered: close() |
| } |
| } |
| |
| Menu { |
| title: qsTr("&Edit") |
| |
| MenuItem { |
| text: qsTr("&Copy") |
| enabled: textArea.selectedText |
| onTriggered: textArea.copy() |
| } |
| MenuItem { |
| text: qsTr("Cu&t") |
| enabled: textArea.selectedText |
| onTriggered: textArea.cut() |
| } |
| MenuItem { |
| text: qsTr("&Paste") |
| enabled: textArea.canPaste |
| onTriggered: textArea.paste() |
| } |
| } |
| |
| Menu { |
| title: qsTr("F&ormat") |
| |
| MenuItem { |
| text: qsTr("&Bold") |
| checkable: true |
| checked: document.bold |
| onTriggered: document.bold = !document.bold |
| } |
| MenuItem { |
| text: qsTr("&Italic") |
| checkable: true |
| checked: document.italic |
| onTriggered: document.italic = !document.italic |
| } |
| MenuItem { |
| text: qsTr("&Underline") |
| checkable: true |
| checked: document.underline |
| onTriggered: document.underline = !document.underline |
| } |
| } |
| } |
| |
| FileDialog { |
| id: openDialog |
| fileMode: FileDialog.OpenFile |
| selectedNameFilter.index: 1 |
| nameFilters: ["Text files (*.txt)", "HTML files (*.html *.htm)", "Markdown files (*.md *.markdown)"] |
| folder: StandardPaths.writableLocation(StandardPaths.DocumentsLocation) |
| onAccepted: document.load(file) |
| } |
| |
| FileDialog { |
| id: saveDialog |
| fileMode: FileDialog.SaveFile |
| defaultSuffix: document.fileType |
| nameFilters: openDialog.nameFilters |
| selectedNameFilter.index: document.fileType === "txt" ? 0 : 1 |
| folder: StandardPaths.writableLocation(StandardPaths.DocumentsLocation) |
| onAccepted: document.saveAs(file) |
| } |
| |
| FontDialog { |
| id: fontDialog |
| onAccepted: { |
| document.fontFamily = font.family; |
| document.fontSize = font.pointSize; |
| } |
| } |
| |
| ColorDialog { |
| id: colorDialog |
| currentColor: "black" |
| } |
| |
| MessageDialog { |
| id: errorDialog |
| } |
| |
| MessageDialog { |
| id : quitDialog |
| title: qsTr("Quit?") |
| text: qsTr("The file has been modified. Quit anyway?") |
| buttons: (MessageDialog.Yes | MessageDialog.No) |
| onYesClicked: Qt.quit() |
| } |
| |
| header: ToolBar { |
| leftPadding: 8 |
| |
| Flow { |
| id: flow |
| width: parent.width |
| |
| Row { |
| id: fileRow |
| ToolButton { |
| id: openButton |
| text: "\uF115" // icon-folder-open-empty |
| font.family: "fontello" |
| onClicked: openDialog.open() |
| } |
| ToolSeparator { |
| contentItem.visible: fileRow.y === editRow.y |
| } |
| } |
| |
| Row { |
| id: editRow |
| ToolButton { |
| id: copyButton |
| text: "\uF0C5" // icon-docs |
| font.family: "fontello" |
| focusPolicy: Qt.TabFocus |
| enabled: textArea.selectedText |
| onClicked: textArea.copy() |
| } |
| ToolButton { |
| id: cutButton |
| text: "\uE802" // icon-scissors |
| font.family: "fontello" |
| focusPolicy: Qt.TabFocus |
| enabled: textArea.selectedText |
| onClicked: textArea.cut() |
| } |
| ToolButton { |
| id: pasteButton |
| text: "\uF0EA" // icon-paste |
| font.family: "fontello" |
| focusPolicy: Qt.TabFocus |
| enabled: textArea.canPaste |
| onClicked: textArea.paste() |
| } |
| ToolSeparator { |
| contentItem.visible: editRow.y === formatRow.y |
| } |
| } |
| |
| Row { |
| id: formatRow |
| ToolButton { |
| id: boldButton |
| text: "\uE800" // icon-bold |
| font.family: "fontello" |
| focusPolicy: Qt.TabFocus |
| checkable: true |
| checked: document.bold |
| onClicked: document.bold = !document.bold |
| } |
| ToolButton { |
| id: italicButton |
| text: "\uE801" // icon-italic |
| font.family: "fontello" |
| focusPolicy: Qt.TabFocus |
| checkable: true |
| checked: document.italic |
| onClicked: document.italic = !document.italic |
| } |
| ToolButton { |
| id: underlineButton |
| text: "\uF0CD" // icon-underline |
| font.family: "fontello" |
| focusPolicy: Qt.TabFocus |
| checkable: true |
| checked: document.underline |
| onClicked: document.underline = !document.underline |
| } |
| ToolButton { |
| id: fontFamilyToolButton |
| text: qsTr("\uE808") // icon-font |
| font.family: "fontello" |
| font.bold: document.bold |
| font.italic: document.italic |
| font.underline: document.underline |
| onClicked: { |
| fontDialog.currentFont.family = document.fontFamily; |
| fontDialog.currentFont.pointSize = document.fontSize; |
| fontDialog.open(); |
| } |
| } |
| ToolButton { |
| id: textColorButton |
| text: "\uF1FC" // icon-brush |
| font.family: "fontello" |
| focusPolicy: Qt.TabFocus |
| onClicked: colorDialog.open() |
| |
| Rectangle { |
| width: aFontMetrics.width + 3 |
| height: 2 |
| color: document.textColor |
| parent: textColorButton.contentItem |
| anchors.horizontalCenter: parent.horizontalCenter |
| anchors.baseline: parent.baseline |
| anchors.baselineOffset: 6 |
| |
| TextMetrics { |
| id: aFontMetrics |
| font: textColorButton.font |
| text: textColorButton.text |
| } |
| } |
| } |
| ToolSeparator { |
| contentItem.visible: formatRow.y === alignRow.y |
| } |
| } |
| |
| Row { |
| id: alignRow |
| ToolButton { |
| id: alignLeftButton |
| text: "\uE803" // icon-align-left |
| font.family: "fontello" |
| focusPolicy: Qt.TabFocus |
| checkable: true |
| checked: document.alignment == Qt.AlignLeft |
| onClicked: document.alignment = Qt.AlignLeft |
| } |
| ToolButton { |
| id: alignCenterButton |
| text: "\uE804" // icon-align-center |
| font.family: "fontello" |
| focusPolicy: Qt.TabFocus |
| checkable: true |
| checked: document.alignment == Qt.AlignHCenter |
| onClicked: document.alignment = Qt.AlignHCenter |
| } |
| ToolButton { |
| id: alignRightButton |
| text: "\uE805" // icon-align-right |
| font.family: "fontello" |
| focusPolicy: Qt.TabFocus |
| checkable: true |
| checked: document.alignment == Qt.AlignRight |
| onClicked: document.alignment = Qt.AlignRight |
| } |
| ToolButton { |
| id: alignJustifyButton |
| text: "\uE806" // icon-align-justify |
| font.family: "fontello" |
| focusPolicy: Qt.TabFocus |
| checkable: true |
| checked: document.alignment == Qt.AlignJustify |
| onClicked: document.alignment = Qt.AlignJustify |
| } |
| } |
| } |
| } |
| |
| DocumentHandler { |
| id: document |
| document: textArea.textDocument |
| cursorPosition: textArea.cursorPosition |
| selectionStart: textArea.selectionStart |
| selectionEnd: textArea.selectionEnd |
| textColor: colorDialog.color |
| Component.onCompleted: { |
| if (Qt.application.arguments.length === 2) |
| document.load("file:" + Qt.application.arguments[1]); |
| else |
| document.load("qrc:/texteditor.html") |
| } |
| onLoaded: { |
| textArea.textFormat = format |
| textArea.text = text |
| } |
| onError: { |
| errorDialog.text = message |
| errorDialog.visible = true |
| } |
| } |
| |
| Flickable { |
| id: flickable |
| flickableDirection: Flickable.VerticalFlick |
| anchors.fill: parent |
| |
| TextArea.flickable: TextArea { |
| id: textArea |
| textFormat: Qt.RichText |
| wrapMode: TextArea.Wrap |
| focus: true |
| selectByMouse: true |
| persistentSelection: true |
| // Different styles have different padding and background |
| // decorations, but since this editor is almost taking up the |
| // entire window, we don't need them. |
| leftPadding: 6 |
| rightPadding: 6 |
| topPadding: 0 |
| bottomPadding: 0 |
| background: null |
| |
| MouseArea { |
| acceptedButtons: Qt.RightButton |
| anchors.fill: parent |
| onClicked: contextMenu.open() |
| } |
| |
| onLinkActivated: Qt.openUrlExternally(link) |
| } |
| |
| ScrollBar.vertical: ScrollBar {} |
| } |
| |
| Menu { |
| id: contextMenu |
| |
| MenuItem { |
| text: qsTr("Copy") |
| enabled: textArea.selectedText |
| onTriggered: textArea.copy() |
| } |
| MenuItem { |
| text: qsTr("Cut") |
| enabled: textArea.selectedText |
| onTriggered: textArea.cut() |
| } |
| MenuItem { |
| text: qsTr("Paste") |
| enabled: textArea.canPaste |
| onTriggered: textArea.paste() |
| } |
| |
| MenuSeparator {} |
| |
| MenuItem { |
| text: qsTr("Font...") |
| onTriggered: fontDialog.open() |
| } |
| |
| MenuItem { |
| text: qsTr("Color...") |
| onTriggered: colorDialog.open() |
| } |
| } |
| |
| onClosing: { |
| if (document.modified) { |
| quitDialog.open() |
| close.accepted = false |
| } |
| } |
| } |