diff --git a/PrinterApplication.py b/PrinterApplication.py index 285a5d1e9f..0fad7d5fc9 100644 --- a/PrinterApplication.py +++ b/PrinterApplication.py @@ -45,7 +45,15 @@ class PrinterApplication(QtApplication): self._physics = None self._volume = None self._platform = None - self._output_source = 'local_file' + self._output_devices = { + 'local_file': { + 'id': 'local_file', + 'function': self._writeToLocalFile, + 'description': 'Save to Disk', + 'icon': 'save', + 'priority': 0 + } + } self.activeMachineChanged.connect(self._onActiveMachineChanged) def _loadPlugins(self): @@ -106,6 +114,7 @@ class PrinterApplication(QtApplication): else: self.requestAddPrinter.emit() + self._removableDrivesChanged() if self._engine.rootObjects: self.closeSplash() @@ -256,39 +265,51 @@ class PrinterApplication(QtApplication): else: self._platform.setPosition(Vector(0.0, 0.0, 0.0)) - removableDrivesChanged = pyqtSignal() + outputDevicesChanged = pyqtSignal() + @pyqtProperty('QVariantMap', notify = outputDevicesChanged) + def outputDevices(self): + return self._output_devices - outputDeviceChanged = pyqtSignal() - @pyqtProperty(str, notify = outputDeviceChanged) - def outputDevice(self): - return self._output_source + @pyqtProperty('QStringList', notify = outputDevicesChanged) + def outputDeviceNames(self): + return self._output_devices.keys() - @pyqtProperty(str, notify = outputDeviceChanged) - def outputDeviceIcon(self): - if self._output_source == 'local_file': - return 'save' - elif self._output_source == 'sdcard': - return 'save_sd' - elif self._output_source == 'usb': - return 'print_usb' + ## Add an output device that can be written to. + # + # \param id The identifier used to identify the device. + # \param device A dictionary of device information. + # It should contains the following: + # - function: A function to be called when trying to write to the device. Will be passed the device id as first parameter. + # - description: A translated string containing a description of what happens when writing to the device. + # - icon: The icon to use to represent the device. + # - priority: The priority of the device. The device with the highest priority will be used as the default device. + def addOutputDevice(self, id, device): + self._output_devices[id] = device + self.outputDevicesChanged.emit() + def removeOutputDevice(self, id): + del self._output_devices[id] + self.outputDevicesChanged.emit() - @pyqtSlot() - def writeToOutputDevice(self): - pass + @pyqtSlot(str) + def writeToOutputDevice(self, device): + self._output_devices[device]['function'](device) - @pyqtProperty("QStringList", notify = removableDrivesChanged) - def removableDrives(self): - return list(self.getStorageDevice('LocalFileStorage').getRemovableDrives().keys()) + writeToLocalFileRequested = pyqtSignal() + def _writeToLocalFile(self, device): + self.writeToLocalFileRequested.emit() - @pyqtSlot() - def saveToSD(self): + def _writeToSD(self, device): for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue - drives = self.getStorageDevice('LocalFileStorage').getRemovableDrives() - path = next(iter(drives.values())) + try: + path = self.getStorageDevice('LocalFileStorage').getRemovableDrives()[device] + except KeyError: + Logger.log('e', 'Tried to write to unknown SD card %s', device) + return + filename = os.path.join(path, node.getName()[0:node.getName().rfind('.')] + '.gcode') job = WriteMeshJob(filename, node.getMeshData()) @@ -296,5 +317,18 @@ class PrinterApplication(QtApplication): return def _removableDrivesChanged(self): - print(self.getStorageDevice('LocalFileStorage').getRemovableDrives()) - self.removableDrivesChanged.emit() + drives = self.getStorageDevice('LocalFileStorage').getRemovableDrives() + for drive in drives: + if drive not in self._output_devices: + self.addOutputDevice(drive, { + 'id': drive, + 'function': self._writeToSD, + 'description': 'Save to SD Card {0}'.format(drive), + 'icon': 'save_sd', + 'priority': 1 + }) + + for device in self._output_devices: + if not device in drives: + if self._output_devices[device]['function'] == self._writeToSD: + self.removeOutputDevice(device) diff --git a/qml/Printer.qml b/qml/Printer.qml index a81a261c64..854672d344 100644 --- a/qml/Printer.qml +++ b/qml/Printer.qml @@ -354,6 +354,7 @@ UM.MainWindow { Connections { target: Printer onRequestAddPrinter: addMachine.visible = true; + onWriteToLocalFileRequested: saveDialog.open(); } Component.onCompleted: UM.Theme.load(UM.Resources.getPath(UM.Resources.ThemesLocation, "cura")) diff --git a/qml/SaveButton.qml b/qml/SaveButton.qml index f5b6dfe50e..ae4c701d6b 100644 --- a/qml/SaveButton.qml +++ b/qml/SaveButton.qml @@ -13,9 +13,38 @@ Button { property real progress: UM.Backend.progress; Behavior on progress { NumberAnimation { duration: 250; } } - enabled: progress >= 0.95; +// enabled: progress >= 0.95; - iconSource: UM.Theme.icons[Printer.outputDeviceIcon]; + property string currentDevice: 'local_file' + property bool defaultOverride: false; + property bool defaultAmbiguous: false; + + iconSource: UM.Theme.icons[Printer.outputDevices[base.currentDevice].icon]; + tooltip: Printer.outputDevices[base.currentDevice].description; + + Connections { + target: Printer; + onOutputDevicesChanged: { + if(!base.defaultOverride) { + base.defaultAmbiguous = false; + var device = null; + for(var i in Printer.outputDevices) { + console.log(i); + if(device == null) { + device = i; + } else if(Printer.outputDevices[i].priority > Printer.outputDevices[device].priority) { + device = i; + } else if(Printer.outputDevices[i].priority == Printer.outputDevices[device].priority) { + base.defaultAmbiguous = true; + } + } + + if(device != null) { + base.currentDevice = device; + } + } + } + } style: ButtonStyle { background: UM.AngledCornerRectangle { @@ -101,6 +130,40 @@ Button { } } + MouseArea { + anchors.fill: parent; + + acceptedButtons: Qt.RightButton; + + onClicked: devicesMenu.popup(); + } + + Menu { + id: devicesMenu; + + Instantiator { + model: Printer.outputDeviceNames; + MenuItem { + text: Printer.outputDevices[modelData].description; + checkable: true; + checked: base.defaultAmbiguous ? false : modelData == base.currentDevice; + exclusiveGroup: devicesMenuGroup; + onTriggered: { + base.defaultOverride = true; + base.currentDevice = modelData; + if(base.defaultAmbiguous) { + base.defaultAmbiguous = false; + Printer.writeToOutputDevice(modelData); + } + } + } + onObjectAdded: devicesMenu.insertItem(index, object) + onObjectRemoved: devicesMenu.removeItem(object) + } + + ExclusiveGroup { id: devicesMenuGroup; } + } + text: { if(base.progress < 0) { return qsTr("Please load a 3D model"); @@ -112,10 +175,10 @@ Button { } onClicked: { - if(Printer.outputDevice != "local_file") { - Printer.writeToOutputDevice(); - } else if(base.saveAction) { - base.saveAction.trigger(); + if(base.defaultAmbiguous) { + devicesMenu.popup(); + } else { + Printer.writeToOutputDevice(base.currentDevice); } } }