diff --git a/blackMosquito.png b/blackMosquito.png index 68821071..16c5d2a6 100644 Binary files a/blackMosquito.png and b/blackMosquito.png differ diff --git a/buttleofx/MainWindow.qml b/buttleofx/MainWindow.qml index 9f1069a2..2e9d3e85 100644 --- a/buttleofx/MainWindow.qml +++ b/buttleofx/MainWindow.qml @@ -1,10 +1,10 @@ -import QtQuick 2.0 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 import QtQml 2.1 +import QtQuick 2.0 import QuickMamba 1.0 -import QtQuick.Dialogs 1.1 import QtQuick.Window 2.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 import QtQuick.LocalStorage 2.0 import "gui/graph/qml" @@ -13,6 +13,7 @@ import "gui/paramEditor/qml" import "gui/browser_v2/qml" import "gui/plugin/qml" import "gui/shortcut/qml" +import "gui/dialogs" ApplicationWindow { property var settingsDatabase: getInitializedDatabase() @@ -72,19 +73,16 @@ ApplicationWindow { property string urlOfFileToSave: _buttleData.urlOfFileToSave - // TopFocusHandler { // anchors.fill: parent // } Keys.onPressed: { - // Viewer if ((event.key == Qt.Key_1) && (event.modifiers & Qt.KeypadModifier)) { player.changeViewer(1) } if ((event.key == Qt.Key_2) && (event.modifiers & Qt.KeypadModifier)) { - player.changeViewer(2) } if ((event.key == Qt.Key_3) && (event.modifiers & Qt.KeypadModifier)) { @@ -119,15 +117,15 @@ ApplicationWindow { } } - property bool aNodeIsSelected:true + property bool aNodeIsSelected: true // Window of hint for plugins PluginWindow { id: doc title: "Plugin's Documentation" - selectedNodeLabel: _buttleData.currentSelectedNodeWrappers.count!=0 ? _buttleData.currentSelectedNodeWrappers.get(0).name : "" - selectedNodeDoc: _buttleData.currentSelectedNodeWrappers.count!=0 ? _buttleData.currentSelectedNodeWrappers.get(0).pluginDoc : "" - selectedNodeGroup: _buttleData.currentSelectedNodeWrappers.count!=0 ? _buttleData.currentSelectedNodeWrappers.get(0).pluginGroup : "" + selectedNodeLabel: _buttleData.currentSelectedNodeWrappers.count != 0 ? _buttleData.currentSelectedNodeWrappers.get(0).name : "" + selectedNodeDoc: _buttleData.currentSelectedNodeWrappers.count != 0 ? _buttleData.currentSelectedNodeWrappers.get(0).pluginDoc : "" + selectedNodeGroup: _buttleData.currentSelectedNodeWrappers.count != 0 ? _buttleData.currentSelectedNodeWrappers.get(0).pluginGroup : "" } // Window of shortcuts @@ -136,103 +134,58 @@ ApplicationWindow { title: "Shortcuts" } - FileDialog { + BrowserOpenDialog{ id: finderLoadGraph - title: "Open a graph" - nameFilters: [ "All files (*)" ] - selectedNameFilter: "All files (*)" - - onAccepted: { - if (finderLoadGraph.fileUrl) { - _buttleData.loadData(finderLoadGraph.fileUrl) - } - } } - FileDialog { + BrowserSaveDialog{ id: finderSaveGraph - title: "Save the graph" - nameFilters: [ "All files (*)" ] - selectedNameFilter: "All files (*)" - - onAccepted: { - if (finderSaveGraph.fileUrl) { - _buttleData.saveData(finderSaveGraph.fileUrl) - } - } - - selectExisting: false } - MessageDialog { + ExitDialog { id: openGraph - title:"Save the graph?" - icon: StandardIcon.Warning - modality: Qt.WindowStaysOnTopHint && Qt.WindowModal - text: urlOfFileToSave == "" ? "Save graph changes before closing ?" : "Save " + _buttleData.getFileName(urlOfFileToSave) + " changes before closing ?" - detailedText: "If you don't save the graph, unsaved modifications will be lost. " - standardButtons: StandardButton.Yes | StandardButton.No | StandardButton.Abort - Component.onCompleted: visible = false - - onYes: { - if(urlOfFileToSave!="") { + visible: false + dialogText: "Do you want to save before closing this file?
If you don't, all unsaved changes will be lost" + + onSaveButtonClicked: { + if (urlOfFileToSave != "") { _buttleData.saveData(urlOfFileToSave) - } else{ - finderSaveGraph.open() + } else { + finderSaveGraph.show("open") } } - onNo: { - finderLoadGraph.open() + onDiscardButtonClicked: { + finderLoadGraph.visible = true } - onRejected: {} } - MessageDialog { + ExitDialog { id: newGraph - title: "Save the graph?" - icon: StandardIcon.Warning - modality: Qt.WindowStaysOnTopHint && Qt.WindowModal - text: urlOfFileToSave == "" ? "Save graph changes before closing ?" : "Save " + _buttleData.getFileName(urlOfFileToSave) + " changes before closing ?" - detailedText: "If you don't save the graph, unsaved modifications will be lost. " - standardButtons: StandardButton.Yes | StandardButton.No | StandardButton.Abort - Component.onCompleted: visible = false - - onYes: { - if (urlOfFileToSave!="") { + visible: false + dialogText: "Do you want to save before closing this file?
If you don't, all unsaved changes will be lost" + + onSaveButtonClicked: { + if (urlOfFileToSave != "") { _buttleData.saveData(urlOfFileToSave) - _buttleData.newData() } else { - finderSaveGraph.open() - _buttleData.newData() + finderSaveGraph.show("new") } } - onNo: { - _buttleData.newData() - } + onDiscardButtonClicked: _buttleData.newData() } - MessageDialog { + ExitDialog { id: closeButtle - title: "Save the graph?" - icon: StandardIcon.Warning - modality: Qt.WindowStaysOnTopHint && Qt.WindowModal - text: urlOfFileToSave == "" ? "Save graph changes before closing ?" : "Save " + _buttleData.getFileName(urlOfFileToSave) + " changes before closing ?" - detailedText: "If you don't save the graph, unsaved modifications will be lost. " - standardButtons: StandardButton.Yes | StandardButton.No | StandardButton.Abort - Component.onCompleted: visible = false - - onYes: { - if(urlOfFileToSave!="") { + visible: false + + onSaveButtonClicked: { + if (urlOfFileToSave != "") { _buttleData.saveData(urlOfFileToSave) } else { - finderSaveGraph.open() - finderSaveGraph.close() - finderSaveGraph.open() + finderSaveGraph.show("close") } } - onNo: { - Qt.quit() - } + onDiscardButtonClicked: Qt.quit() } menuBar: MenuBar { @@ -247,7 +200,7 @@ ApplicationWindow { if (!_buttleData.graphCanBeSaved) { _buttleData.newData() } else { - newGraph.open() + newGraph.visible = true } } } @@ -258,11 +211,9 @@ ApplicationWindow { onTriggered: { if (!_buttleData.graphCanBeSaved) { - finderLoadGraph.open() + finderLoadGraph.visible = true } else { - openGraph.open() - openGraph.close() - openGraph.open() + openGraph.visible = true } } } @@ -270,14 +221,14 @@ ApplicationWindow { MenuItem { text: "Save" shortcut: "Ctrl+S" - enabled: _buttleData.graphCanBeSaved && urlOfFileToSave != "" ? true : false + enabled: _buttleData.graphCanBeSaved && urlOfFileToSave != "" onTriggered: _buttleData.saveData(urlOfFileToSave) } MenuItem { text: "Save As" shortcut: "Ctrl+Shift+S" - onTriggered: finderSaveGraph.open() + onTriggered: finderSaveGraph.visible = true } MenuSeparator { } @@ -290,7 +241,7 @@ ApplicationWindow { if (!_buttleData.graphCanBeSaved) { Qt.quit() } else { - closeButtle.open() + closeButtle.visible = true } } } @@ -303,7 +254,7 @@ ApplicationWindow { id: undoRedoStack title: "Undo/Redo stack" - property variant undoRedoList:_buttleData.graphCanBeSaved ? _buttleManager.undoRedoStack:_buttleManager.undoRedoStack + property variant undoRedoList: _buttleData.graphCanBeSaved ? _buttleManager.undoRedoStack : _buttleManager.undoRedoStack Instantiator { model: undoRedoStack.undoRedoList @@ -414,10 +365,11 @@ ApplicationWindow { title: "Nodes" Instantiator { - model: _buttleData.getMenu(1,"") + model: _buttleData.getMenu(1, "") + Menu { id: firstMenu - title:object + title: object __parentContentItem: nodesMenu.__contentItem // To remove warning Instantiator { @@ -447,11 +399,11 @@ ApplicationWindow { } Instantiator { - model: _buttleData.getMenu(2,firstMenu.title) + model: _buttleData.getMenu(2, firstMenu.title) Menu { id: secondMenu - title:object + title: object __parentContentItem: nodesMenu.__contentItem // To remove warning Instantiator { @@ -481,11 +433,11 @@ ApplicationWindow { } Instantiator { - model: _buttleData.getMenu(3,secondMenu.title) + model: _buttleData.getMenu(3, secondMenu.title) Menu { id: thirdMenu - title:object + title: object __parentContentItem: nodesMenu.__contentItem // To remove warning Instantiator { @@ -515,10 +467,10 @@ ApplicationWindow { } Instantiator { - model: _buttleData.getMenu(4,thirdMenu.title) + model: _buttleData.getMenu(4, thirdMenu.title) Menu { - id:fourthMenu + id: fourthMenu title: object __parentContentItem: nodesMenu.__contentItem // To remove warning @@ -549,7 +501,7 @@ ApplicationWindow { } Instantiator { - model: _buttleData.getMenu(5,fourthMenu.title) + model: _buttleData.getMenu(5, fourthMenu.title) Menu { id: fifthMenu @@ -622,7 +574,6 @@ ApplicationWindow { } } - Menu { title: "View" @@ -704,29 +655,41 @@ ApplicationWindow { MenuItem { text: "Browser" checkable: true - checked: browser.parent.visible==true ? true : false - onTriggered: browser.parent.visible == false ? browser.parent.visible=true : browser.parent.visible=false + checked: browser.parent.visible + + onTriggered: { + browser.parent.visible = !browser.parent.visible + } } MenuItem { text: "Viewer" checkable: true - checked: player.parent.visible==true ? true : false - onTriggered: player.parent.visible == false ? player.parent.visible=true : player.parent.visible=false + checked: player.parent.visible + + onTriggered: { + player.parent.visible = !player.parent.visible + } } MenuItem { text: "Graph" checkable: true - checked: graphEditor.parent.visible==true ? true : false - onTriggered: graphEditor.parent.visible == false ? graphEditor.parent.visible=true : graphEditor.parent.visible=false + checked: graphEditor.parent.visible + + onTriggered: { + graphEditor.parent.visible = !graphEditor.parent.visible + } } MenuItem { text: "Parameters" checkable: true - checked: paramEditor.parent.visible==true ? true : false - onTriggered: paramEditor.parent.visible == false ? paramEditor.parent.visible=true : paramEditor.parent.visible=false + checked: paramEditor.parent.visible + + onTriggered: { + paramEditor.parent.visible = !paramEditor.parent.visible + } } */ } @@ -743,7 +706,6 @@ ApplicationWindow { } */ - // This rectangle represents the zone under the menu, it allows to define the anchors.fill and margins for the SplitterRow Rectangle { id: modulsContainer @@ -816,6 +778,7 @@ ApplicationWindow { z: -1 visible: selectedView == 1 || selectedView == 2 children: lastSelectedView[3] + } } } @@ -825,7 +788,7 @@ ApplicationWindow { id: subviews visible: false - property variant parentBeforeFullscreen : null + property variant parentBeforeFullscreen: null Player { id: player @@ -841,7 +804,7 @@ ApplicationWindow { } } onButtonFullscreenClicked: - if (parent != fullscreenContent){ + if (parent != fullscreenContent) { subviews.parentBeforeFullscreen = parent fullscreenWindow.visibility = Window.FullScreen fullscreenContent.children = player @@ -861,7 +824,7 @@ ApplicationWindow { } } onButtonFullscreenClicked: - if (parent != fullscreenContent){ + if (parent != fullscreenContent) { subviews.parentBeforeFullscreen = parent fullscreenWindow.visibility = Window.FullScreen fullscreenContent.children = graphEditor @@ -883,7 +846,7 @@ ApplicationWindow { } } onButtonFullscreenClicked: - if (parent != fullscreenContent){ + if (parent != fullscreenContent) { subviews.parentBeforeFullscreen = parent fullscreenWindow.visibility = Window.FullScreen fullscreenContent.children = paramEditor @@ -903,7 +866,7 @@ ApplicationWindow { } } onButtonFullscreenClicked: - if (parent != fullscreenContent){ + if (parent != fullscreenContent) { subviews.parentBeforeFullscreen = parent fullscreenWindow.visibility = Window.FullScreen fullscreenContent.children = advancedParamEditor @@ -930,6 +893,12 @@ ApplicationWindow { fullscreenContent.children = browser } } + + Connections{ + target: browser.fileWindow + onItemClicked: isSupported ? browser.fileWindow.onItemClickedSlot(pathImg) : 0 + onItemDoubleClicked: isSupported ? browser.fileWindow.onItemDoubleClickedSlot(absolutePath) : 0 + } } Item { diff --git a/buttleofx/data/buttleData.py b/buttleofx/data/buttleData.py index 755cd73b..4dcf31bc 100644 --- a/buttleofx/data/buttleData.py +++ b/buttleofx/data/buttleData.py @@ -524,9 +524,8 @@ def loadData(self, url='buttleofx/backup/data.bofx'): """ Loads all data from a Json file (the default Json file if no url is given) """ - - filepath = QtCore.QUrl(url).toLocalFile() - + Qurl = QtCore.QUrl(url) + filepath = (Qurl.isLocalFile() and Qurl.toLocalFile()) or url self.newData() with open(filepath, 'r') as f: @@ -647,14 +646,21 @@ def saveData(self, url): """ Saves all data in a json file """ + # If called from Python, it could be a str or a QUrl if isinstance(url, str): - # If called from Python, it could be a str or a QUrl. - filepath = QtCore.QUrl.fromLocalFile(url).toLocalFile() + filepath = url else: - filepath = QtCore.QUrl(url).toLocalFile() + filepath = url.toLocalFile() if url.isLocalFile() else url.toString() + + if filepath.endswith('buttleSave_now.bofx'): + filepath = os.path.dirname(filepath) - if not filepath.lower().endswith(".bofx"): - filepath = filepath + ".bofx" + # if destination path is a folder, we create a file name containing date and time of now + if os.path.isdir(filepath): + filepath = os.path.join(filepath, 'buttleSave%s' % datetime.today().strftime('%m_%d_%y_%I_%M')) + + if not filepath.lower().endswith('.bofx'): + filepath += '.bofx' with io.open(filepath, 'w', encoding='utf-8') as f: dictJson = { @@ -675,8 +681,8 @@ def saveData(self, url): # Graph dictJson["graph"] = self.getGraph().object_to_dict() - # Graph : currentSeletedNodes - for node in self.getGraph().getNodes(): + # Graph : currentSelectedNodes + for node in self._graph.getNodes(): if node.getName() in self.getCurrentSelectedNodeNames(): dictJson["graph"]["currentSelectedNodes"].append(node.getName()) @@ -736,6 +742,9 @@ def zoom(self, width, height, nodeWidth, zoomCoeff, graphPreviousWidth, graphPre def getButtlePath(self): return self._buttlePath + def getHomeDir(self): + return os.path.expanduser("~") + def getCurrentConnectionWrapper(self): """ Returns the current currentConnectionWrapper. @@ -1036,6 +1045,7 @@ def graphCanBeSaved(self): # filePath buttlePath = QtCore.pyqtProperty(str, getButtlePath, constant=True) + homeDir = QtCore.pyqtProperty(str, getHomeDir, constant=True) # Current param, view, and selected node currentParamNodeChanged = QtCore.pyqtSignal() @@ -1092,12 +1102,12 @@ def graphCanBeSaved(self): globalButtleData = ButtleData() -def _decode_dict(dict_): +def _decode_dict(_dict): """ This function will recursively pass in nested dicts, and will convert all str elements into string (essential for some Tuttle functions). """ - for key in dict_: - if isinstance(dict_[key], str): - dict_[key] = str(dict_[key]) - return dict_ + for key in _dict: + if isinstance(_dict[key], str): + _dict[key] = str(_dict[key]) + return _dict diff --git a/buttleofx/gui/browser_v2/actions/browserAction.py b/buttleofx/gui/browser_v2/actions/browserAction.py index 4c03c186..2e423683 100644 --- a/buttleofx/gui/browser_v2/actions/browserAction.py +++ b/buttleofx/gui/browser_v2/actions/browserAction.py @@ -7,12 +7,12 @@ from buttleofx.gui.browser_v2.actions.actionManager import globalActionManager from buttleofx.gui.browser_v2.actions.actionWrapper import ActionWrapper -from buttleofx.gui.browser_v2.browserModel import globalBrowserModel from buttleofx.gui.browser_v2.browserItem import BrowserItem from buttleofx.gui.browser_v2.actions.concreteActions.copy import Copy from buttleofx.gui.browser_v2.actions.concreteActions.move import Move from buttleofx.gui.browser_v2.actions.concreteActions.create import Create from buttleofx.gui.browser_v2.actions.concreteActions.delete import Delete +from buttleofx.gui.browser_v2.browserModel import globalBrowserDialog, globalBrowser class BrowserAction(QtCore.QObject): @@ -21,11 +21,11 @@ class BrowserAction(QtCore.QObject): """ cacheChanged = QtCore.pyqtSignal() - def __init__(self): + def __init__(self, bModel): logging.debug('BrowserAction begin constructor') QtCore.QObject.__init__(self) self._cacheActions = None # for copy, move actions - self._browserModel = globalBrowserModel + self._browserModel = bModel logging.debug('BrowserAction end constructor') def pushCache(self, listActions): @@ -99,4 +99,5 @@ def handleNew(self, typeItem): isCache = QtCore.pyqtProperty(bool, isEmptyCache, notify=cacheChanged) -globalBrowserAction = BrowserAction() +globalBrowserAction = BrowserAction(globalBrowser) +globalBrowserActionDialog = BrowserAction(globalBrowserDialog) diff --git a/buttleofx/gui/browser_v2/browserModel.py b/buttleofx/gui/browser_v2/browserModel.py index c0ce20b3..9c3cf9b6 100644 --- a/buttleofx/gui/browser_v2/browserModel.py +++ b/buttleofx/gui/browser_v2/browserModel.py @@ -42,6 +42,7 @@ def __init__(self, path=op.expanduser("~/"), sync=False, showSeq=True, hideDotFi """ QtCore.QObject.__init__(self, parent) self._currentPath = path + self._bufferBrowserItems = [] # used when recursive process: fix async signal connection when add object self._browserItems = [] # used only in python side self._browserItemsModel = QObjectListModel(self) # used for UI self._filter = filterFiles @@ -98,6 +99,7 @@ def updateItems(self, recursivePattern): return self.clearItemsSync.emit() + self._bufferBrowserItems.clear() detectOption = sequenceParser.eDetectionDefaultWithDotFile if self._hideDotFiles: detectOption = sequenceParser.eDetectionDefault @@ -146,6 +148,7 @@ def pushBrowserItems(self, allItems, toModel=True): if not self._isSync: itemToAdd.moveToThread(self.thread()) self.addItemSync.emit(itemToAdd, toModel) + self._bufferBrowserItems.append(itemToAdd) @QtCore.pyqtSlot(object, bool) def onAddItemSync(self, bItem, toModel=True): @@ -174,9 +177,8 @@ def searchRecursively(self, pattern, modelRequester): if modelRequester.getParallelThread().isStopped(): return - listToBrowse = self._browserItems + listToBrowse = self._bufferBrowserItems if self == modelRequester: - listToBrowse = self._browserItems.copy() # copy: _browserItems deleted line after modelRequester.clearItemsSync.emit() for bItem in listToBrowse: # 1st pass, all files in current dir @@ -417,4 +419,5 @@ def selectItemTo(self, index): loading = QtCore.pyqtProperty(bool, isLoading, notify=loadingChanged) -globalBrowserModel = BrowserModel() +globalBrowser = BrowserModel() +globalBrowserDialog = BrowserModel() diff --git a/buttleofx/gui/browser_v2/qml/Browser.qml b/buttleofx/gui/browser_v2/qml/Browser.qml index e951a14b..fe2ffbad 100644 --- a/buttleofx/gui/browser_v2/qml/Browser.qml +++ b/buttleofx/gui/browser_v2/qml/Browser.qml @@ -9,7 +9,13 @@ Rectangle { height: 600 color: "#353535" + property alias fileWindow: fileWindow + property alias navBar: navBar + property bool showTab: true + property variant bModel: _browser + property variant bAction: _browserAction property int visitedFolderListIndex: 0 + signal buttonCloseClicked(bool clicked) signal buttonFullscreenClicked(bool clicked) @@ -22,6 +28,13 @@ Rectangle { ++ visitedFolderListIndex } + function popVisitedFolder(){ + if (visitedFolderList.count > 0 && visitedFolderListIndex > 0) { + -- visitedFolderListIndex + bModel.currentPath = visitedFolderList.get(visitedFolderListIndex).url + } + } + // Recently visited folder stack ListModel { id: visitedFolderList @@ -32,9 +45,10 @@ Rectangle { spacing: 0 Tab { - Layout.fillWidth: true id: tabBar + Layout.fillWidth: true name: "Browser" + visible: root.showTab onCloseClicked: root.buttonCloseClicked(true) onFullscreenClicked: root.buttonFullscreenClicked(true) } @@ -44,9 +58,10 @@ Rectangle { Layout.fillWidth: true Layout.preferredHeight: childrenRect.height - property var model: _browser + property var model: root.bModel property alias visitedFolderList: visitedFolderList property alias visitedFolderListIndex: root.visitedFolderListIndex + onPushVisitedFolder: { root.pushVisitedFolder(path) } @@ -54,10 +69,8 @@ Rectangle { Rectangle { id: separator - Layout.fillWidth: true Layout.preferredHeight: 1 - color: "#00b2a1" } @@ -67,7 +80,8 @@ Rectangle { Layout.fillWidth: true Layout.fillHeight: true - property var model: _browser + property var model: root.bModel + property var bAction: root.bAction property alias visitedFolderList: visitedFolderList property alias visitedFolderListIndex: root.visitedFolderListIndex @@ -76,4 +90,14 @@ Rectangle { } } } + + Keys.onPressed: { + if ((event.modifiers & Qt.ControlModifier) && (event.key == Qt.Key_L)){ + navBar.toggleUrlEdit() + } + + if (event.key == Qt.Key_Backspace){ + popVisitedFolder() + } + } } diff --git a/buttleofx/gui/browser_v2/qml/FileWindow.qml b/buttleofx/gui/browser_v2/qml/FileWindow.qml index 8d52b73d..d216b683 100644 --- a/buttleofx/gui/browser_v2/qml/FileWindow.qml +++ b/buttleofx/gui/browser_v2/qml/FileWindow.qml @@ -9,8 +9,9 @@ Rectangle { id: root color: "transparent" - //TODO: think about standalone - function handleGraphViewerClick(pathImg){ + // defaults slots + function onItemClickedSlot(pathImg){ + // handleGraphViewerClick // We come to the temporary viewer player.changeViewer(11) @@ -28,7 +29,9 @@ Rectangle { _buttleData.currentViewerIndex = 10 // We assign to the viewer the 10th view _buttleEvent.emitViewerChangedSignal() } - function handleGraphViewerDoubleClick(browserItem){ + + function onItemDoubleClickedSlot(absolutePath){ + // handleGraphViewerDoubleClick _buttleData.currentGraphWrapper = _buttleData.graphWrapper _buttleData.currentGraphIsGraph() @@ -40,12 +43,14 @@ Rectangle { _buttleData.currentViewerNodeWrapper = player.lastNodeWrapper player.changeViewer(player.lastView) } - _buttleManager.nodeManager.dropFile(browserItem.path, 10, 10) + _buttleManager.nodeManager.dropFile(absolutePath, 10, 10) } + signal itemClicked(string absolutePath, string pathImg, bool isFolder, bool isSupported) + signal itemDoubleClicked(string absolutePath, string pathImg, bool isFolder, bool isSupported) signal pushVisitedFolder(string path) - Keys.onEscapePressed: root.model.unselectAllItems() + Keys.onEscapePressed: root.model.unselectAllItems() MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton @@ -76,7 +81,7 @@ Rectangle { iconName: "edit-select-all" shortcut: StandardKey.SelectAll onTriggered: { - _browser.selectAllItems() + root.model.selectAllItems() } } @@ -85,7 +90,7 @@ Rectangle { iconName: "reload" shortcut: StandardKey.Refresh onTriggered: { - _browser.refresh() + root.model.refresh() } } MenuSeparator{} @@ -103,8 +108,8 @@ Rectangle { iconName: "folder-new" shortcut: StandardKey.New onTriggered: { - _browserAction.handleNew("Folder") - _browser.refresh() + root.bAction.handleNew("Folder") + root.model.refresh() } } MenuItem{ @@ -113,8 +118,8 @@ Rectangle { iconName: "document-new" shortcut: StandardKey.UnknownKey onTriggered: { - _browserAction.handleNew("File") - _browser.refresh() + root.bAction.handleNew("File") + root.model.refresh() } } MenuSeparator{} @@ -124,7 +129,7 @@ Rectangle { shortcut: StandardKey.Copy iconName: "edit-copy" onTriggered: { - _browserAction.handleCopy() + root.bAction.handleCopy() } } MenuItem{ @@ -133,21 +138,21 @@ Rectangle { iconName: "edit-cut" shortcut: StandardKey.Cut onTriggered: { - _browserAction.handleMove() + root.bAction.handleMove() } } MenuItem{ text:"Paste" iconName: "edit-paste" shortcut: StandardKey.Paste - enabled: _browserAction.isCache + enabled: root.bAction.isCache onTriggered: { var destination="" - if(_browser.selectedItems.count == 1 && _browser.selectedItems.get(0).isFolder()) - destination = _browser.selectedItems.get(0).path + if(root.model.selectedItems.count == 1 && root.model.selectedItems.get(0).isFolder()) + destination = root.model.selectedItems.get(0).path - _browserAction.handlePaste(destination) - _browser.refresh() + root.bAction.handlePaste(destination) + root.model.refresh() } } @@ -157,8 +162,8 @@ Rectangle { iconName: "edit-delete" shortcut: StandardKey.Deletes onTriggered: { - _browserAction.handleDelete() - _browser.refresh() + root.bAction.handleDelete() + root.model.refresh() } } @@ -323,12 +328,7 @@ Rectangle { } else if(mouse.button == Qt.LeftButton){ - if(!model.object.isFolder()){ - if (model.object.isSupported()){ - handleGraphViewerClick(model.object.path) - } - } - + root.itemClicked(model.object.path, model.object.path, model.object.isFolder(), model.object.isSupported()) if ((mouse.modifiers & Qt.ShiftModifier)) root.model.selectItemTo(index) else if ((mouse.modifiers & Qt.ControlModifier)) @@ -338,17 +338,15 @@ Rectangle { } } onDoubleClicked: { + root.itemDoubleClicked(model.object.path, model.object.path, model.object.isFolder(), model.object.isSupported()) + + // we ensure this behavior by default if (model.object.isFolder()) { pushVisitedFolder(model.object.path) root.model.currentPath = model.object.path } - - // If it's an image, we create a node - else if (model.object.isSupported()) - handleGraphViewerDoubleClick(model.object) } } - } } diff --git a/buttleofx/gui/browser_v2/qml/NavBar.qml b/buttleofx/gui/browser_v2/qml/NavBar.qml index bbe98787..44fb866b 100644 --- a/buttleofx/gui/browser_v2/qml/NavBar.qml +++ b/buttleofx/gui/browser_v2/qml/NavBar.qml @@ -7,12 +7,22 @@ import QtQuick.Controls.Styles 1.0 Rectangle { id: root color: "#2E2E2E" - clip: true signal pushVisitedFolder(string path) property alias searchLayout: searchLayoutRectangle + function toggleUrlEdit(visibility){ + visibility = visibility !== undefined ? visibility : breadCrum.visible + breadCrum.visible = !visibility + textEditContainer.visible = visibility + + if(visibility) + texteditPath.forceActiveFocus() + } + + Component.onCompleted: toggleUrlEdit(true) + QtObject { id: m; property bool searchEnabled: false @@ -43,26 +53,17 @@ Rectangle { Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter tooltip: "Previous" - iconSource: - if (hovered) - "img/previous_hover.png" - else - "img/previous.png" + iconSource: hovered ? "img/previous_hover.png" : "img/previous.png" style: - ButtonStyle { - background: Rectangle { - anchors.fill: parent - color: "transparent" + ButtonStyle { + background: Rectangle { + anchors.fill: parent + color: "transparent" + } } - } - onClicked: { - if (visitedFolderList.count > 0 && visitedFolderListIndex > 0) { - -- visitedFolderListIndex - model.currentPath = visitedFolderList.get(visitedFolderListIndex).url - } - } + onClicked: popVisitedFolder() } Button { @@ -260,7 +261,8 @@ Rectangle { } Keys.onReleased: { - if(event.key === Qt.Key_Shift || event.key === Qt.Key_Alt) + if(event.key === Qt.Key_Shift || event.key === Qt.Key_Alt || event.key === Qt.Key_Control + || (event.key === Qt.Key_Control && event.key === Qt.Key_L)) return root.model.currentPath = texteditPath.text graySuggestion.fill() @@ -311,7 +313,6 @@ Rectangle { } function show() { - console.log(root.model.listFolderNavBar.count) if(!root.model.listFolderNavBar.count) return this.__popup(0, 0) @@ -330,16 +331,10 @@ Rectangle { clip: true MouseArea { - anchors.fill: parent - propagateComposedEvents: true - onDoubleClicked: { - if (breadCrum.visible) - breadCrum.visible = false - - if (!textEditContainer.visible){ - textEditContainer.visible = true - texteditPath.forceActiveFocus() - } + anchors.fill: parent + propagateComposedEvents: true + onDoubleClicked: { + root.toggleUrlEdit() } } delegate: component @@ -513,7 +508,7 @@ Rectangle { anchors.fill: parent anchors.margins: 2 - placeholderText: "Enter your search ..." + placeholderText: "Search ..." style: TextFieldStyle { selectionColor: "#00b2a1" @@ -525,7 +520,7 @@ Rectangle { } } onAccepted: { - _browser.loadData(text.trim()) + root.model.loadData(text.trim()) } onFocusChanged: { diff --git a/buttleofx/gui/dialogs/BrowserDialog.qml b/buttleofx/gui/dialogs/BrowserDialog.qml new file mode 100644 index 00000000..122d0224 --- /dev/null +++ b/buttleofx/gui/dialogs/BrowserDialog.qml @@ -0,0 +1,40 @@ +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQml 2.1 +import QtQuick 2.0 +import QtQuick.Window 2.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 + + +import "../browser_v2/qml/" + +// common part of open and save browserDialog (Abstract behavior) +// the connecitons are done in 'subclasses' + +Window{ + id: finderBrowser + title: 'Finder Browser' + width: 630 + height: 380 + visible: false + flags: "Dialog" + modality: "ApplicationModal" + property alias browser: browser + property bool showTab: false + + Browser { + id: browser + bModel: _browserDialog + bAction: _browserActionDialog + anchors.fill: parent + showTab: finderBrowser.showTab + } + onVisibleChanged:{ + if(visible == false) + browser.bModel.stopLoading() + else + browser.navBar.toggleUrlEdit(true) + } +} diff --git a/buttleofx/gui/dialogs/BrowserOpenDialog.qml b/buttleofx/gui/dialogs/BrowserOpenDialog.qml new file mode 100644 index 00000000..d73d6ec0 --- /dev/null +++ b/buttleofx/gui/dialogs/BrowserOpenDialog.qml @@ -0,0 +1,16 @@ +import QtQuick 2.0 + +BrowserDialog{ + id: root + title: 'Open Graph' + + Connections{ + target: root.browser.fileWindow + onItemDoubleClicked:{ + if (!isFolder && absolutePath != "") { + _buttleData.loadData(absolutePath) + root.visible = false + } + } + } +} diff --git a/buttleofx/gui/dialogs/BrowserSaveDialog.qml b/buttleofx/gui/dialogs/BrowserSaveDialog.qml new file mode 100644 index 00000000..f2492bcd --- /dev/null +++ b/buttleofx/gui/dialogs/BrowserSaveDialog.qml @@ -0,0 +1,111 @@ +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQml 2.1 +import QtQuick 2.0 +import QtQuick.Window 2.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 + + +import "../browser_v2/qml/" + +// BrowserSave dialog: used to save a comp. +// the connecitons are done MainWindow.qml (i.e the Component which use this dialog) + +BrowserDialog{ + id: root + title: 'Save the Graph' + signal saveButtonClicked(string absoluteFilePath) + property variant idBrowserOpenDialog: undefined + property string action + + function show(doAction) { + root.action = doAction + root.visible = true + } + + + onSaveButtonClicked: { + if (absoluteFilePath != "") { + _buttleData.urlOfFileToSave = absoluteFilePath + _buttleData.saveData(_buttleData.urlOfFileToSave) + + root.visible = false + + if (root.action == "open" && idBrowserOpenDialog) + idBrowserOpenDialog.visible = true + else if (root.action == "new") + _buttleData.newData() + else if (root.action == "close") + Qt.quit() + } + } + + RowLayout { + id: bottomRow + Layout.fillWidth: true + Layout.fillHeight: true + anchors.bottom: parent.bottom + width: root.width - 8 + spacing: 0 + + TextField { + id: entryBar + Layout.fillWidth: true + style: + TextFieldStyle { + selectionColor: "#00b2a1" + textColor: "#2E2E2E" + background: Rectangle { + id: entryStyle + color: "#DDDDDD" + border.color: "#00b2a1" + radius: 3 + border.width: 1 + states: [ + State { + name: "out" + when: !entryBar.focus + PropertyChanges { + target: entryStyle + border.width: 0 + } + } + ] + } + } + } + + Button{ + text: "Save" + onClicked: saveButtonClicked(entryBar.text) + + style: ButtonStyle { + background: Rectangle { + id: buttonRectangle + radius: 3 + implicitWidth: 100 + implicitHeight: 25 + + border.color: "#9F9C99"; + border.width: 1; + + gradient: Gradient { + GradientStop { position: 0; color: control.pressed ? "#EFEBE7" : "#EFEBE7" } + GradientStop { position: .5; color: control.pressed ? "#D9D9D9" : "#EFEBE7" } + GradientStop { position: 0; color: control.pressed ? "#EFEBE7" : "#EFEBE7" } + } + } + } + } + } + + Connections{ + target: root.browser.fileWindow + onItemClicked: { + entryBar.text = absolutePath + (isFolder ? '/buttleSave_now.bofx' : '') + } + } + Component.onCompleted: entryBar.text = root.browser.bModel.currentPath + 'buttleSave_now.bofx' +} diff --git a/buttleofx/gui/dialogs/ExitDialog.qml b/buttleofx/gui/dialogs/ExitDialog.qml new file mode 100644 index 00000000..5dff85de --- /dev/null +++ b/buttleofx/gui/dialogs/ExitDialog.qml @@ -0,0 +1,111 @@ +import QtQuick 2.1 +import QtQuick.Window 2.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 + +Window { + id: exitDialog + width: 470 + height: 120 + title: "Save Changes?" + color: "#272727" + flags: Qt.Dialog + modality: "ApplicationModal" + + property string dialogText: "Do you want to save before exiting?
If you don't, all unsaved changes will be lost." + + signal saveButtonClicked + signal discardButtonClicked + + Component { + id: buttonStyle + + ButtonStyle { + background: Rectangle { + id: buttonRectangle + radius: 6 + implicitWidth: 100 + implicitHeight: 25 + + border.color: "#9F9C99"; + border.width: 1; + opacity: 0.7 + + gradient: Gradient { + GradientStop { position: 0; color: control.pressed ? "#EFEBE7" : "#EFEBE7" } + GradientStop { position: .5; color: control.pressed ? "#D9D9D9" : "#EFEBE7" } + GradientStop { position: 0; color: control.pressed ? "#EFEBE7" : "#EFEBE7" } + } + + states: + State { + name: "mouse-over"; + when: control.hovered + PropertyChanges { + target: buttonRectangle; + border.color: "#00B2A1"; + opacity: 1} + } + transitions: Transition { + NumberAnimation { + properties: "opacity, border.width"; + easing.type: Easing.InOutQuad; + duration: 200 + } + } + } + } + } + + ColumnLayout { + anchors.centerIn: parent + spacing: 15 + + RowLayout { + spacing: 20 + + Image { source: "../img/icons/cropped-buttle.png" } + + Text { + text: dialogText + color: "#FEFEFE" + } + } + + RowLayout { + anchors.horizontalCenter: parent.horizontalCenter + spacing: 6 + + Button { + id: saveButton + text: "Save" + style: buttonStyle + isDefault: true + + onClicked: { + exitDialog.saveButtonClicked() + exitDialog.visible = false + } + } + + Button { + id: discardButton + text: "Discard" + style: buttonStyle + + onClicked: { + exitDialog.discardButtonClicked() + exitDialog.visible = false + } + } + + Button { + id: abortButton + text: "Abort" + style: buttonStyle + onClicked: exitDialog.visible = false + } + } + } +} diff --git a/buttleofx/gui/dialogs/FileViewerDialog.qml b/buttleofx/gui/dialogs/FileViewerDialog.qml new file mode 100644 index 00000000..956323e5 --- /dev/null +++ b/buttleofx/gui/dialogs/FileViewerDialog.qml @@ -0,0 +1,228 @@ +import QtQuick 2.1 +import QtQuick.Window 2.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 +import Qt.labs.folderlistmodel 2.1 + +Window { + id: fileViewerWindow + width: 630 + height: 380 + color: "#141414" + flags: Qt.Dialog + + property string buttonText + property string folderModelFolder + property string entryBarText: entryBar.text + + signal buttonClicked(string currentFile) + + FolderListModel { + id: folderModel + showDirsFirst: true + folder: _buttleData.homeDir + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: 4 + + RowLayout { + id: headerBar + anchors.top: parent.top + anchors.leftMargin: parent.spacing + anchors.rightMargin: parent.spacing + + Button { + id: parentFolderButton + width: 15 + height: 15 + + iconSource: + if (hovered) { + "../browser_v2/qml/img/parent_hover.png" + } else { + "../browser_v2/qml/img/parent.png" + } + + style: + ButtonStyle { + background: Rectangle { + anchors.fill: parent + color: "transparent" + } + } + + onClicked: { + folderModel.folder = folderModel.parentFolder + } + } + + Rectangle { + Layout.fillWidth: true + height: 24 + color: "black" + radius: 5 + border.color: "grey" + + TextInput { + id: urlBar + x: 5 + y: 4 + + text: folderModel.folder.toString().substring(7) + readOnly: true + selectByMouse: true + Layout.fillWidth: true + + color: "white" + selectionColor: "#00b2a1" + } + } + } + + ScrollView { + anchors.fill: parent + + style: ScrollViewStyle { + scrollBarBackground: Rectangle { + id: scrollBar + width: styleData.hovered ? 8 : 4 + color: "transparent" + + Behavior on width { PropertyAnimation { easing.type: Easing.InOutQuad ; duration: 200 } } + } + + handle: Item { + implicitWidth: 15 + Rectangle { + color: "#00b2a1" + anchors.fill: parent + } + } + + decrementControl : Rectangle { + visible: false + } + + incrementControl : Rectangle { + visible: false + } + } + + GridView { + id: folderView + model: folderModel + anchors.fill: parent + anchors.topMargin: 20 + cellWidth: 150 + cellHeight: 100 + boundsBehavior: Flickable.StopAtBounds + focus: true + + highlight: Rectangle { + width: folderView.cellWidth + height: folderView.cellHeight + color: "#00b2a1" + radius: 4 + + x: folderView.currentItem.x + y: folderView.currentItem.y + Behavior on x { SmoothedAnimation { duration: -1; velocity: -1 } } + Behavior on y { SmoothedAnimation { duration: -1; velocity: -1 } } + } + + delegate: Rectangle { + width: folderView.cellWidth + height: folderView.cellHeight + color: "transparent" + + Rectangle{ + Image { + anchors.horizontalCenter: parent.horizontalCenter + width: 55 + height: 55 + asynchronous: true + fillMode: Image.PreserveAspectFit + sourceSize.width: width + sourceSize.height: height + property variant supportedFormats: ["bmp", "gif", "jpg", "jpeg", "png", "pbm", "pgm", "ppm", "xbm", "xpm"] + + source: { + if (folderModel.isFolder(index)) { + "../browser_v2/qml/img/folder-icon.png" + } else if (supportedFormats.indexOf(folderModel.get(index, "fileSuffix").toLowerCase()) != -1) { + folderModel.get(index, "filePath") + } else { + "../browser_v2/qml/img/file-icon.png" + } + } + } + + Text { + text: fileName + color: "white" + width: folderView.cellWidth - 10 + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WrapAnywhere + } + } + + MouseArea { + anchors.fill: parent + + onClicked: { + folderView.currentIndex = index + if (!folderModel.isFolder(index)) { + entryBar.text = folderModel.get(index, "fileName") + } else { + entryBar.text = "" + } + } + onDoubleClicked: { + if (folderModel.isFolder(index)) { + folderModel.folder = folderModel.get(index, "filePath") + } + } + } + } + } + } + + RowLayout { + id: bottomRow + Layout.fillWidth: true + Layout.fillHeight: true + anchors.bottom: parent.bottom + + TextField { + id: entryBar + Layout.fillWidth: true + } + + Button { + text: buttonText + + style: + ButtonStyle { + background: Rectangle { + radius: 6 + implicitWidth: 100 + implicitHeight: 25 + + border.color: control.hovered ? "#00B2A1" : "#9F9C99" + border.width: control.hovered ? 3 : 2 + + gradient: Gradient { + GradientStop { position: 0; color: control.pressed ? "#EFEBE7" : "#EFEBE7" } + GradientStop { position: .5; color: control.pressed ? "#D9D9D9" : "#EFEBE7" } + GradientStop { position: 0; color: control.pressed ? "#EFEBE7" : "#EFEBE7" } + } + } + } + onClicked: fileViewerWindow.buttonClicked(folderModel.folder + "/" + entryBarText) + } + } + } +} diff --git a/buttleofx/gui/graph/qml/FinderLoadGraph.qml b/buttleofx/gui/graph/qml/FinderLoadGraph.qml deleted file mode 100644 index 5462f2f6..00000000 --- a/buttleofx/gui/graph/qml/FinderLoadGraph.qml +++ /dev/null @@ -1,18 +0,0 @@ -import QtQuick 2.0 -import QtQuick.Dialogs 1.0 - -FileDialog { - signal getFileUrl(string fileurl) - - id: finderLoadGraph - title: "Open a graph" - folder: _buttleData.buttlePath - nameFilters: ["ButtleOFX Graph files (*.bofx)", "All files (*)"] - selectedNameFilter: "All files (*)" - - onAccepted: { - console.log(finderLoadGraph.fileUrl) - _buttleData.loadData(finderLoadGraph.fileUrl) - getFileUrl(finderLoadGraph.fileUrl) - } -} diff --git a/buttleofx/gui/graph/qml/FinderSaveGraph.qml b/buttleofx/gui/graph/qml/FinderSaveGraph.qml deleted file mode 100644 index 34a964f7..00000000 --- a/buttleofx/gui/graph/qml/FinderSaveGraph.qml +++ /dev/null @@ -1,19 +0,0 @@ -import QtQuick 2.0 -import QtQuick.Dialogs 1.0 - -FileDialog { - signal getFileUrl(string fileurl) - - id: finderSaveGraph - title: "Save the graph" - folder: _buttleData.buttlePath - nameFilters: ["ButtleOFX Graph files (*.bofx)", "All files (*)"] - selectedNameFilter: "All files (*)" - - onAccepted: { - _buttleData.saveData(finderSaveGraph.fileUrl) - getFileUrl(finderSaveGraph.fileUrl) - } - - selectExisting: false -} diff --git a/buttleofx/gui/graph/qml/Tools.qml b/buttleofx/gui/graph/qml/Tools.qml index 857a4c63..3ed7baad 100644 --- a/buttleofx/gui/graph/qml/Tools.qml +++ b/buttleofx/gui/graph/qml/Tools.qml @@ -1,7 +1,7 @@ import QtQuick 2.0 -import QtQuick.Dialogs 1.0 import "../../plugin/qml" +import "../../dialogs" Rectangle { id: tools @@ -13,6 +13,32 @@ Rectangle { signal clickCreationNode(string nodeType) + BrowserOpenDialog{ + id: finderLoadGraph + } + + BrowserSaveDialog{ + id: finderSaveGraph + } + + ExitDialog { + id: openGraph + visible: false + dialogText: "Do you want to save before closing this file?
If you don't, all unsaved changes will be lost" + + onSaveButtonClicked: { + if (urlOfFileToSave != "") { + _buttleData.saveData(urlOfFileToSave) + finderLoadGraph.visible = true + } else { + finderSaveGraph.show("open") + } + } + onDiscardButtonClicked: { + finderLoadGraph.visible = true + } + } + gradient: Gradient { GradientStop { position: 0.0; color: gradian2 } GradientStop { position: 0.85; color: gradian2 } @@ -39,13 +65,13 @@ Rectangle { locked: false onClicked: { - if (pluginVisible==true){ - pluginVisible=false + if (pluginVisible == true){ + pluginVisible = false } else { - pluginVisible=true + pluginVisible = true } - editNode=false + editNode = false } } @@ -62,11 +88,9 @@ Rectangle { editNode = false if (!_buttleData.graphCanBeSaved) { - finderLoadGraph.open() + finderLoadGraph.visible = true } else { - openGraph.open() - openGraph.close() - openGraph.open() + openGraph.visible = true } } } @@ -82,10 +106,11 @@ Rectangle { onClicked: { pluginVisible = false editNode = false + if (urlOfFileToSave != "") { _buttleData.saveData(urlOfFileToSave) } else { - finderSaveGraph.open() + finderSaveGraph.show("save") } } } diff --git a/buttleofx/gui/img/icons/cropped-buttle.png b/buttleofx/gui/img/icons/cropped-buttle.png new file mode 100644 index 00000000..20e4a95a Binary files /dev/null and b/buttleofx/gui/img/icons/cropped-buttle.png differ diff --git a/buttleofx/main.py b/buttleofx/main.py index 23fc3840..8f2df621 100644 --- a/buttleofx/main.py +++ b/buttleofx/main.py @@ -38,8 +38,8 @@ from buttleofx.event import globalButtleEvent from buttleofx.manager import globalButtleManager from buttleofx.core.undo_redo.manageTools import globalCommandManager -from buttleofx.gui.browser_v2.browserModel import BrowserModel, globalBrowserModel -from buttleofx.gui.browser_v2.actions.browserAction import globalBrowserAction +from buttleofx.gui.browser_v2.browserModel import BrowserModel, globalBrowser, globalBrowserDialog +from buttleofx.gui.browser_v2.actions.browserAction import globalBrowserAction, globalBrowserActionDialog from buttleofx.gui.browser_v2.actions.browserAction import globalActionManager from PyQt5 import QtCore, QtGui, QtQml, QtQuick, QtWidgets @@ -80,48 +80,50 @@ class EventFilter(QtCore.QObject): + def __init__(self, app, engine): + self.mainApp = app + self.mainEngine = engine + self.buttleData = globalButtleData + super(EventFilter, self).__init__() + + def onSaveDialogButtonClicked(self, fileToSave): + self.buttleData.urlOfFileToSave = fileToSave + self.buttleData.saveData(QtCore.QUrl(self.buttleData.urlOfFileToSave)) + QtCore.QCoreApplication.quit() + + def onExitDialogDiscardButtonClicked(self): + QtCore.QCoreApplication.quit() + + def onExitDialogSaveButtonClicked(self): + if self.buttleData.urlOfFileToSave: + self.buttleData.saveData(self.buttleData.urlOfFileToSave) + QtCore.QCoreApplication.quit() + else: + saveDialogComponent = QtQml.QQmlComponent(self.mainEngine) + saveDialogComponent.loadUrl(QtCore.QUrl(os.path.dirname(os.path.abspath(__file__)) + '/gui/dialogs/BrowserSaveDialog.qml')) + saveDialog = saveDialogComponent.create() + saveDialog.saveButtonClicked.connect(self.onSaveDialogButtonClicked) + saveDialog.show() + def eventFilter(self, receiver, event): if event.type() == QtCore.QEvent.KeyPress: - # If alt f4 event ignored + # If Alt F4 event ignored if event.modifiers() == QtCore.Qt.AltModifier and event.key() == QtCore.Qt.Key_F4: event.ignore() if event.type() != QtCore.QEvent.Close: return QtCore.QObject.eventFilter(self, receiver, event) if not isinstance(receiver, QtQuick.QQuickWindow) or not receiver.title() == "ButtleOFX": return False - if not globalButtleData.graphCanBeSaved: - return False - msgBox = QtWidgets.QMessageBox() - msgBox.setText("Save graph changes before closing ?") - msgBox.setModal(True) - msgBox.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) - msgBox.setInformativeText("If you don't save the graph, unsaved modifications will be lost.") - msgBox.setStandardButtons( - QtWidgets.QMessageBox.Save | QtWidgets.QMessageBox.Discard | QtWidgets.QMessageBox.Abort) - msgBox.setDefaultButton(QtWidgets.QMessageBox.Save) - ret = msgBox.exec_() - - if ret == QtWidgets.QMessageBox.Save: - if globalButtleData.urlOfFileToSave: - # Save on the already existing file - globalButtleData.saveData(globalButtleData.urlOfFileToSave) - # Close the application - return QtCore.QObject.eventFilter(self, receiver, event) - - # This project has never been saved, so ask the user on which file to save. - dialog = QtWidgets.QFileDialog() - fileToSave = dialog.getSaveFileName(None, "Save the graph", os.path.expanduser("~"))[0] - if not (fileToSave.endswith(".bofx")): - fileToSave += ".bofx" - globalButtleData.urlOfFileToSave = fileToSave - globalButtleData.saveData(fileToSave) - # Close the application - return QtCore.QObject.eventFilter(self, receiver, event) + if not self.buttleData.graphCanBeSaved: + return False - if ret == QtWidgets.QMessageBox.Discard: - # Close the application - return QtCore.QObject.eventFilter(self, receiver, event) + exitDialogComponent = QtQml.QQmlComponent(self.mainEngine) + exitDialogComponent.loadUrl(QtCore.QUrl(os.path.dirname(os.path.abspath(__file__)) + '/gui/dialogs/ExitDialog.qml')) + exitDialog = exitDialogComponent.create() + exitDialog.saveButtonClicked.connect(self.onExitDialogSaveButtonClicked) + exitDialog.discardButtonClicked.connect(self.onExitDialogDiscardButtonClicked) + exitDialog.show() # Don't call the parent class, so we don't close the application return True @@ -237,15 +239,17 @@ def main(argv, app): parser.add_argument('folder', nargs='?', help='Folder to browse') args = parser.parse_args() - globalBrowserModel.setCurrentPath(os.path.abspath(args.folder) if args.folder else globalBrowserModel.getHomePath()) + globalBrowser.setCurrentPath(os.path.abspath(args.folder) if args.folder else globalBrowser.getHomePath()) # Expose data to QML rc = engine.rootContext() rc.setContextProperty("_buttleApp", app) rc.setContextProperty("_buttleData", globalButtleData) rc.setContextProperty("_buttleManager", buttleManager) rc.setContextProperty("_buttleEvent", globalButtleEvent) - rc.setContextProperty("_browser", globalBrowserModel) + rc.setContextProperty("_browser", globalBrowser) + rc.setContextProperty("_browserDialog", globalBrowserDialog) rc.setContextProperty("_browserAction", globalBrowserAction) + rc.setContextProperty("_browserActionDialog", globalBrowserActionDialog) rc.setContextProperty("_actionManager", globalActionManager) iconPath = os.path.join(currentFilePath, "../blackMosquito.png") @@ -284,9 +288,11 @@ def main(argv, app): logging.debug("Watch directory: %s", parentDir) qic.addFilesFromDirectory(parentDir, recursive=True) - aFilter = EventFilter() + aFilter = EventFilter(app, engine) app.installEventFilter(aFilter) - globalBrowserModel.loadData() + + globalBrowser.loadData() + globalBrowserDialog.loadData() with globalActionManager: topLevelItem.show()