qtdeclarative/examples/quickcontrols/texteditor/qml/texteditor.qml

531 lines
16 KiB
QML

// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Dialogs
// TODO:
// - make designer-friendly
ApplicationWindow {
id: window
width: 1024
height: 600
visible: true
title: textArea.textDocument.source +
" - Text Editor Example" + (textArea.textDocument.modified ? " *" : "")
Action {
id: openAction
text: qsTr("&Open")
shortcut: StandardKey.Open
onTriggered: {
if (textArea.textDocument.modified)
discardDialog.open()
else
openDialog.open()
}
}
Action {
id: saveAction
text: qsTr("&Save…")
shortcut: StandardKey.Save
enabled: textArea.textDocument.modified
onTriggered: textArea.textDocument.save()
}
Action {
id: saveAsAction
text: qsTr("Save &As…")
shortcut: StandardKey.SaveAs
onTriggered: saveDialog.open()
}
Action {
id: quitAction
text: qsTr("&Quit")
shortcut: StandardKey.Quit
onTriggered: close()
}
Action {
id: copyAction
text: qsTr("&Copy")
shortcut: StandardKey.Copy
enabled: textArea.selectedText
onTriggered: textArea.copy()
}
Action {
id: cutAction
text: qsTr("Cu&t")
shortcut: StandardKey.Cut
enabled: textArea.selectedText
onTriggered: textArea.cut()
}
Action {
id: pasteAction
text: qsTr("&Paste")
shortcut: StandardKey.Paste
enabled: textArea.canPaste
onTriggered: textArea.paste()
}
Action {
id: boldAction
text: qsTr("&Bold")
shortcut: StandardKey.Bold
checkable: true
checked: textArea.cursorSelection.font.bold
onTriggered: textArea.cursorSelection.font.bold = checked
}
Action {
id: italicAction
text: qsTr("&Italic")
shortcut: StandardKey.Italic
checkable: true
checked: textArea.cursorSelection.font.italic
onTriggered: textArea.cursorSelection.font.italic = checked
}
Action {
id: underlineAction
text: qsTr("&Underline")
shortcut: StandardKey.Underline
checkable: true
checked: textArea.cursorSelection.font.underline
onTriggered: textArea.cursorSelection.font.underline = checked
}
Action {
id: strikeoutAction
text: qsTr("&Strikeout")
checkable: true
checked: textArea.cursorSelection.font.strikeout
onTriggered: textArea.cursorSelection.font.strikeout = checked
}
Action {
id: alignLeftAction
text: qsTr("Align &Left")
shortcut: "Ctrl+{"
checkable: true
checked: textArea.cursorSelection.alignment === Qt.AlignLeft
onTriggered: textArea.cursorSelection.alignment = Qt.AlignLeft
}
Action {
id: alignCenterAction
text: qsTr("&Center")
shortcut: "Ctrl+|"
checkable: true
checked: textArea.cursorSelection.alignment === Qt.AlignCenter
onTriggered: textArea.cursorSelection.alignment = Qt.AlignCenter
}
Action {
id: alignRightAction
text: qsTr("Align &Right")
shortcut: "Ctrl+}"
checkable: true
checked: textArea.cursorSelection.alignment === Qt.AlignRight
onTriggered: textArea.cursorSelection.alignment = Qt.AlignRight
}
Action {
id: alignJustifyAction
text: qsTr("&Justify")
shortcut: "Ctrl+Alt+}"
checkable: true
checked: textArea.cursorSelection.alignment === Qt.AlignJustify
onTriggered: textArea.cursorSelection.alignment = Qt.AlignJustify
}
Action {
id: fontDialogAction
text: qsTr("Fon&t…")
shortcut: "Ctrl+T"
onTriggered: {
fontDialog.selectedFont = textArea.cursorSelection.font
fontDialog.open()
}
}
Action {
id: colorDialogAction
text: qsTr("Color…")
shortcut: "Ctrl+Shift+C"
onTriggered: {
colorDialog.selectedColor = textArea.cursorSelection.color
colorDialog.open()
}
}
Component {
id: menuSeparatorComponent
MenuSeparator {}
}
menuBar: MenuBar {
Menu {
title: qsTr("&File")
MenuItem {
action: openAction
}
MenuItem {
action: saveAction
}
MenuItem {
action: saveAsAction
}
MenuItem {
action: quitAction
}
}
Menu {
title: qsTr("&Edit")
MenuItem {
action: copyAction
}
MenuItem {
action: cutAction
}
MenuItem {
action: pasteAction
}
}
Menu {
title: qsTr("F&ormat")
MenuItem {
action: boldAction
}
MenuItem {
action: italicAction
}
MenuItem {
action: underlineAction
}
MenuItem {
action: strikeoutAction
}
MenuItem {
action: fontDialogAction
}
MenuItem {
action: colorDialogAction
}
MenuSeparator {}
MenuItem {
action: alignLeftAction
}
MenuItem {
action: alignCenterAction
}
MenuItem {
action: alignJustifyAction
}
MenuItem {
action: alignRightAction
}
}
}
FileDialog {
id: openDialog
fileMode: FileDialog.OpenFile
selectedNameFilter.index: 1
nameFilters: ["Text files (*.txt)", "HTML files (*.html *.htm)", "Markdown files (*.md *.markdown)"]
currentFolder: StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
onAccepted: {
textArea.textDocument.modified = false // we asked earlier, if necessary
textArea.textDocument.source = selectedFile
}
}
FileDialog {
id: saveDialog
fileMode: FileDialog.SaveFile
nameFilters: openDialog.nameFilters
currentFolder: StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
onAccepted: textArea.textDocument.saveAs(selectedFile)
}
FontDialog {
id: fontDialog
onAccepted: textArea.cursorSelection.font = selectedFont
}
ColorDialog {
id: colorDialog
selectedColor: textArea.cursorSelection.color
onAccepted: textArea.cursorSelection.color = selectedColor
}
MessageDialog {
title: qsTr("Error")
id: errorDialog
}
MessageDialog {
id : quitDialog
title: qsTr("Quit?")
text: qsTr("The file has been modified. Quit anyway?")
buttons: MessageDialog.Yes | MessageDialog.No
onButtonClicked: function (button, role) {
if (role === MessageDialog.YesRole) {
textArea.textDocument.modified = false
Qt.quit()
}
}
}
MessageDialog {
id : discardDialog
title: qsTr("Discard changes?")
text: qsTr("The file has been modified. Open a new file anyway?")
buttons: MessageDialog.Yes | MessageDialog.No
onButtonClicked: function (button, role) {
if (role === MessageDialog.YesRole)
openDialog.open()
}
}
header: ToolBar {
Flow {
width: parent.width
Row {
id: fileRow
ToolButton {
id: openButton
text: "\uF115" // icon-folder-open-empty
font.family: "fontello"
action: openAction
focusPolicy: Qt.TabFocus
}
ToolButton {
id: saveButton
text: "\uE80A" // icon-floppy-disk
font.family: "fontello"
action: saveAction
focusPolicy: Qt.TabFocus
}
ToolSeparator {
contentItem.visible: fileRow.y === editRow.y
}
}
Row {
id: editRow
ToolButton {
id: copyButton
text: "\uF0C5" // icon-docs
font.family: "fontello"
focusPolicy: Qt.TabFocus
action: copyAction
}
ToolButton {
id: cutButton
text: "\uE802" // icon-scissors
font.family: "fontello"
focusPolicy: Qt.TabFocus
action: cutAction
}
ToolButton {
id: pasteButton
text: "\uF0EA" // icon-paste
font.family: "fontello"
focusPolicy: Qt.TabFocus
action: pasteAction
}
ToolSeparator {
contentItem.visible: editRow.y === formatRow.y
}
}
Row {
id: formatRow
ToolButton {
id: boldButton
text: "\uE800" // icon-bold
font.family: "fontello"
focusPolicy: Qt.TabFocus
action: boldAction
}
ToolButton {
id: italicButton
text: "\uE801" // icon-italic
font.family: "fontello"
focusPolicy: Qt.TabFocus
action: italicAction
}
ToolButton {
id: underlineButton
text: "\uF0CD" // icon-underline
font.family: "fontello"
focusPolicy: Qt.TabFocus
action: underlineAction
}
ToolButton {
id: strikeoutButton
text: "\uF0CC"
font.family: "fontello"
focusPolicy: Qt.TabFocus
action: strikeoutAction
}
ToolButton {
id: fontFamilyToolButton
text: qsTr("\uE808") // icon-font
font.family: "fontello"
font.bold: textArea.cursorSelection.font.bold
font.italic: textArea.cursorSelection.font.italic
font.underline: textArea.cursorSelection.font.underline
font.strikeout: textArea.cursorSelection.font.strikeout
focusPolicy: Qt.TabFocus
onClicked: function () {
fontDialog.selectedFont = textArea.cursorSelection.font
fontDialog.open()
}
}
ToolButton {
id: textColorButton
text: "\uF1FC" // icon-brush
font.family: "fontello"
focusPolicy: Qt.TabFocus
onClicked: function () {
colorDialog.selectedColor = textArea.cursorSelection.color
colorDialog.open()
}
Rectangle {
width: aFontMetrics.width + 3
height: 2
color: textArea.cursorSelection.color
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
action: alignLeftAction
}
ToolButton {
id: alignCenterButton
text: "\uE804" // icon-align-center
font.family: "fontello"
focusPolicy: Qt.TabFocus
action: alignCenterAction
}
ToolButton {
id: alignRightButton
text: "\uE805" // icon-align-right
font.family: "fontello"
focusPolicy: Qt.TabFocus
action: alignRightAction
}
ToolButton {
id: alignJustifyButton
text: "\uE806" // icon-align-justify
font.family: "fontello"
focusPolicy: Qt.TabFocus
action: alignJustifyAction
}
}
}
}
Flickable {
id: flickable
flickableDirection: Flickable.VerticalFlick
anchors.fill: parent
ScrollBar.vertical: ScrollBar {}
TextArea.flickable: TextArea {
id: textArea
textFormat: Qt.AutoText
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
onLinkActivated: function (link) {
Qt.openUrlExternally(link)
}
Component.onCompleted: {
if (Qt.application.arguments.length === 2)
textDocument.source = "file:" + Qt.application.arguments[1]
else
textDocument.source = "qrc:/texteditor.html"
const menu = textArea.ContextMenu.menu
menu.addItem(menuSeparatorComponent.createObject(menu.contentItem))
menu.addAction(fontDialogAction)
menu.addAction(colorDialogAction)
}
textDocument.onStatusChanged: {
// a message lookup table using computed properties:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer
const statusMessages = {
[ TextDocument.ReadError ]: qsTr("Failed to load “%1”"),
[ TextDocument.WriteError ]: qsTr("Failed to save “%1”"),
[ TextDocument.NonLocalFileError ]: qsTr("Not a local file: “%1”"),
}
const err = statusMessages[textDocument.status]
if (err) {
errorDialog.text = err.arg(textDocument.source)
errorDialog.open()
}
}
}
}
onClosing: function (close) {
if (textArea.textDocument.modified) {
quitDialog.open()
close.accepted = false
}
}
}