mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-14 17:15:56 +08:00
Merge branch 'master' of https://github.com/Ultimaker/Cura
This commit is contained in:
commit
b36301347e
@ -3,10 +3,15 @@ import platform
|
|||||||
import traceback
|
import traceback
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
|
||||||
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR
|
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, QCoreApplication
|
||||||
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTextEdit
|
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTextEdit
|
||||||
|
|
||||||
def show():
|
def show(type, value, tb):
|
||||||
|
application = QCoreApplication.instance()
|
||||||
|
if not application:
|
||||||
|
traceback.print_exception(type, value, tb)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
dialog = QDialog()
|
dialog = QDialog()
|
||||||
dialog.setWindowTitle("Oops!")
|
dialog.setWindowTitle("Oops!")
|
||||||
|
|
||||||
@ -25,7 +30,7 @@ def show():
|
|||||||
except:
|
except:
|
||||||
version = "Unknown"
|
version = "Unknown"
|
||||||
|
|
||||||
trace = "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
|
trace = "".join(traceback.format_exception(type, value, tb))
|
||||||
|
|
||||||
crash_info = "Version: {0}\nPlatform: {1}\nQt: {2}\nPyQt: {3}\n\nException:\n{4}"
|
crash_info = "Version: {0}\nPlatform: {1}\nQt: {2}\nPyQt: {3}\n\nException:\n{4}"
|
||||||
crash_info = crash_info.format(version, platform.platform(), QT_VERSION_STR, PYQT_VERSION_STR, trace)
|
crash_info = crash_info.format(version, platform.platform(), QT_VERSION_STR, PYQT_VERSION_STR, trace)
|
||||||
@ -39,3 +44,4 @@ def show():
|
|||||||
buttons.helpRequested.connect(lambda: webbrowser.open("http://github.com/Ultimaker/Cura/issues"))
|
buttons.helpRequested.connect(lambda: webbrowser.open("http://github.com/Ultimaker/Cura/issues"))
|
||||||
|
|
||||||
dialog.exec_()
|
dialog.exec_()
|
||||||
|
sys.exit(1)
|
||||||
|
@ -67,7 +67,7 @@ class CuraApplication(QtApplication):
|
|||||||
"SelectionTool",
|
"SelectionTool",
|
||||||
"CameraTool",
|
"CameraTool",
|
||||||
"GCodeWriter",
|
"GCodeWriter",
|
||||||
"LocalFileStorage"
|
"LocalFileOutputDevice"
|
||||||
])
|
])
|
||||||
self._physics = None
|
self._physics = None
|
||||||
self._volume = None
|
self._volume = None
|
||||||
@ -101,16 +101,12 @@ class CuraApplication(QtApplication):
|
|||||||
self._plugin_registry.addPluginLocation(os.path.join(QtApplication.getInstallPrefix(), "lib", "cura"))
|
self._plugin_registry.addPluginLocation(os.path.join(QtApplication.getInstallPrefix(), "lib", "cura"))
|
||||||
if not hasattr(sys, "frozen"):
|
if not hasattr(sys, "frozen"):
|
||||||
self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins"))
|
self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins"))
|
||||||
|
self._plugin_registry.loadPlugin("ConsoleLogger")
|
||||||
|
|
||||||
self._plugin_registry.loadPlugins({ "type": "logger"})
|
self._plugin_registry.loadPlugins()
|
||||||
self._plugin_registry.loadPlugins({ "type": "storage_device" })
|
|
||||||
self._plugin_registry.loadPlugins({ "type": "view" })
|
|
||||||
self._plugin_registry.loadPlugins({ "type": "mesh_reader" })
|
|
||||||
self._plugin_registry.loadPlugins({ "type": "mesh_writer" })
|
|
||||||
self._plugin_registry.loadPlugins({ "type": "tool" })
|
|
||||||
self._plugin_registry.loadPlugins({ "type": "extension" })
|
|
||||||
|
|
||||||
self._plugin_registry.loadPlugin("CuraEngineBackend")
|
if self.getBackend() == None:
|
||||||
|
raise RuntimeError("Could not load the backend plugin!")
|
||||||
|
|
||||||
def addCommandLineOptions(self, parser):
|
def addCommandLineOptions(self, parser):
|
||||||
super().addCommandLineOptions(parser)
|
super().addCommandLineOptions(parser)
|
||||||
@ -119,15 +115,6 @@ class CuraApplication(QtApplication):
|
|||||||
def run(self):
|
def run(self):
|
||||||
self._i18n_catalog = i18nCatalog("cura");
|
self._i18n_catalog = i18nCatalog("cura");
|
||||||
|
|
||||||
self.addOutputDevice("local_file", {
|
|
||||||
"id": "local_file",
|
|
||||||
"function": self._writeToLocalFile,
|
|
||||||
"description": self._i18n_catalog.i18nc("Save button tooltip", "Save to Disk"),
|
|
||||||
"shortDescription": self._i18n_catalog.i18nc("Save button tooltip", "Save to Disk"),
|
|
||||||
"icon": "save",
|
|
||||||
"priority": 0
|
|
||||||
})
|
|
||||||
|
|
||||||
self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Setting up scene..."))
|
self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Setting up scene..."))
|
||||||
|
|
||||||
controller = self.getController()
|
controller = self.getController()
|
||||||
@ -167,8 +154,6 @@ class CuraApplication(QtApplication):
|
|||||||
self.setMainQml(Resources.getPath(Resources.QmlFilesLocation, "Cura.qml"))
|
self.setMainQml(Resources.getPath(Resources.QmlFilesLocation, "Cura.qml"))
|
||||||
self.initializeEngine()
|
self.initializeEngine()
|
||||||
|
|
||||||
self.getStorageDevice("LocalFileStorage").removableDrivesChanged.connect(self._removableDrivesChanged)
|
|
||||||
|
|
||||||
if self.getMachines():
|
if self.getMachines():
|
||||||
active_machine_pref = Preferences.getInstance().getValue("cura/active_machine")
|
active_machine_pref = Preferences.getInstance().getValue("cura/active_machine")
|
||||||
if active_machine_pref:
|
if active_machine_pref:
|
||||||
@ -181,7 +166,6 @@ class CuraApplication(QtApplication):
|
|||||||
else:
|
else:
|
||||||
self.requestAddPrinter.emit()
|
self.requestAddPrinter.emit()
|
||||||
|
|
||||||
self._removableDrivesChanged()
|
|
||||||
if self._engine.rootObjects:
|
if self._engine.rootObjects:
|
||||||
self.closeSplash()
|
self.closeSplash()
|
||||||
|
|
||||||
@ -401,16 +385,6 @@ class CuraApplication(QtApplication):
|
|||||||
def expandedCategories(self):
|
def expandedCategories(self):
|
||||||
return Preferences.getInstance().getValue("cura/categories_expanded").split(";")
|
return Preferences.getInstance().getValue("cura/categories_expanded").split(";")
|
||||||
|
|
||||||
outputDevicesChanged = pyqtSignal()
|
|
||||||
|
|
||||||
@pyqtProperty("QVariantMap", notify = outputDevicesChanged)
|
|
||||||
def outputDevices(self):
|
|
||||||
return self._output_devices
|
|
||||||
|
|
||||||
@pyqtProperty("QStringList", notify = outputDevicesChanged)
|
|
||||||
def outputDeviceNames(self):
|
|
||||||
return self._output_devices.keys()
|
|
||||||
|
|
||||||
@pyqtSlot(str, result = "QVariant")
|
@pyqtSlot(str, result = "QVariant")
|
||||||
def getSettingValue(self, key):
|
def getSettingValue(self, key):
|
||||||
if not self.getActiveMachine():
|
if not self.getActiveMachine():
|
||||||
@ -479,82 +453,6 @@ class CuraApplication(QtApplication):
|
|||||||
for node in ungrouped_nodes:
|
for node in ungrouped_nodes:
|
||||||
Selection.remove(node)
|
Selection.remove(node)
|
||||||
|
|
||||||
## Add an output device that can be written to.
|
|
||||||
#
|
|
||||||
# \param id \type{string} The identifier used to identify the device.
|
|
||||||
# \param device \type{StorageDevice} 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()
|
|
||||||
|
|
||||||
## Remove output device
|
|
||||||
# \param id \type{string} The identifier used to identify the device.
|
|
||||||
# \sa PrinterApplication::addOutputDevice()
|
|
||||||
def removeOutputDevice(self, id):
|
|
||||||
if id in self._output_devices:
|
|
||||||
del self._output_devices[id]
|
|
||||||
self.outputDevicesChanged.emit()
|
|
||||||
|
|
||||||
@pyqtSlot(str)
|
|
||||||
def writeToOutputDevice(self, device):
|
|
||||||
self._output_devices[device]["function"](device)
|
|
||||||
|
|
||||||
writeToLocalFileRequested = pyqtSignal()
|
|
||||||
|
|
||||||
def _writeToLocalFile(self, device):
|
|
||||||
self.writeToLocalFileRequested.emit()
|
|
||||||
|
|
||||||
def _writeToSD(self, device):
|
|
||||||
for node in DepthFirstIterator(self.getController().getScene().getRoot()):
|
|
||||||
if type(node) is not SceneNode or not node.getMeshData():
|
|
||||||
continue
|
|
||||||
|
|
||||||
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")
|
|
||||||
|
|
||||||
message = Message(self._output_devices[device]["description"], 0, False, -1)
|
|
||||||
message.show()
|
|
||||||
|
|
||||||
job = WriteMeshJob(filename, node.getMeshData())
|
|
||||||
job._sdcard = device
|
|
||||||
job._message = message
|
|
||||||
job.start()
|
|
||||||
job.finished.connect(self._onWriteToSDFinished)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def _removableDrivesChanged(self):
|
|
||||||
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": self._i18n_catalog.i18nc("Save button tooltip. {0} is sd card name", "Save to SD Card {0}").format(drive),
|
|
||||||
"shortDescription": self._i18n_catalog.i18nc("Save button tooltip. {0} is sd card name", "Save to SD Card {0}").format(""),
|
|
||||||
"icon": "save_sd",
|
|
||||||
"priority": 1
|
|
||||||
})
|
|
||||||
|
|
||||||
drives_to_remove = []
|
|
||||||
for device in self._output_devices:
|
|
||||||
if device not in drives:
|
|
||||||
if self._output_devices[device]["function"] == self._writeToSD:
|
|
||||||
drives_to_remove.append(device)
|
|
||||||
|
|
||||||
for drive in drives_to_remove:
|
|
||||||
self.removeOutputDevice(drive)
|
|
||||||
|
|
||||||
def _onActiveMachineChanged(self):
|
def _onActiveMachineChanged(self):
|
||||||
machine = self.getActiveMachine()
|
machine = self.getActiveMachine()
|
||||||
if machine:
|
if machine:
|
||||||
@ -580,25 +478,6 @@ class CuraApplication(QtApplication):
|
|||||||
else:
|
else:
|
||||||
self._platform.setPosition(Vector(0.0, 0.0, 0.0))
|
self._platform.setPosition(Vector(0.0, 0.0, 0.0))
|
||||||
|
|
||||||
def _onWriteToSDFinished(self, job):
|
|
||||||
message = Message(self._i18n_catalog.i18nc("Saved to SD message, {0} is sdcard, {1} is filename", "Saved to SD Card {0} as {1}").format(job._sdcard, job.getFileName()))
|
|
||||||
message.addAction(
|
|
||||||
"eject",
|
|
||||||
self._i18n_catalog.i18nc("Message action", "Eject"),
|
|
||||||
"eject",
|
|
||||||
self._i18n_catalog.i18nc("Message action tooltip, {0} is sdcard", "Eject SD Card {0}").format(job._sdcard)
|
|
||||||
)
|
|
||||||
|
|
||||||
job._message.hide()
|
|
||||||
|
|
||||||
message._sdcard = job._sdcard
|
|
||||||
message.actionTriggered.connect(self._onMessageActionTriggered)
|
|
||||||
message.show()
|
|
||||||
|
|
||||||
def _onMessageActionTriggered(self, message, action):
|
|
||||||
if action == "eject":
|
|
||||||
self.getStorageDevice("LocalFileStorage").ejectRemovableDrive(message._sdcard)
|
|
||||||
|
|
||||||
def _onFileLoaded(self, job):
|
def _onFileLoaded(self, job):
|
||||||
mesh = job.getResult()
|
mesh = job.getResult()
|
||||||
if mesh != None:
|
if mesh != None:
|
||||||
|
15
cura_app.py
15
cura_app.py
@ -3,12 +3,15 @@
|
|||||||
# Copyright (c) 2015 Ultimaker B.V.
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the AGPLv3 or higher.
|
# Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
try:
|
import sys
|
||||||
import cura.CuraApplication
|
|
||||||
|
|
||||||
app = cura.CuraApplication.CuraApplication.getInstance()
|
def exceptHook(type, value, traceback):
|
||||||
app.run()
|
|
||||||
except Exception as e:
|
|
||||||
import cura.CrashHandler
|
import cura.CrashHandler
|
||||||
cura.CrashHandler.show()
|
cura.CrashHandler.show(type, value, traceback)
|
||||||
|
|
||||||
|
sys.excepthook = exceptHook
|
||||||
|
|
||||||
|
import cura.CuraApplication
|
||||||
|
|
||||||
|
app = cura.CuraApplication.CuraApplication.getInstance()
|
||||||
|
app.run()
|
||||||
|
@ -9,11 +9,11 @@ catalog = i18nCatalog("cura")
|
|||||||
|
|
||||||
def getMetaData():
|
def getMetaData():
|
||||||
return {
|
return {
|
||||||
"type": "backend",
|
|
||||||
"plugin": {
|
"plugin": {
|
||||||
"name": "CuraEngine Backend",
|
"name": "CuraEngine Backend",
|
||||||
"author": "Ultimaker",
|
"author": "Ultimaker",
|
||||||
"description": catalog.i18nc("CuraEngine backend plugin description", "Provides the link to the CuraEngine slicing backend")
|
"description": catalog.i18nc("CuraEngine backend plugin description", "Provides the link to the CuraEngine slicing backend"),
|
||||||
|
"api": 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,18 +10,17 @@ import io
|
|||||||
class GCodeWriter(MeshWriter):
|
class GCodeWriter(MeshWriter):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._gcode = None
|
|
||||||
|
|
||||||
def write(self, file_name, storage_device, mesh_data):
|
def write(self, stream, node, mode = MeshWriter.OutputMode.TextMode):
|
||||||
if "gcode" in file_name:
|
if mode != MeshWriter.OutputMode.TextMode:
|
||||||
|
Logger.log("e", "GCode Writer does not support non-text mode")
|
||||||
|
return False
|
||||||
|
|
||||||
scene = Application.getInstance().getController().getScene()
|
scene = Application.getInstance().getController().getScene()
|
||||||
gcode_list = getattr(scene, "gcode_list")
|
gcode_list = getattr(scene, "gcode_list")
|
||||||
if gcode_list:
|
if gcode_list:
|
||||||
f = storage_device.openFile(file_name, "wt")
|
|
||||||
Logger.log("d", "Writing GCode to file %s", file_name)
|
|
||||||
for gcode in gcode_list:
|
for gcode in gcode_list:
|
||||||
f.write(gcode)
|
stream.write(gcode)
|
||||||
storage_device.closeFile(f)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
@ -8,17 +8,21 @@ catalog = i18nCatalog("cura")
|
|||||||
|
|
||||||
def getMetaData():
|
def getMetaData():
|
||||||
return {
|
return {
|
||||||
"type": "mesh_writer",
|
|
||||||
"plugin": {
|
"plugin": {
|
||||||
"name": "GCode Writer",
|
"name": "GCode Writer",
|
||||||
"author": "Ultimaker",
|
"author": "Ultimaker",
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"description": catalog.i18nc("GCode Writer Plugin Description", "Writes GCode to a file")
|
"description": catalog.i18nc("GCode Writer Plugin Description", "Writes GCode to a file"),
|
||||||
|
"api": 2
|
||||||
},
|
},
|
||||||
|
|
||||||
"mesh_writer": {
|
"mesh_writer": {
|
||||||
|
"output": [{
|
||||||
"extension": "gcode",
|
"extension": "gcode",
|
||||||
"description": catalog.i18nc("GCode Writer File Description", "GCode File")
|
"description": catalog.i18nc("GCode Writer File Description", "GCode File"),
|
||||||
|
"mime_type": "text/x-gcode",
|
||||||
|
"mode": GCodeWriter.GCodeWriter.OutputMode.TextMode
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,12 +9,12 @@ catalog = i18nCatalog("cura")
|
|||||||
|
|
||||||
def getMetaData():
|
def getMetaData():
|
||||||
return {
|
return {
|
||||||
"type": "view",
|
|
||||||
"plugin": {
|
"plugin": {
|
||||||
"name": "Layer View",
|
"name": "Layer View",
|
||||||
"author": "Ultimaker",
|
"author": "Ultimaker",
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"description": catalog.i18nc("Layer View plugin description", "Provides the Layer view.")
|
"description": catalog.i18nc("Layer View plugin description", "Provides the Layer view."),
|
||||||
|
"api": 2
|
||||||
},
|
},
|
||||||
"view": {
|
"view": {
|
||||||
"name": catalog.i18nc("Layers View mode", "Layers"),
|
"name": catalog.i18nc("Layers View mode", "Layers"),
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
|
# Copyright (c) 2013 David Braam
|
||||||
|
# Uranium is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
from . import RemovableDrivePlugin
|
||||||
|
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
## Support for removable devices on Linux.
|
||||||
|
#
|
||||||
|
# TODO: This code uses the most basic interfaces for handling this.
|
||||||
|
# We should instead use UDisks2 to handle mount/unmount and hotplugging events.
|
||||||
|
#
|
||||||
|
class LinuxRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
|
||||||
|
def checkRemovableDrives(self):
|
||||||
|
drives = {}
|
||||||
|
for volume in glob.glob("/media/*"):
|
||||||
|
if os.path.ismount(volume):
|
||||||
|
drives[volume] = os.path.basename(volume)
|
||||||
|
elif volume == "/media/"+os.getenv("USER"):
|
||||||
|
for volume in glob.glob("/media/"+os.getenv("USER")+"/*"):
|
||||||
|
if os.path.ismount(volume):
|
||||||
|
drives[volume] = os.path.basename(volume)
|
||||||
|
|
||||||
|
for volume in glob.glob("/run/media/" + os.getenv("USER") + "/*"):
|
||||||
|
if os.path.ismount(volume):
|
||||||
|
drives[volume] = os.path.basename(volume)
|
||||||
|
|
||||||
|
return drives
|
||||||
|
|
||||||
|
def performEjectDevice(self, device):
|
||||||
|
p = subprocess.Popen(["umount", device.getId()], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
output = p.communicate()
|
||||||
|
|
||||||
|
return_code = p.wait()
|
||||||
|
if return_code != 0:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
@ -0,0 +1,66 @@
|
|||||||
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
|
# Copyright (c) 2013 David Braam
|
||||||
|
# Uranium is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
from . import RemovableDrivePlugin
|
||||||
|
|
||||||
|
import threading
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
|
import plistlib
|
||||||
|
|
||||||
|
## Support for removable devices on Mac OSX
|
||||||
|
class OSXRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
|
||||||
|
def checkRemovableDrives(self):
|
||||||
|
drives = {}
|
||||||
|
p = subprocess.Popen(["system_profiler", "SPUSBDataType", "-xml"], stdout=subprocess.PIPE)
|
||||||
|
plist = plistlib.loads(p.communicate()[0])
|
||||||
|
p.wait()
|
||||||
|
|
||||||
|
for dev in self._findInTree(plist, "Mass Storage Device"):
|
||||||
|
if "removable_media" in dev and dev["removable_media"] == "yes" and "volumes" in dev and len(dev["volumes"]) > 0:
|
||||||
|
for vol in dev["volumes"]:
|
||||||
|
if "mount_point" in vol:
|
||||||
|
volume = vol["mount_point"]
|
||||||
|
drives[volume] = os.path.basename(volume)
|
||||||
|
|
||||||
|
p = subprocess.Popen(["system_profiler", "SPCardReaderDataType", "-xml"], stdout=subprocess.PIPE)
|
||||||
|
plist = plistlib.loads(p.communicate()[0])
|
||||||
|
p.wait()
|
||||||
|
|
||||||
|
for entry in plist:
|
||||||
|
if "_items" in entry:
|
||||||
|
for item in entry["_items"]:
|
||||||
|
for dev in item["_items"]:
|
||||||
|
if "removable_media" in dev and dev["removable_media"] == "yes" and "volumes" in dev and len(dev["volumes"]) > 0:
|
||||||
|
for vol in dev["volumes"]:
|
||||||
|
if "mount_point" in vol:
|
||||||
|
volume = vol["mount_point"]
|
||||||
|
drives[volume] = os.path.basename(volume)
|
||||||
|
|
||||||
|
return drives
|
||||||
|
|
||||||
|
def performEjectDevice(self, device):
|
||||||
|
p = subprocess.Popen(["diskutil", "eject", path], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
output = p.communicate()
|
||||||
|
|
||||||
|
return_code = p.wait()
|
||||||
|
if return_code != 0:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _findInTree(self, t, n):
|
||||||
|
ret = []
|
||||||
|
if type(t) is dict:
|
||||||
|
if "_name" in t and t["_name"] == n:
|
||||||
|
ret.append(t)
|
||||||
|
for k, v in t.items():
|
||||||
|
ret += self._findInTree(v, n)
|
||||||
|
if type(t) is list:
|
||||||
|
for v in t:
|
||||||
|
ret += self._findInTree(v, n)
|
||||||
|
return ret
|
@ -0,0 +1,87 @@
|
|||||||
|
import os.path
|
||||||
|
|
||||||
|
from UM.Application import Application
|
||||||
|
from UM.Logger import Logger
|
||||||
|
from UM.Message import Message
|
||||||
|
from UM.Mesh.WriteMeshJob import WriteMeshJob
|
||||||
|
from UM.Mesh.MeshWriter import MeshWriter
|
||||||
|
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
||||||
|
from UM.OutputDevice.OutputDevice import OutputDevice
|
||||||
|
from UM.OutputDevice import OutputDeviceError
|
||||||
|
|
||||||
|
from UM.i18n import i18nCatalog
|
||||||
|
catalog = i18nCatalog("uranium")
|
||||||
|
|
||||||
|
class RemovableDriveOutputDevice(OutputDevice):
|
||||||
|
def __init__(self, device_id, device_name):
|
||||||
|
super().__init__(device_id)
|
||||||
|
|
||||||
|
self.setName(device_name)
|
||||||
|
self.setShortDescription(catalog.i18nc("", "Save to Removable Drive"))
|
||||||
|
self.setDescription(catalog.i18nc("", "Save to Removable Drive {0}").format(device_name))
|
||||||
|
self.setIconName("save_sd")
|
||||||
|
self.setPriority(1)
|
||||||
|
|
||||||
|
def requestWrite(self, node):
|
||||||
|
gcode_writer = Application.getInstance().getMeshFileHandler().getWriterByMimeType("text/x-gcode")
|
||||||
|
if not gcode_writer:
|
||||||
|
Logger.log("e", "Could not find GCode writer, not writing to removable drive %s", self.getName())
|
||||||
|
raise OutputDeviceError.WriteRequestFailedError()
|
||||||
|
|
||||||
|
file_name = None
|
||||||
|
for n in BreadthFirstIterator(node):
|
||||||
|
if n.getMeshData():
|
||||||
|
file_name = n.getName()
|
||||||
|
if file_name:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not file_name:
|
||||||
|
Logger.log("e", "Could not determine a proper file name when trying to write to %s, aborting", self.getName())
|
||||||
|
raise OutputDeviceError.WriteRequestFailedError()
|
||||||
|
|
||||||
|
file_name = os.path.join(self.getId(), os.path.splitext(file_name)[0] + ".gcode")
|
||||||
|
|
||||||
|
try:
|
||||||
|
Logger.log("d", "Writing to %s", file_name)
|
||||||
|
stream = open(file_name, "wt")
|
||||||
|
job = WriteMeshJob(gcode_writer, stream, node, MeshWriter.OutputMode.TextMode)
|
||||||
|
job.setFileName(file_name)
|
||||||
|
job.progress.connect(self._onProgress)
|
||||||
|
job.finished.connect(self._onFinished)
|
||||||
|
|
||||||
|
message = Message(catalog.i18nc("", "Saving to Removable Drive {0}").format(self.getName()), 0, False, -1)
|
||||||
|
message.show()
|
||||||
|
|
||||||
|
job._message = message
|
||||||
|
job.start()
|
||||||
|
except PermissionError as e:
|
||||||
|
raise OutputDeviceError.PermissionDeniedError() from e
|
||||||
|
except OSError as e:
|
||||||
|
raise OutputDeviceError.WriteRequestFailedError() from e
|
||||||
|
|
||||||
|
def _onProgress(self, job, progress):
|
||||||
|
if hasattr(job, "_message"):
|
||||||
|
job._message.setProgress(progress)
|
||||||
|
self.writeProgress.emit(self, progress)
|
||||||
|
|
||||||
|
def _onFinished(self, job):
|
||||||
|
if hasattr(job, "_message"):
|
||||||
|
job._message.hide()
|
||||||
|
job._message = None
|
||||||
|
self.writeFinished.emit(self)
|
||||||
|
if job.getResult():
|
||||||
|
message = Message(catalog.i18nc("", "Saved to Removable Drive {0} as {1}").format(self.getName(), os.path.basename(job.getFileName())))
|
||||||
|
message.addAction("eject", catalog.i18nc("", "Eject"), "eject", catalog.i18nc("", "Eject removable device {0}").format(self.getName()))
|
||||||
|
message.actionTriggered.connect(self._onActionTriggered)
|
||||||
|
message.show()
|
||||||
|
self.writeSuccess.emit(self)
|
||||||
|
else:
|
||||||
|
message = Message(catalog.i18nc("", "Could not save to removable drive {0}: {1}").format(self.getName(), str(job.getError())))
|
||||||
|
message.show()
|
||||||
|
self.writeError.emit(self)
|
||||||
|
job.getStream().close()
|
||||||
|
|
||||||
|
def _onActionTriggered(self, message, action):
|
||||||
|
if action == "eject":
|
||||||
|
Application.getInstance().getOutputDeviceManager().getOutputDevicePlugin("RemovableDriveOutputDevice").ejectDevice(self)
|
||||||
|
|
73
plugins/RemovableDriveOutputDevice/RemovableDrivePlugin.py
Normal file
73
plugins/RemovableDriveOutputDevice/RemovableDrivePlugin.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
|
# Uranium is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
from UM.Signal import Signal
|
||||||
|
from UM.Message import Message
|
||||||
|
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
|
||||||
|
|
||||||
|
from . import RemovableDriveOutputDevice
|
||||||
|
|
||||||
|
from UM.i18n import i18nCatalog
|
||||||
|
catalog = i18nCatalog("uranium")
|
||||||
|
|
||||||
|
class RemovableDrivePlugin(OutputDevicePlugin):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self._update_thread = threading.Thread(target = self._updateThread)
|
||||||
|
self._update_thread.setDaemon(True)
|
||||||
|
|
||||||
|
self._check_updates = True
|
||||||
|
|
||||||
|
self._drives = {}
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self._update_thread.start()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self._check_updates = False
|
||||||
|
self._update_thread.join()
|
||||||
|
|
||||||
|
self._addRemoveDrives({})
|
||||||
|
|
||||||
|
def checkRemovableDrives(self):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def ejectDevice(self, device):
|
||||||
|
result = self.performEjectDevice(device)
|
||||||
|
if result:
|
||||||
|
message = Message(catalog.i18n("Ejected {0}. You can now safely remove the drive.").format(device.getName()))
|
||||||
|
message.show()
|
||||||
|
else:
|
||||||
|
message = Message(catalog.i18n("Failed to eject {0}. Maybe it is still in use?").format(device.getName()))
|
||||||
|
message.show()
|
||||||
|
|
||||||
|
def performEjectDevice(self, device):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def _updateThread(self):
|
||||||
|
while self._check_updates:
|
||||||
|
result = self.checkRemovableDrives()
|
||||||
|
self._addRemoveDrives(result)
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
def _addRemoveDrives(self, drives):
|
||||||
|
# First, find and add all new or changed keys
|
||||||
|
for key, value in drives.items():
|
||||||
|
if key not in self._drives:
|
||||||
|
self.getOutputDeviceManager().addOutputDevice(RemovableDriveOutputDevice.RemovableDriveOutputDevice(key, value))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if self._drives[key] != value:
|
||||||
|
self.getOutputDeviceManager().removeOutputDevice(key)
|
||||||
|
self.getOutputDeviceManager().addOutputDevice(RemovableDriveOutputDevice.RemovableDriveOutputDevice(key, value))
|
||||||
|
|
||||||
|
# Then check for keys that have been removed
|
||||||
|
for key in self._drives.keys():
|
||||||
|
if key not in drives:
|
||||||
|
self.getOutputDeviceManager().removeOutputDevice(key)
|
||||||
|
|
||||||
|
self._drives = drives
|
@ -0,0 +1,98 @@
|
|||||||
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
|
# Copyright (c) 2013 David Braam
|
||||||
|
# Uranium is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
from . import RemovableDrivePlugin
|
||||||
|
|
||||||
|
import threading
|
||||||
|
import string
|
||||||
|
|
||||||
|
from ctypes import windll
|
||||||
|
from ctypes import wintypes
|
||||||
|
|
||||||
|
import ctypes
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from UM.i18n import i18nCatalog
|
||||||
|
catalog = i18nCatalog("uranium")
|
||||||
|
|
||||||
|
# WinAPI Constants that we need
|
||||||
|
# Hardcoded here due to stupid WinDLL stuff that does not give us access to these values.
|
||||||
|
DRIVE_REMOVABLE = 2
|
||||||
|
|
||||||
|
GENERIC_READ = 2147483648
|
||||||
|
GENERIC_WRITE = 1073741824
|
||||||
|
|
||||||
|
FILE_SHARE_READ = 1
|
||||||
|
FILE_SHARE_WRITE = 2
|
||||||
|
|
||||||
|
IOCTL_STORAGE_EJECT_MEDIA = 2967560
|
||||||
|
|
||||||
|
OPEN_EXISTING = 3
|
||||||
|
|
||||||
|
## Removable drive support for windows
|
||||||
|
class WindowsRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
|
||||||
|
def checkRemovableDrives(self):
|
||||||
|
drives = {}
|
||||||
|
|
||||||
|
bitmask = windll.kernel32.GetLogicalDrives()
|
||||||
|
# Check possible drive letters, from A to Z
|
||||||
|
# Note: using ascii_uppercase because we do not want this to change with locale!
|
||||||
|
for letter in string.ascii_uppercase:
|
||||||
|
drive = "{0}:/".format(letter)
|
||||||
|
|
||||||
|
# Do we really want to skip A and B?
|
||||||
|
# GetDriveTypeA explicitly wants a byte array of type ascii. It will accept a string, but this wont work
|
||||||
|
if bitmask & 1 and windll.kernel32.GetDriveTypeA(drive.encode("ascii")) == DRIVE_REMOVABLE:
|
||||||
|
volume_name = ""
|
||||||
|
name_buffer = ctypes.create_unicode_buffer(1024)
|
||||||
|
filesystem_buffer = ctypes.create_unicode_buffer(1024)
|
||||||
|
error = windll.kernel32.GetVolumeInformationW(ctypes.c_wchar_p(drive), name_buffer, ctypes.sizeof(name_buffer), None, None, None, filesystem_buffer, ctypes.sizeof(filesystem_buffer))
|
||||||
|
|
||||||
|
if error != 0:
|
||||||
|
volume_name = name_buffer.value
|
||||||
|
|
||||||
|
if not volume_name:
|
||||||
|
volume_name = catalog.i18nc("Default name for removable device", "Removable Drive")
|
||||||
|
|
||||||
|
# Certain readers will report themselves as a volume even when there is no card inserted, but will show an
|
||||||
|
# "No volume in drive" warning when trying to call GetDiskFreeSpace. However, they will not report a valid
|
||||||
|
# filesystem, so we can filter on that. In addition, this excludes other things with filesystems Windows
|
||||||
|
# does not support.
|
||||||
|
if filesystem_buffer.value == "":
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check for the free space. Some card readers show up as a drive with 0 space free when there is no card inserted.
|
||||||
|
freeBytes = ctypes.c_longlong(0)
|
||||||
|
if windll.kernel32.GetDiskFreeSpaceExA(drive.encode("ascii"), ctypes.byref(freeBytes), None, None) == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if freeBytes.value < 1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
drives[drive] = "{0} ({1}:)".format(volume_name, letter)
|
||||||
|
bitmask >>= 1
|
||||||
|
|
||||||
|
return drives
|
||||||
|
|
||||||
|
def performEjectDevice(self, device):
|
||||||
|
# Magic WinAPI stuff
|
||||||
|
# First, open a handle to the Device
|
||||||
|
handle = windll.kernel32.CreateFileA("\\\\.\\{0}".format(device.getId()[:-1]).encode("ascii"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, None, OPEN_EXISTING, 0, None )
|
||||||
|
|
||||||
|
if handle == -1:
|
||||||
|
print(windll.kernel32.GetLastError())
|
||||||
|
return
|
||||||
|
|
||||||
|
result = None
|
||||||
|
# Then, try and tell it to eject
|
||||||
|
if not windll.kernel32.DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, None, None, None, None, None, None):
|
||||||
|
result = False
|
||||||
|
else:
|
||||||
|
result = True
|
||||||
|
|
||||||
|
# Finally, close the handle
|
||||||
|
windll.kernel32.CloseHandle(handle)
|
||||||
|
return result
|
32
plugins/RemovableDriveOutputDevice/__init__.py
Normal file
32
plugins/RemovableDriveOutputDevice/__init__.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
|
# Uranium is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
import platform
|
||||||
|
|
||||||
|
from UM.i18n import i18nCatalog
|
||||||
|
catalog = i18nCatalog("uranium")
|
||||||
|
|
||||||
|
def getMetaData():
|
||||||
|
return {
|
||||||
|
"plugin": {
|
||||||
|
"name": catalog.i18nc("Removable Drive Output Device Plugin name", "Removable Drive Output Device Plugin"),
|
||||||
|
"author": "Ultimaker B.V.",
|
||||||
|
"description": catalog.i18nc("Removable Drive Output Device Plugin description", "Provides removable drive hotplugging and writing support"),
|
||||||
|
"version": "1.0",
|
||||||
|
"api": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def register(app):
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
from . import WindowsRemovableDrivePlugin
|
||||||
|
return { "output_device": WindowsRemovableDrivePlugin.WindowsRemovableDrivePlugin() }
|
||||||
|
elif platform.system() == "Darwin":
|
||||||
|
from . import OSXRemovableDrivePlugin
|
||||||
|
return { "output_device": OSXRemovableDrivePlugin.OSXRemovableDrivePlugin() }
|
||||||
|
elif platform.system() == "Linux":
|
||||||
|
from . import LinuxRemovableDrivePlugin
|
||||||
|
return { "output_device": LinuxRemovableDrivePlugin.LinuxRemovableDrivePlugin() }
|
||||||
|
else:
|
||||||
|
Logger.log("e", "Unsupported system %s, no removable device hotplugging support available.", platform.system())
|
||||||
|
return { }
|
@ -8,78 +8,9 @@ import QtQuick.Window 2.1
|
|||||||
|
|
||||||
import UM 1.0 as UM
|
import UM 1.0 as UM
|
||||||
|
|
||||||
UM.Dialog
|
UM.Wizard{
|
||||||
{
|
|
||||||
id: base
|
id: base
|
||||||
|
property bool printer: true
|
||||||
//: Add Printer dialog title
|
file: "ultimaker2.json"
|
||||||
title: qsTr("Add Printer");
|
firstRun: printer ? false : true
|
||||||
|
|
||||||
ColumnLayout
|
|
||||||
{
|
|
||||||
anchors.fill: parent;
|
|
||||||
|
|
||||||
Label
|
|
||||||
{
|
|
||||||
//: Add Printer wizard page title
|
|
||||||
text: qsTr("Add Printer");
|
|
||||||
font.pointSize: 18;
|
|
||||||
}
|
|
||||||
|
|
||||||
Label
|
|
||||||
{
|
|
||||||
//: Add Printer wizard page description
|
|
||||||
text: qsTr("Please select the type of printer:");
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollView
|
|
||||||
{
|
|
||||||
Layout.fillWidth: true;
|
|
||||||
|
|
||||||
ListView
|
|
||||||
{
|
|
||||||
id: machineList;
|
|
||||||
model: UM.Models.availableMachinesModel
|
|
||||||
delegate: RadioButton
|
|
||||||
{
|
|
||||||
exclusiveGroup: printerGroup;
|
|
||||||
text: model.name;
|
|
||||||
onClicked: ListView.view.currentIndex = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
//: Add Printer wizard field label
|
|
||||||
text: qsTr("Printer Name:");
|
|
||||||
}
|
|
||||||
|
|
||||||
TextField { id: machineName; Layout.fillWidth: true; text: machineList.model.getItem(machineList.currentIndex).name }
|
|
||||||
|
|
||||||
Item { Layout.fillWidth: true; Layout.fillHeight: true; }
|
|
||||||
|
|
||||||
ExclusiveGroup { id: printerGroup; }
|
|
||||||
}
|
|
||||||
|
|
||||||
rightButtons: [
|
|
||||||
Button
|
|
||||||
{
|
|
||||||
//: Add Printer wizarad button
|
|
||||||
text: qsTr("Next");
|
|
||||||
onClicked:
|
|
||||||
{
|
|
||||||
if(machineList.currentIndex != -1)
|
|
||||||
{
|
|
||||||
UM.Models.availableMachinesModel.createMachine(machineList.currentIndex, machineName.text)
|
|
||||||
base.visible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Button
|
|
||||||
{
|
|
||||||
//: Add Printer wizarad button
|
|
||||||
text: qsTr("Cancel");
|
|
||||||
onClicked: base.visible = false;
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import QtQuick.Controls.Styles 1.1
|
|||||||
import QtQuick.Layouts 1.1
|
import QtQuick.Layouts 1.1
|
||||||
import QtQuick.Dialogs 1.1
|
import QtQuick.Dialogs 1.1
|
||||||
|
|
||||||
import UM 1.0 as UM
|
import UM 1.1 as UM
|
||||||
|
|
||||||
UM.MainWindow {
|
UM.MainWindow {
|
||||||
id: base
|
id: base
|
||||||
@ -30,9 +30,13 @@ UM.MainWindow {
|
|||||||
title: qsTr("&File");
|
title: qsTr("&File");
|
||||||
|
|
||||||
MenuItem { action: actions.open; }
|
MenuItem { action: actions.open; }
|
||||||
MenuItem { action: actions.save; }
|
|
||||||
|
|
||||||
MenuSeparator { }
|
Menu {
|
||||||
|
id: recentFilesMenu;
|
||||||
|
title: "Open Recent"
|
||||||
|
iconName: "document-open-recent";
|
||||||
|
|
||||||
|
enabled: Printer.recentFiles.length > 0;
|
||||||
|
|
||||||
Instantiator {
|
Instantiator {
|
||||||
model: Printer.recentFiles
|
model: Printer.recentFiles
|
||||||
@ -41,13 +45,37 @@ UM.MainWindow {
|
|||||||
var path = modelData.toString()
|
var path = modelData.toString()
|
||||||
return (index + 1) + ". " + path.slice(path.lastIndexOf("/") + 1);
|
return (index + 1) + ". " + path.slice(path.lastIndexOf("/") + 1);
|
||||||
}
|
}
|
||||||
onTriggered: {
|
onTriggered: UM.MeshFileHandler.readLocalFile(modelData);
|
||||||
UM.MeshFileHandler.readLocalFile(modelData);
|
}
|
||||||
Printer.setPlatformActivity(true)
|
onObjectAdded: recentFilesMenu.insertItem(index, object)
|
||||||
|
onObjectRemoved: recentFilesMenu.removeItem(object)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onObjectAdded: fileMenu.insertItem(index, object)
|
|
||||||
onObjectRemoved: fileMenu.removeItem(object)
|
MenuSeparator { }
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Save Selection to File";
|
||||||
|
enabled: UM.Selection.hasSelection;
|
||||||
|
iconName: "document-save-as";
|
||||||
|
onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file");
|
||||||
|
}
|
||||||
|
Menu {
|
||||||
|
id: saveAllMenu
|
||||||
|
title: "Save All"
|
||||||
|
iconName: "document-save";
|
||||||
|
enabled: devicesModel.count > 0 && UM.Backend.progress > 0.99;
|
||||||
|
|
||||||
|
Instantiator {
|
||||||
|
model: UM.OutputDevicesModel { id: devicesModel; }
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: model.description;
|
||||||
|
onTriggered: UM.OutputDeviceManager.requestWriteToDevice(model.id);
|
||||||
|
}
|
||||||
|
onObjectAdded: saveAllMenu.insertItem(index, object)
|
||||||
|
onObjectRemoved: saveAllMenu.removeItem(object)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuSeparator { }
|
MenuSeparator { }
|
||||||
@ -65,7 +93,26 @@ UM.MainWindow {
|
|||||||
MenuItem { action: actions.deleteSelection; }
|
MenuItem { action: actions.deleteSelection; }
|
||||||
MenuItem { action: actions.deleteAll; }
|
MenuItem { action: actions.deleteAll; }
|
||||||
}
|
}
|
||||||
|
Menu
|
||||||
|
{
|
||||||
|
title: qsTr("&View");
|
||||||
|
id: top_view_menu
|
||||||
|
Instantiator
|
||||||
|
{
|
||||||
|
model: UM.Models.viewModel
|
||||||
|
MenuItem
|
||||||
|
{
|
||||||
|
text: model.name;
|
||||||
|
checkable: true;
|
||||||
|
checked: model.active;
|
||||||
|
exclusiveGroup: view_menu_top_group;
|
||||||
|
onTriggered: UM.Controller.setActiveView(model.id);
|
||||||
|
}
|
||||||
|
onObjectAdded: top_view_menu.insertItem(index, object)
|
||||||
|
onObjectRemoved: top_view_menu.removeItem(object)
|
||||||
|
}
|
||||||
|
ExclusiveGroup { id: view_menu_top_group; }
|
||||||
|
}
|
||||||
Menu {
|
Menu {
|
||||||
id: machineMenu;
|
id: machineMenu;
|
||||||
//: Machine menu
|
//: Machine menu
|
||||||
@ -281,7 +328,6 @@ UM.MainWindow {
|
|||||||
|
|
||||||
addMachineAction: actions.addMachine;
|
addMachineAction: actions.addMachine;
|
||||||
configureMachinesAction: actions.configureMachines;
|
configureMachinesAction: actions.configureMachines;
|
||||||
saveAction: actions.save;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@ -368,7 +414,7 @@ UM.MainWindow {
|
|||||||
resetAll.onTriggered: Printer.resetAll()
|
resetAll.onTriggered: Printer.resetAll()
|
||||||
reloadAll.onTriggered: Printer.reloadAll()
|
reloadAll.onTriggered: Printer.reloadAll()
|
||||||
|
|
||||||
addMachine.onTriggered: addMachine.visible = true;
|
addMachine.onTriggered: addMachineWizard.visible = true;
|
||||||
|
|
||||||
preferences.onTriggered: preferences.visible = true;
|
preferences.onTriggered: preferences.visible = true;
|
||||||
configureMachines.onTriggered: { preferences.visible = true; preferences.setPage(2); }
|
configureMachines.onTriggered: { preferences.visible = true; preferences.setPage(2); }
|
||||||
@ -439,38 +485,25 @@ UM.MainWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDialog {
|
|
||||||
id: saveDialog;
|
|
||||||
//: File save dialog title
|
|
||||||
title: qsTr("Save File");
|
|
||||||
selectExisting: false;
|
|
||||||
|
|
||||||
modality: UM.Application.platform == "linux" ? Qt.NonModal : Qt.WindowModal;
|
|
||||||
|
|
||||||
nameFilters: UM.MeshFileHandler.supportedWriteFileTypes
|
|
||||||
|
|
||||||
onAccepted:
|
|
||||||
{
|
|
||||||
UM.MeshFileHandler.writeLocalFile(fileUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EngineLog {
|
EngineLog {
|
||||||
id: engineLog;
|
id: engineLog;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddMachineWizard {
|
AddMachineWizard {
|
||||||
id: addMachine;
|
id: addMachineWizard
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AboutDialog {
|
AboutDialog {
|
||||||
id: aboutDialog
|
id: aboutDialog
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: Printer
|
target: Printer
|
||||||
onRequestAddPrinter: addMachine.visible = true;
|
onRequestAddPrinter: {
|
||||||
onWriteToLocalFileRequested: saveDialog.open();
|
addMachineWizard.visible = true
|
||||||
|
addMachineWizard.printer = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: UM.Theme.load(UM.Resources.getPath(UM.Resources.ThemesLocation, "cura"))
|
Component.onCompleted: UM.Theme.load(UM.Resources.getPath(UM.Resources.ThemesLocation, "cura"))
|
||||||
|
@ -6,47 +6,18 @@ import QtQuick.Controls 1.1
|
|||||||
import QtQuick.Controls.Styles 1.1
|
import QtQuick.Controls.Styles 1.1
|
||||||
import QtQuick.Layouts 1.1
|
import QtQuick.Layouts 1.1
|
||||||
|
|
||||||
import UM 1.0 as UM
|
import UM 1.1 as UM
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: base;
|
id: base;
|
||||||
|
|
||||||
property Action saveAction;
|
|
||||||
|
|
||||||
property real progress: UM.Backend.progress;
|
property real progress: UM.Backend.progress;
|
||||||
property bool activity: Printer.getPlatformActivity;
|
property bool activity: Printer.getPlatformActivity;
|
||||||
Behavior on progress { NumberAnimation { duration: 250; } }
|
Behavior on progress { NumberAnimation { duration: 250; } }
|
||||||
|
|
||||||
property string currentDevice: "local_file"
|
|
||||||
property bool defaultOverride: false;
|
|
||||||
property bool defaultAmbiguous: false;
|
|
||||||
|
|
||||||
property variant printDuration: PrintInformation.currentPrintTime;
|
property variant printDuration: PrintInformation.currentPrintTime;
|
||||||
property real printMaterialAmount: PrintInformation.materialAmount;
|
property real printMaterialAmount: PrintInformation.materialAmount;
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: Printer;
|
|
||||||
onOutputDevicesChanged: {
|
|
||||||
if(!base.defaultOverride) {
|
|
||||||
base.defaultAmbiguous = false;
|
|
||||||
var device = null;
|
|
||||||
for(var i in Printer.outputDevices) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle{
|
Rectangle{
|
||||||
id: background
|
id: background
|
||||||
implicitWidth: base.width;
|
implicitWidth: base.width;
|
||||||
@ -76,7 +47,7 @@ Rectangle {
|
|||||||
visible: base.progress >= 0 && base.progress < 0.99 ? false : true
|
visible: base.progress >= 0 && base.progress < 0.99 ? false : true
|
||||||
color: UM.Theme.colors.save_button_estimated_text;
|
color: UM.Theme.colors.save_button_estimated_text;
|
||||||
font: UM.Theme.fonts.small;
|
font: UM.Theme.fonts.small;
|
||||||
text:
|
text: {
|
||||||
if(base.activity == false) {
|
if(base.activity == false) {
|
||||||
//: Save button label
|
//: Save button label
|
||||||
return qsTr("Please load a 3D model");
|
return qsTr("Please load a 3D model");
|
||||||
@ -90,6 +61,8 @@ Rectangle {
|
|||||||
//: Save button label
|
//: Save button label
|
||||||
return qsTr("Estimated Print-time");
|
return qsTr("Estimated Print-time");
|
||||||
}
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Label {
|
Label {
|
||||||
id: printDurationLabel
|
id: printDurationLabel
|
||||||
@ -113,7 +86,7 @@ Rectangle {
|
|||||||
elide: mediumLengthDuration ? Text.ElideRight : Text.ElideNone
|
elide: mediumLengthDuration ? Text.ElideRight : Text.ElideNone
|
||||||
visible: base.activity == false || base.progress < 0.99 ? false : true
|
visible: base.activity == false || base.progress < 0.99 ? false : true
|
||||||
//: Print material amount save button label
|
//: Print material amount save button label
|
||||||
text: base.printMaterialAmount < 0 ? "" : qsTr("%1m material").arg(base.printMaterialAmount);
|
text: base.printMaterialAmount < 0 ? "" : qsTr("%1m of Material").arg(base.printMaterialAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@ -134,29 +107,28 @@ Rectangle {
|
|||||||
anchors.topMargin: UM.Theme.sizes.save_button_text_margin.height;
|
anchors.topMargin: UM.Theme.sizes.save_button_text_margin.height;
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
|
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
|
||||||
tooltip: ''
|
tooltip: UM.OutputDeviceManager.activeDeviceDescription;
|
||||||
enabled: progress > 0.99 && base.activity == true
|
enabled: progress > 0.99 && base.activity == true
|
||||||
|
|
||||||
width: infoBox.width/6*4.5
|
width: infoBox.width/6*4.5
|
||||||
height: UM.Theme.sizes.save_button_save_to_button.height
|
height: UM.Theme.sizes.save_button_save_to_button.height
|
||||||
|
|
||||||
|
text: UM.OutputDeviceManager.activeDeviceShortDescription;
|
||||||
|
|
||||||
style: ButtonStyle {
|
style: ButtonStyle {
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: !control.enabled ? UM.Theme.colors.save_button_inactive : control.hovered ? UM.Theme.colors.save_button_active_hover : UM.Theme.colors.save_button_active;
|
color: !control.enabled ? UM.Theme.colors.save_button_inactive : control.hovered ? UM.Theme.colors.save_button_active_hover : UM.Theme.colors.save_button_active;
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.centerIn: parent
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
color: UM.Theme.colors.save_button_safe_to_text;
|
color: UM.Theme.colors.save_button_safe_to_text;
|
||||||
font: UM.Theme.fonts.sidebar_save_to;
|
font: UM.Theme.fonts.sidebar_save_to;
|
||||||
text: Printer.outputDevices[base.currentDevice].shortDescription;
|
text: control.text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
label: Item { }
|
||||||
}
|
}
|
||||||
onClicked:
|
onClicked: UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice)
|
||||||
if(base.defaultAmbiguous) {
|
|
||||||
devicesMenu.popup();
|
|
||||||
} else {
|
|
||||||
Printer.writeToOutputDevice(base.currentDevice);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
@ -165,16 +137,20 @@ Rectangle {
|
|||||||
anchors.topMargin: UM.Theme.sizes.save_button_text_margin.height
|
anchors.topMargin: UM.Theme.sizes.save_button_text_margin.height
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: UM.Theme.sizes.default_margin.width;
|
anchors.rightMargin: UM.Theme.sizes.default_margin.width;
|
||||||
tooltip: ''
|
|
||||||
|
tooltip: qsTr("Select the active output device");
|
||||||
|
|
||||||
width: infoBox.width/6*1.3 - UM.Theme.sizes.save_button_text_margin.height;
|
width: infoBox.width/6*1.3 - UM.Theme.sizes.save_button_text_margin.height;
|
||||||
height: UM.Theme.sizes.save_button_save_to_button.height
|
height: UM.Theme.sizes.save_button_save_to_button.height
|
||||||
|
|
||||||
|
iconSource: UM.Theme.icons[UM.OutputDeviceManager.activeDeviceIconName];
|
||||||
|
|
||||||
style: ButtonStyle {
|
style: ButtonStyle {
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: UM.Theme.colors.save_button_background;
|
color: UM.Theme.colors.save_button_background;
|
||||||
border.width: control.hovered ? UM.Theme.sizes.save_button_border.width : 0
|
border.width: control.hovered ? UM.Theme.sizes.save_button_border.width : 0
|
||||||
border.color: UM.Theme.colors.save_button_border
|
border.color: UM.Theme.colors.save_button_border
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: deviceSelectionIcon
|
id: deviceSelectionIcon
|
||||||
color: UM.Theme.colors.save_button_background;
|
color: UM.Theme.colors.save_button_background;
|
||||||
@ -183,14 +159,13 @@ Rectangle {
|
|||||||
anchors.verticalCenter: parent.verticalCenter;
|
anchors.verticalCenter: parent.verticalCenter;
|
||||||
width: parent.height - UM.Theme.sizes.save_button_text_margin.width ;
|
width: parent.height - UM.Theme.sizes.save_button_text_margin.width ;
|
||||||
height: parent.height - UM.Theme.sizes.save_button_text_margin.width;
|
height: parent.height - UM.Theme.sizes.save_button_text_margin.width;
|
||||||
|
|
||||||
UM.RecolorImage {
|
UM.RecolorImage {
|
||||||
anchors.centerIn: parent;
|
anchors.fill: parent;
|
||||||
width: parent.width;
|
|
||||||
height: parent.height;
|
|
||||||
sourceSize.width: width;
|
sourceSize.width: width;
|
||||||
sourceSize.height: height;
|
sourceSize.height: height;
|
||||||
color: UM.Theme.colors.save_button_active
|
color: UM.Theme.colors.save_button_active
|
||||||
source: UM.Theme.icons[Printer.outputDevices[base.currentDevice].icon];
|
source: control.iconSource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Label {
|
Label {
|
||||||
@ -203,24 +178,20 @@ Rectangle {
|
|||||||
color: UM.Theme.colors.save_button_active;
|
color: UM.Theme.colors.save_button_active;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
label: Item { }
|
||||||
}
|
}
|
||||||
|
|
||||||
menu: Menu {
|
menu: Menu {
|
||||||
id: devicesMenu;
|
id: devicesMenu;
|
||||||
Instantiator {
|
Instantiator {
|
||||||
model: Printer.outputDeviceNames;
|
model: devicesModel;
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: Printer.outputDevices[modelData].description;
|
text: model.description
|
||||||
checkable: true;
|
checkable: true;
|
||||||
checked: base.defaultAmbiguous ? false : modelData == base.currentDevice;
|
checked: model.id == UM.OutputDeviceManager.activeDevice;
|
||||||
exclusiveGroup: devicesMenuGroup;
|
exclusiveGroup: devicesMenuGroup;
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
base.defaultOverride = true;
|
UM.OutputDeviceManager.setActiveDevice(model.id);
|
||||||
base.currentDevice = modelData;
|
|
||||||
if(base.defaultAmbiguous) {
|
|
||||||
base.defaultAmbiguous = false;
|
|
||||||
Printer.writeToOutputDevice(modelData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onObjectAdded: devicesMenu.insertItem(index, object)
|
onObjectAdded: devicesMenu.insertItem(index, object)
|
||||||
@ -230,4 +201,8 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UM.OutputDevicesModel {
|
||||||
|
id: devicesModel;
|
||||||
|
}
|
||||||
}
|
}
|
@ -13,7 +13,6 @@ Rectangle {
|
|||||||
|
|
||||||
property Action addMachineAction;
|
property Action addMachineAction;
|
||||||
property Action configureMachinesAction;
|
property Action configureMachinesAction;
|
||||||
property alias saveAction: saveButton.saveAction;
|
|
||||||
|
|
||||||
color: UM.Theme.colors.sidebar;
|
color: UM.Theme.colors.sidebar;
|
||||||
|
|
||||||
|
109
resources/qml/WizardPages/AddMachine.qml
Normal file
109
resources/qml/WizardPages/AddMachine.qml
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// Copyright (c) 2015 Ultimaker B.V.
|
||||||
|
// Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
import QtQuick 2.2
|
||||||
|
import QtQuick.Controls 1.1
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import QtQuick.Window 2.1
|
||||||
|
|
||||||
|
import UM 1.0 as UM
|
||||||
|
import ".."
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: wizardPage
|
||||||
|
property string title
|
||||||
|
signal openFile(string fileName)
|
||||||
|
signal closeWizard()
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: rootElement
|
||||||
|
onFinalClicked: {//You can add functions here that get triggered when the final button is clicked in the wizard-element
|
||||||
|
saveMachine()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: parent.title
|
||||||
|
font.pointSize: 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
//: Add Printer wizard page description
|
||||||
|
text: qsTr("Please select the type of printer:");
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
ListView {
|
||||||
|
id: machineList;
|
||||||
|
model: UM.Models.availableMachinesModel
|
||||||
|
delegate: RadioButton {
|
||||||
|
id:machine_button
|
||||||
|
exclusiveGroup: printerGroup;
|
||||||
|
checked: ListView.view.currentIndex == index ? true : false
|
||||||
|
text: model.name;
|
||||||
|
onClicked: {
|
||||||
|
ListView.view.currentIndex = index;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("Variation:");
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
ListView {
|
||||||
|
id: variations_list
|
||||||
|
model: machineList.model.getItem(machineList.currentIndex).variations
|
||||||
|
delegate: RadioButton {
|
||||||
|
id: variation_radio_button
|
||||||
|
checked: ListView.view.currentIndex == index ? true : false
|
||||||
|
exclusiveGroup: variationGroup;
|
||||||
|
text: model.name;
|
||||||
|
onClicked: ListView.view.currentIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
//: Add Printer wizard field label
|
||||||
|
text: qsTr("Printer Name:");
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField { id: machineName; Layout.fillWidth: true; text: machineList.model.getItem(machineList.currentIndex).name }
|
||||||
|
Item { Layout.fillWidth: true; Layout.fillHeight: true; }
|
||||||
|
ExclusiveGroup { id: printerGroup; }
|
||||||
|
ExclusiveGroup { id: variationGroup; }
|
||||||
|
|
||||||
|
function getSpecialMachineType(machineId){
|
||||||
|
for (var i = 0; i < UM.Models.addMachinesModel.rowCount(); i++) {
|
||||||
|
if (UM.Models.addMachinesModel.getItem(i).name == machineId){
|
||||||
|
return UM.Models.addMachinesModel.getItem(i).name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveMachine(){
|
||||||
|
if(machineList.currentIndex != -1) {
|
||||||
|
UM.Models.availableMachinesModel.createMachine(machineList.currentIndex, variations_list.currentIndex, machineName.text)
|
||||||
|
|
||||||
|
var originalString = "Ultimaker Original"
|
||||||
|
var originalPlusString = "Ultimaker Original+"
|
||||||
|
var originalMachineType = getSpecialMachineType(originalString)
|
||||||
|
|
||||||
|
if (UM.Models.availableMachinesModel.getItem(machineList.currentIndex).name == originalMachineType){
|
||||||
|
var variation = UM.Models.availableMachinesModel.getItem(machineList.currentIndex).variations.getItem(variations_list.currentIndex).name
|
||||||
|
if (variation == originalString || variation == originalPlusString){
|
||||||
|
console.log(UM.Models.availableMachinesModel.getItem(machineList.currentIndex).variations.getItem(variations_list.currentIndex).type)
|
||||||
|
wizardPage.openFile(UM.Models.availableMachinesModel.getItem(machineList.currentIndex).variations.getItem(variations_list.currentIndex).type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wizardPage.closeWizard()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
52
resources/qml/WizardPages/Bedleveling.qml
Normal file
52
resources/qml/WizardPages/Bedleveling.qml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) 2015 Ultimaker B.V.
|
||||||
|
// Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
import QtQuick 2.2
|
||||||
|
import QtQuick.Controls 1.1
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import QtQuick.Window 2.1
|
||||||
|
|
||||||
|
import UM 1.0 as UM
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
property string title
|
||||||
|
anchors.fill: parent;
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: parent.title
|
||||||
|
font.pointSize: 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
//: Add Printer wizard page description
|
||||||
|
text: qsTr("Please select the type of printer:");
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
Layout.fillWidth: true;
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: machineList;
|
||||||
|
model: UM.Models.availableMachinesModel
|
||||||
|
delegate: RadioButton {
|
||||||
|
exclusiveGroup: printerGroup;
|
||||||
|
text: model.name;
|
||||||
|
onClicked: {
|
||||||
|
ListView.view.currentIndex = index;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
//: Add Printer wizard field label
|
||||||
|
text: qsTr("Printer Name:");
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField { id: machineName; Layout.fillWidth: true; text: machineList.model.getItem(machineList.currentIndex).name }
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true; Layout.fillHeight: true; }
|
||||||
|
|
||||||
|
ExclusiveGroup { id: printerGroup; }
|
||||||
|
}
|
52
resources/qml/WizardPages/SelectUpgradedParts.qml
Normal file
52
resources/qml/WizardPages/SelectUpgradedParts.qml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) 2015 Ultimaker B.V.
|
||||||
|
// Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
import QtQuick 2.2
|
||||||
|
import QtQuick.Controls 1.1
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import QtQuick.Window 2.1
|
||||||
|
|
||||||
|
import UM 1.0 as UM
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
property string title
|
||||||
|
anchors.fill: parent;
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: parent.title
|
||||||
|
font.pointSize: 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
//: Add Printer wizard page description
|
||||||
|
text: qsTr("Please select the type of printer:");
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
Layout.fillWidth: true;
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: machineList;
|
||||||
|
model: UM.Models.availableMachinesModel
|
||||||
|
delegate: RadioButton {
|
||||||
|
exclusiveGroup: printerGroup;
|
||||||
|
text: model.name;
|
||||||
|
onClicked: {
|
||||||
|
ListView.view.currentIndex = index;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
//: Add Printer wizard field label
|
||||||
|
text: qsTr("Printer Name:");
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField { id: machineName; Layout.fillWidth: true; text: machineList.model.getItem(machineList.currentIndex).name }
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true; Layout.fillHeight: true; }
|
||||||
|
|
||||||
|
ExclusiveGroup { id: printerGroup; }
|
||||||
|
}
|
52
resources/qml/WizardPages/UltimakerCheckup.qml
Normal file
52
resources/qml/WizardPages/UltimakerCheckup.qml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) 2015 Ultimaker B.V.
|
||||||
|
// Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
import QtQuick 2.2
|
||||||
|
import QtQuick.Controls 1.1
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import QtQuick.Window 2.1
|
||||||
|
|
||||||
|
import UM 1.0 as UM
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
property string title
|
||||||
|
anchors.fill: parent;
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: parent.title
|
||||||
|
font.pointSize: 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
//: Add Printer wizard page description
|
||||||
|
text: qsTr("Please select the type of printer:");
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
Layout.fillWidth: true;
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: machineList;
|
||||||
|
model: UM.Models.availableMachinesModel
|
||||||
|
delegate: RadioButton {
|
||||||
|
exclusiveGroup: printerGroup;
|
||||||
|
text: model.name;
|
||||||
|
onClicked: {
|
||||||
|
ListView.view.currentIndex = index;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
//: Add Printer wizard field label
|
||||||
|
text: qsTr("Printer Name:");
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField { id: machineName; Layout.fillWidth: true; text: machineList.model.getItem(machineList.currentIndex).name }
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true; Layout.fillHeight: true; }
|
||||||
|
|
||||||
|
ExclusiveGroup { id: printerGroup; }
|
||||||
|
}
|
52
resources/qml/WizardPages/UpgradeFirmware.qml
Normal file
52
resources/qml/WizardPages/UpgradeFirmware.qml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) 2015 Ultimaker B.V.
|
||||||
|
// Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
import QtQuick 2.2
|
||||||
|
import QtQuick.Controls 1.1
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import QtQuick.Window 2.1
|
||||||
|
|
||||||
|
import UM 1.0 as UM
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
property string title
|
||||||
|
anchors.fill: parent;
|
||||||
|
signal openFile(string fileName)
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: parent.title
|
||||||
|
font.pointSize: 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
//: Add Printer wizard page description
|
||||||
|
text: qsTr("Please select the type of printer:");
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
Layout.fillWidth: true;
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: machineList;
|
||||||
|
model: UM.Models.availableMachinesModel
|
||||||
|
delegate: RadioButton {
|
||||||
|
exclusiveGroup: printerGroup;
|
||||||
|
text: model.name;
|
||||||
|
onClicked: {
|
||||||
|
ListView.view.currentIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
//: Add Printer wizard field label
|
||||||
|
text: qsTr("Printer Name:");
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField { id: machineName; Layout.fillWidth: true; text: machineList.model.getItem(machineList.currentIndex).name }
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true; Layout.fillHeight: true; }
|
||||||
|
|
||||||
|
ExclusiveGroup { id: printerGroup; }
|
||||||
|
}
|
@ -1,5 +1,12 @@
|
|||||||
{
|
{
|
||||||
"visible": false,
|
"visible": false,
|
||||||
|
"version": 1,
|
||||||
|
"author": "other",
|
||||||
|
"manufacturer": "other",
|
||||||
|
"author": "other",
|
||||||
|
|
||||||
|
"add_pages": [{"page": "AddMachine", "title": "Add new printer"}],
|
||||||
|
|
||||||
"machine_settings": {
|
"machine_settings": {
|
||||||
"machine_start_gcode": {
|
"machine_start_gcode": {
|
||||||
"default": "G28 ; Home\nG1 Z15.0 F6000 ;move the platform down 15mm\n;Prime the extruder\nG92 E0\nG1 F200 E3\nG92 E0"
|
"default": "G28 ; Home\nG1 Z15.0 F6000 ;move the platform down 15mm\n;Prime the extruder\nG92 E0\nG1 F200 E3\nG92 E0"
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"id": "GRRneo",
|
"id": "grr_neo",
|
||||||
|
"version": 1,
|
||||||
"name": "German RepRap Neo",
|
"name": "German RepRap Neo",
|
||||||
|
"manufacturer": "German RepRap",
|
||||||
|
"author": "other",
|
||||||
"icon": "icon_ultimaker.png",
|
"icon": "icon_ultimaker.png",
|
||||||
"platform": "grr_neo_platform.stl",
|
"platform": "grr_neo_platform.stl",
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"id": "hephestos",
|
"id": "hephestos",
|
||||||
|
"version": 1,
|
||||||
"name": "BQ Prusa i3 Hephestos",
|
"name": "BQ Prusa i3 Hephestos",
|
||||||
|
"manufacturer": "BQ",
|
||||||
|
"author": "other",
|
||||||
"platform": "hephestos_platform.stl",
|
"platform": "hephestos_platform.stl",
|
||||||
"inherits": "fdmprinter.json",
|
"inherits": "fdmprinter.json",
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"id": "hephestos_XL",
|
"id": "hephestos_xl",
|
||||||
|
"version": 1,
|
||||||
"name": "BQ Prusa i3 Hephestos XL",
|
"name": "BQ Prusa i3 Hephestos XL",
|
||||||
|
"manufacturer": "BQ",
|
||||||
|
"author": "other",
|
||||||
"platform": "hephestos_platform.stl",
|
"platform": "hephestos_platform.stl",
|
||||||
"inherits": "fdmprinter.json",
|
"inherits": "fdmprinter.json",
|
||||||
|
|
@ -1,7 +1,10 @@
|
|||||||
{
|
{
|
||||||
"id": "prusa_i3",
|
"id": "prusa_i3",
|
||||||
"icon": "icon_ultimaker2.png",
|
"version": 1,
|
||||||
"name": "Prusa i3",
|
"name": "Prusa i3",
|
||||||
|
"manufacturer": "Prusa",
|
||||||
|
"author": "other",
|
||||||
|
"icon": "icon_ultimaker2.png",
|
||||||
"platform": "prusai3_platform.stl",
|
"platform": "prusai3_platform.stl",
|
||||||
|
|
||||||
"inherits": "fdmprinter.json",
|
"inherits": "fdmprinter.json",
|
@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"id": "ultimaker2",
|
"id": "ultimaker2",
|
||||||
|
"version": 1,
|
||||||
"name": "Ultimaker 2",
|
"name": "Ultimaker 2",
|
||||||
|
"manufacturer": "Ultimaker",
|
||||||
|
"author": "Ultimaker",
|
||||||
"icon": "icon_ultimaker2.png",
|
"icon": "icon_ultimaker2.png",
|
||||||
"platform": "ultimaker2_platform.obj",
|
"platform": "ultimaker2_platform.obj",
|
||||||
"platform_texture": "Ultimaker2backplate.png",
|
"platform_texture": "Ultimaker2backplate.png",
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"id": "ultimaker2extended",
|
"id": "ultimaker2_extended",
|
||||||
|
"version": 1,
|
||||||
"name": "Ultimaker 2 Extended",
|
"name": "Ultimaker 2 Extended",
|
||||||
|
"manufacturer": "Ultimaker",
|
||||||
|
"author": "Ultimaker",
|
||||||
"icon": "icon_ultimaker2.png",
|
"icon": "icon_ultimaker2.png",
|
||||||
"platform": "ultimaker2_platform.obj",
|
"platform": "ultimaker2_platform.obj",
|
||||||
"platform_texture": "Ultimaker2backplate.png",
|
"platform_texture": "Ultimaker2backplate.png",
|
@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"id": "ultimaker2go",
|
"id": "ultimaker2_go",
|
||||||
|
"version": 1,
|
||||||
"name": "Ultimaker 2 Go",
|
"name": "Ultimaker 2 Go",
|
||||||
|
"manufacturer": "Ultimaker",
|
||||||
|
"author": "Ultimaker",
|
||||||
"icon": "icon_ultimaker2.png",
|
"icon": "icon_ultimaker2.png",
|
||||||
"platform": "ultimaker2go_platform.obj",
|
"platform": "ultimaker2go_platform.obj",
|
||||||
"platform_texture": "Ultimaker2backplate.png",
|
"platform_texture": "Ultimaker2backplate.png",
|
@ -1,11 +1,21 @@
|
|||||||
{
|
{
|
||||||
"id": "ultimaker_original",
|
"id": "ultimaker_original",
|
||||||
|
"version": 1,
|
||||||
"name": "Ultimaker Original",
|
"name": "Ultimaker Original",
|
||||||
|
"manufacturer": "Ultimaker",
|
||||||
|
"author": "Ultimaker",
|
||||||
"icon": "icon_ultimaker.png",
|
"icon": "icon_ultimaker.png",
|
||||||
"platform": "ultimaker_platform.stl",
|
"platform": "ultimaker_platform.stl",
|
||||||
|
|
||||||
"inherits": "fdmprinter.json",
|
"inherits": "fdmprinter.json",
|
||||||
|
|
||||||
|
"add_pages": [
|
||||||
|
{"page": "SelectUpgradedParts", "title": "Select Upgraded Parts"},
|
||||||
|
{"page": "UpgradeFirmware", "title": "Upgrade Ultimaker Firmware"},
|
||||||
|
{"page": "UltimakerCheckup", "title": "Ultimaker Checkup"},
|
||||||
|
{"page": "Bedleveling", "title": "Bedleveling Wizard"}
|
||||||
|
],
|
||||||
|
|
||||||
"machine_settings": {
|
"machine_settings": {
|
||||||
"machine_width": { "default": 205 },
|
"machine_width": { "default": 205 },
|
||||||
"machine_height": { "default": 200 },
|
"machine_height": { "default": 200 },
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"id": "ultimaker_original_plus",
|
"id": "ultimaker_original_plus",
|
||||||
|
"version": 1,
|
||||||
"name": "Ultimaker Original+",
|
"name": "Ultimaker Original+",
|
||||||
|
"manufacturer": "Ultimaker",
|
||||||
|
"author": "Ultimaker",
|
||||||
"icon": "icon_ultimaker.png",
|
"icon": "icon_ultimaker.png",
|
||||||
"platform": "ultimaker2_platform.obj",
|
"platform": "ultimaker2_platform.obj",
|
||||||
"platform_texture": "UltimakerPlusbackplate.png",
|
"platform_texture": "UltimakerPlusbackplate.png",
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"id": "witbox",
|
"id": "bq_witbox",
|
||||||
|
"version": 1,
|
||||||
"name": "BQ Witbox",
|
"name": "BQ Witbox",
|
||||||
|
"manufacturer": "BQ",
|
||||||
|
"author": "other",
|
||||||
"platform": "witbox_platform.stl",
|
"platform": "witbox_platform.stl",
|
||||||
"inherits": "fdmprinter.json",
|
"inherits": "fdmprinter.json",
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user