Warning, /maui/nota/src/views/editor/EditorView.qml is written in an unsupported language. File is not indexed.
0001 import QtQuick 2.14
0002 import QtQuick.Controls 2.13
0003 import QtQuick.Layouts 1.3
0004
0005 import org.mauikit.controls 1.3 as Maui
0006 import org.mauikit.filebrowsing 1.3 as FB
0007 import org.mauikit.texteditor 1.0 as TE
0008
0009 import org.maui.nota 1.0 as Nota
0010
0011 Pane
0012 {
0013 id: control
0014
0015 readonly property alias count: _tabView.count
0016
0017 readonly property alias currentTab : _tabView.currentItem
0018 readonly property bool currentFileExistsLocally : FB.FM.fileExists(control.currentEditor.fileUrl)
0019 readonly property TE.TextEditor currentEditor: currentTab ? currentTab.currentItem.editor : null
0020
0021 readonly property alias listView: _tabView
0022 readonly property alias plugin: _pluginLayout
0023 readonly property alias model : _tabView.contentModel
0024 readonly property alias tabView : _tabView
0025
0026 padding: 0
0027
0028 Action
0029 {
0030 id: _openFileAction
0031 icon.name: "folder-open"
0032 text: i18n("Open Files")
0033 onTriggered:
0034 {
0035 openFileDialog()
0036 }
0037 }
0038
0039 Action
0040 {
0041 id: _openRecentFileAction
0042 icon.name: "folder-recent"
0043 text: i18n("Open Recent Files")
0044 onTriggered:
0045 {
0046 _stackView.push(historyViewComponent)
0047 }
0048 }
0049
0050 Action
0051 {
0052 id: _newFileAction
0053 icon.name: "list-add"
0054 text: i18n("New")
0055 onTriggered:
0056 {
0057 editorView.openTab("")
0058 }
0059 }
0060
0061 contentItem: ColumnLayout
0062 {
0063 id: _pluginLayout
0064 spacing: 0
0065
0066 Maui.TabView
0067 {
0068 id: _tabView
0069 Layout.fillWidth: true
0070 Layout.fillHeight: true
0071
0072 altTabBar: !root.isWide
0073
0074 holder.emoji: "qrc:/img/document-edit.svg"
0075
0076 holder.title: i18n("Create a New Document")
0077 holder.body: i18n("You can create or open a new document.")
0078 holder.actions: [_newFileAction, _openFileAction, _openRecentFileAction]
0079
0080 Connections
0081 {
0082 target: _tabView.holder
0083 function onContentDropped(drop)
0084 {
0085 if(drop.urls)
0086 {
0087 for(var url of drop.urls)
0088 control.openTab(url)
0089 }
0090 }
0091 }
0092 tabBar.visible: true
0093 tabBar.showNewTabButton: false
0094 tabBar.leftContent: Loader
0095 {
0096 active: settings.enableSidebar
0097 visible: active
0098 asynchronous: true
0099
0100 sourceComponent: ToolButton
0101 {
0102 icon.name: _sideBarView.sideBar.visible ? "sidebar-collapse" : "sidebar-expand"
0103 onClicked: _sideBarView.sideBar.toggle()
0104
0105 text: i18n("Places")
0106 display: isWide ? ToolButton.TextBesideIcon : ToolButton.IconOnly
0107
0108 checked: _sideBarView.sideBar.visible
0109
0110 ToolTip.delay: 1000
0111 ToolTip.timeout: 5000
0112 ToolTip.visible: hovered
0113 ToolTip.text: i18n("Toogle SideBar")
0114 }
0115 }
0116
0117 tabBar.rightContent: [
0118
0119 ToolButton
0120 {
0121 text: _tabView.count
0122 visible: _tabView.count > 1
0123 font.bold: true
0124 font.pointSize: Maui.Style.fontSizes.small
0125 onClicked: _tabView.openOverview()
0126 background: Rectangle
0127 {
0128 color: Maui.Theme.alternateBackgroundColor
0129 radius: Maui.Style.radiusV
0130 }
0131 },
0132
0133 Loader
0134 {
0135 asynchronous: true
0136 sourceComponent: Maui.ToolButtonMenu
0137 {
0138 icon.name: "list-add"
0139
0140 MenuItem
0141 {
0142 action: _newFileAction
0143 }
0144
0145 MenuItem
0146 {
0147 action: _openFileAction
0148 }
0149
0150 MenuItem
0151 {
0152 action: _openRecentFileAction
0153 }
0154
0155 MenuSeparator {}
0156
0157 Maui.MenuItemActionRow
0158 {
0159 Action
0160 {
0161 icon.name: checked ? "view-readermode-active" : "view-readermode"
0162 text: i18n("Focus")
0163 checked: root.focusMode
0164 checkable: true
0165 onTriggered: root.focusMode = !root.focusMode
0166 }
0167
0168 Action
0169 {
0170 text: i18n("Terminal")
0171 icon.name: "dialog-scripts"
0172 enabled: Maui.Handy.isLinux
0173 onTriggered: currentTab.toggleTerminal()
0174 checkable: true
0175 checked: currentTab ? currentTab.terminalVisible : false
0176 }
0177
0178 Action
0179 {
0180 enabled: settings.supportSplit
0181 text: i18n("Split View")
0182 icon.name: root.currentTab.orientation === Qt.Horizontal ? "view-split-left-right" : "view-split-top-bottom"
0183 checked: root.currentTab && root.currentTab.count === 2
0184 checkable: true
0185 onTriggered:
0186 {
0187 if(root.currentTab.count === 2)
0188 {
0189 root.currentTab.pop()
0190 return
0191 }//close the inactive split
0192
0193 root.currentTab.split("")
0194 }
0195 }
0196 }
0197
0198 MenuSeparator {}
0199
0200 MenuItem
0201 {
0202 text: i18n("Shortcuts")
0203 icon.name: "configure-shortcuts"
0204 onTriggered:
0205 {
0206 _dialogLoader.sourceComponent = _shortcutsDialogComponent
0207 dialog.open()
0208 }
0209 }
0210
0211 MenuItem
0212 {
0213 text: i18n("Settings")
0214 icon.name: "settings-configure"
0215 onTriggered:
0216 {
0217 _dialogLoader.sourceComponent = _settingsDialogComponent
0218 dialog.open()
0219 }
0220 }
0221
0222 MenuItem
0223 {
0224 text: i18n("Plugins")
0225 icon.name: "system-run"
0226 onTriggered:
0227 {
0228 _dialogLoader.sourceComponent = _plugingsDialogComponent
0229 dialog.open()
0230 }
0231 }
0232
0233 MenuItem
0234 {
0235 text: i18n("About")
0236 icon.name: "documentinfo"
0237 onTriggered: root.about()
0238 }
0239 }
0240 },
0241
0242 Maui.WindowControls {}
0243 ]
0244
0245 tabViewButton: Maui.TabViewButton
0246 {
0247 id: _tabButton
0248 tabView: _tabView
0249 onClicked:
0250 {
0251 if(_tabButton.mindex === _tabView.currentIndex)
0252 {
0253 _docMenuLoader.item.show((width*0.5)-(_docMenuLoader.item.width*0.5), height + Maui.Style.space.medium)
0254 return
0255 }
0256
0257 _tabView.setCurrentIndex(_tabButton.mindex)
0258 _tabView.currentItem.forceActiveFocus()
0259 }
0260
0261 rightContent: Maui.Icon
0262 {
0263 visible: _tabButton.checked
0264 source: "overflow-menu"
0265 height: Maui.Style.iconSizes.small
0266 width: height
0267 }
0268
0269 onCloseClicked:
0270 {
0271 _tabView.closeTabClicked(_tabButton.mindex)
0272 }
0273
0274 Component
0275 {
0276 id: _infoDialogComponent
0277
0278 Maui.PopupPage
0279 {
0280 id: _infoDialog
0281 property var info: FB.FM.getFileInfo(currentEditor.fileUrl)
0282
0283 onClosed: destroy()
0284 Maui.SectionItem
0285 {
0286 label1.text: i18n("Name")
0287 label2.text: _infoDialog.info.name
0288 }
0289
0290 Maui.SectionItem
0291 {
0292 label1.text: i18n("Date")
0293 label2.text: _infoDialog.info.date
0294 }
0295
0296 Maui.SectionItem
0297 {
0298 label1.text: i18n("Modified")
0299 label2.text: _infoDialog.info.modified
0300 }
0301
0302 Maui.SectionItem
0303 {
0304 label1.text: i18n("Size")
0305 label2.text: Maui.Handy.formatSize(_infoDialog.info.size)
0306 }
0307
0308 Maui.SectionItem
0309 {
0310 label1.text: i18n("Type")
0311 label2.text:_infoDialog.info.mime
0312 }
0313 }
0314 }
0315
0316 Component
0317 {
0318 id: _goToLineDialogComponent
0319
0320 Maui.InputDialog
0321 {
0322 title: i18n("Go to Line")
0323 textEntry.text: currentEditor.document.currentLineIndex+1
0324 textEntry.placeholderText: i18n("Line number")
0325 onFinished: currentEditor.goToLine(text)
0326 }
0327 }
0328
0329 Component
0330 {
0331 id: _removeDialogComponent
0332
0333 Maui.InfoDialog
0334 {
0335
0336 title: i18n("Delete File?")
0337 message: i18n("Are sure you want to delete \n%1", currentEditor.fileUrl)
0338
0339 standardButtons: Dialog.Yes | Dialog.Cancel
0340
0341 template.iconSource: "dialog-question"
0342 template.iconVisible: true
0343
0344 onRejected: close()
0345 onAccepted:
0346 {
0347 FB.FM.deleteFile(currentEditor.fileUrl)
0348 }
0349 }
0350 }
0351
0352 Loader
0353 {
0354 id: _docMenuLoader
0355 asynchronous: true
0356 sourceComponent: Maui.ContextualMenu
0357 {
0358 Maui.MenuItemActionRow
0359 {
0360 Action
0361 {
0362 icon.name: "edit-undo"
0363 text: i18n("Undo")
0364 enabled: currentEditor.body.canUndo
0365 onTriggered: currentEditor.body.undo()
0366 }
0367
0368 Action
0369 {
0370 icon.name: "edit-redo"
0371 text: i18n("Redo")
0372 enabled: currentEditor.body.canRedo
0373 onTriggered: currentEditor.body.redo()
0374 }
0375
0376
0377 Action
0378 {
0379 text: i18n("Save")
0380 icon.name: "document-save"
0381 enabled: currentEditor ? currentEditor.document.modified : false
0382 onTriggered: saveFile(currentEditor.fileUrl, currentEditor)
0383 }
0384
0385 Action
0386 {
0387 icon.name: "document-save-as"
0388 text: i18n("Save as")
0389 onTriggered: saveFile("", currentEditor)
0390 }
0391 }
0392
0393 MenuSeparator {}
0394
0395 MenuItem
0396 {
0397 icon.name: "edit-find"
0398 text: i18n("Find and Replace")
0399 checkable: true
0400
0401 onTriggered:
0402 {
0403 currentEditor.showFindBar = !currentEditor.showFindBar
0404 }
0405 checked: currentEditor.showFindBar
0406 }
0407
0408 MenuItem
0409 {
0410 icon.name: "document-edit"
0411 text: i18n("Line/Word Counter")
0412 checkable: true
0413
0414 onTriggered:
0415 {
0416 settings.showWordCount = !settings.showWordCount
0417 }
0418
0419 checked: settings.showWordCount
0420 }
0421
0422 MenuSeparator {}
0423
0424 Maui.MenuItemActionRow
0425 {
0426 Action
0427 {
0428 property bool isFav: FB.Tagging.isFav(currentEditor.fileUrl)
0429 text: i18n(isFav ? "UnFav it": "Fav it")
0430 checked: isFav
0431 checkable: true
0432 icon.name: "love"
0433 enabled: currentFileExistsLocally
0434 onTriggered:
0435 {
0436 FB.Tagging.toggleFav(currentEditor.fileUrl)
0437 isFav = FB.Tagging.isFav(currentEditor.fileUrl)
0438 }
0439 }
0440
0441 Action
0442 {
0443 enabled: currentFileExistsLocally
0444 text: i18n("Info")
0445 icon.name: "documentinfo"
0446 onTriggered:
0447 {
0448
0449 var dialog = _infoDialogComponent.createObject(control)
0450 dialog.open()
0451
0452 }
0453 }
0454
0455 Action
0456 {
0457 text: i18n("Share")
0458 enabled: currentFileExistsLocally
0459 icon.name: "document-share"
0460 onTriggered: Maui.Platform.shareFiles([currentEditor.fileUrl])
0461
0462 }
0463 }
0464
0465 MenuSeparator {}
0466
0467 MenuItem
0468 {
0469 icon.name: "go-jump"
0470 text: i18n("Go to Line")
0471
0472 onTriggered:
0473 {
0474 _dialogLoader.sourceComponent = _goToLineDialogComponent
0475 dialog.open()
0476 }
0477 }
0478
0479 MenuItem
0480 {
0481 enabled: currentFileExistsLocally
0482 text: i18n("Show in Folder")
0483 icon.name: "folder-open"
0484 onTriggered:
0485 {
0486 FB.FM.openLocation([currentEditor.fileUrl])
0487 }
0488 }
0489
0490 MenuItem
0491 {
0492 text: i18n("Delete File")
0493 icon.name: "edit-delete"
0494 enabled: currentFileExistsLocally
0495 Maui.Theme.textColor: Maui.Theme.negativeTextColor
0496
0497 onTriggered:
0498 {
0499 _dialogLoader.sourceComponent = _removeDialogComponent
0500 dialog.open()
0501 }
0502 }
0503 }
0504 }
0505 }
0506
0507 onNewTabClicked: control.openTab("")
0508 onCloseTabClicked: (index) =>
0509 {
0510 if( tabHasUnsavedFiles(index))
0511 {
0512 _dialogLoader.sourceComponent = _unsavedDialogComponent
0513 dialog.callback = function () { closeTab(index) }
0514
0515 if(tabHasUnsavedFiles(index))
0516 {
0517 dialog.open()
0518 return
0519 }
0520 }
0521 else
0522 {
0523 closeTab(index)
0524 }
0525 }
0526 }
0527 }
0528
0529 Component
0530 {
0531 id: _editorLayoutComponent
0532 EditorLayout {}
0533 }
0534
0535 function unsavedTabSplits(index) //which split indexes are unsaved
0536 {
0537 var indexes = []
0538 const tab = control.model.get(index)
0539 for(var i = 0; i < tab.count; i++)
0540 {
0541 if(tab.model.get(i).editor.document.modified)
0542 {
0543 indexes.push(i)
0544 }
0545 }
0546 return indexes
0547 }
0548
0549 function tabHasUnsavedFiles(index) //if a tab has at least one unsaved file in a split
0550 {
0551 return unsavedTabSplits(index).length
0552 }
0553
0554 function fileIndex(path) //find the [tab, split] index for a path
0555 {
0556 if(path.length === 0)
0557 {
0558 return [-1, -1]
0559 }
0560
0561 for(var i = 0; i < control.count; i++)
0562 {
0563 const tab = control.model.get(i)
0564 for(var j = 0; j < tab.count; j++)
0565 {
0566 const doc = tab.model.get(j)
0567 if(doc.fileUrl.toString() === path)
0568 {
0569 return [i, j]
0570 }
0571 }
0572 }
0573 return [-1,-1]
0574 }
0575
0576 function openTab(path)
0577 {
0578 if(_stackView.depth === 2)
0579 {
0580 _stackView.pop()
0581 }
0582
0583 const index = fileIndex(path)
0584
0585 if(index[0] >= 0)
0586 {
0587 _tabView.currentIndex = index[0]
0588 currentTab.currentIndex = index[1]
0589 return
0590 }
0591
0592 _tabView.addTab(_editorLayoutComponent, {"path": path})
0593 historyList.append(path)
0594 }
0595
0596 function closeTab(index) //no questions asked
0597 {
0598 _tabView.closeTab(index)
0599 }
0600
0601 function saveFile(path, item)
0602 {
0603 if(!item)
0604 return
0605
0606 if (path && FB.FM.fileExists(path))
0607 {
0608 item.document.saveAs(path)
0609 } else
0610 {
0611 _dialogLoader.sourceComponent = _fileDialogComponent
0612 dialog.mode = dialog.modes.SAVE;
0613 // fileDialog.settings.singleSelection = true
0614 dialog.callback = function (paths)
0615 {
0616 item.document.saveAs(paths[0])
0617 historyList.append(paths[0])
0618 };
0619
0620 dialog.open()
0621 }
0622 }
0623
0624 function isUrlOpen(url : string) : bool
0625 {
0626 return fileIndex(url)[0] >= 0;
0627 }
0628 }