/**************************************************************************** ** ** 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 } } }