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 }