mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-06-04 11:14:21 +08:00
WIP: Make import/export profile work
This commit is contained in:
parent
5bb6efcb3e
commit
27f7d16a57
@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt, pyqtSlot
|
||||||
|
|
||||||
from UM.Qt.ListModel import ListModel
|
from UM.Qt.ListModel import ListModel
|
||||||
|
|
||||||
@ -74,3 +74,45 @@ class QualityManagementModel(ListModel):
|
|||||||
item_list += quality_changes_item_list
|
item_list += quality_changes_item_list
|
||||||
|
|
||||||
self.setItems(item_list)
|
self.setItems(item_list)
|
||||||
|
|
||||||
|
# TODO: Duplicated code here from InstanceContainersModel. Refactor and remove this later.
|
||||||
|
#
|
||||||
|
## Gets a list of the possible file filters that the plugins have
|
||||||
|
# registered they can read or write. The convenience meta-filters
|
||||||
|
# "All Supported Types" and "All Files" are added when listing
|
||||||
|
# readers, but not when listing writers.
|
||||||
|
#
|
||||||
|
# \param io_type \type{str} name of the needed IO type
|
||||||
|
# \return A list of strings indicating file name filters for a file
|
||||||
|
# dialog.
|
||||||
|
@pyqtSlot(str, result = "QVariantList")
|
||||||
|
def getFileNameFilters(self, io_type):
|
||||||
|
from UM.i18n import i18nCatalog
|
||||||
|
catalog = i18nCatalog("uranium")
|
||||||
|
#TODO: This function should be in UM.Resources!
|
||||||
|
filters = []
|
||||||
|
all_types = []
|
||||||
|
for plugin_id, meta_data in self._getIOPlugins(io_type):
|
||||||
|
for io_plugin in meta_data[io_type]:
|
||||||
|
filters.append(io_plugin["description"] + " (*." + io_plugin["extension"] + ")")
|
||||||
|
all_types.append("*.{0}".format(io_plugin["extension"]))
|
||||||
|
|
||||||
|
if "_reader" in io_type:
|
||||||
|
# if we're listing readers, add the option to show all supported files as the default option
|
||||||
|
filters.insert(0, catalog.i18nc("@item:inlistbox", "All Supported Types ({0})", " ".join(all_types)))
|
||||||
|
filters.append(catalog.i18nc("@item:inlistbox", "All Files (*)")) # Also allow arbitrary files, if the user so prefers.
|
||||||
|
return filters
|
||||||
|
|
||||||
|
## Gets a list of profile reader or writer plugins
|
||||||
|
# \return List of tuples of (plugin_id, meta_data).
|
||||||
|
def _getIOPlugins(self, io_type):
|
||||||
|
from UM.PluginRegistry import PluginRegistry
|
||||||
|
pr = PluginRegistry.getInstance()
|
||||||
|
active_plugin_ids = pr.getActivePlugins()
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for plugin_id in active_plugin_ids:
|
||||||
|
meta_data = pr.getMetaData(plugin_id)
|
||||||
|
if io_type in meta_data:
|
||||||
|
result.append( (plugin_id, meta_data) )
|
||||||
|
return result
|
||||||
|
@ -171,18 +171,6 @@ class ContainerManager(QObject):
|
|||||||
material_group = self._material_manager.getMaterialGroup(root_material_id)
|
material_group = self._material_manager.getMaterialGroup(root_material_id)
|
||||||
material_group.root_material_node.getContainer().setName(new_name)
|
material_group.root_material_node.getContainer().setName(new_name)
|
||||||
|
|
||||||
## Find instance containers matching certain criteria.
|
|
||||||
#
|
|
||||||
# This effectively forwards to
|
|
||||||
# ContainerRegistry::findInstanceContainersMetadata.
|
|
||||||
#
|
|
||||||
# \param criteria A dict of key - value pairs to search for.
|
|
||||||
#
|
|
||||||
# \return A list of container IDs that match the given criteria.
|
|
||||||
@pyqtSlot("QVariantMap", result = "QVariantList")
|
|
||||||
def findInstanceContainers(self, criteria):
|
|
||||||
return [entry["id"] for entry in self._container_registry.findInstanceContainersMetadata(**criteria)]
|
|
||||||
|
|
||||||
@pyqtSlot(str, result = str)
|
@pyqtSlot(str, result = str)
|
||||||
def makeUniqueName(self, original_name):
|
def makeUniqueName(self, original_name):
|
||||||
return self._container_registry.uniqueName(original_name)
|
return self._container_registry.uniqueName(original_name)
|
||||||
@ -716,11 +704,13 @@ class ContainerManager(QObject):
|
|||||||
return
|
return
|
||||||
return self._container_registry.importProfile(path)
|
return self._container_registry.importProfile(path)
|
||||||
|
|
||||||
@pyqtSlot("QVariantList", QUrl, str)
|
@pyqtSlot(QObject, QUrl, str)
|
||||||
def exportProfile(self, instance_id: str, file_url: QUrl, file_type: str) -> None:
|
def exportQualityChangesGroup(self, quality_changes_group, file_url: QUrl, file_type: str):
|
||||||
if not file_url.isValid():
|
if not file_url.isValid():
|
||||||
return
|
return
|
||||||
path = file_url.toLocalFile()
|
path = file_url.toLocalFile()
|
||||||
if not path:
|
if not path:
|
||||||
return
|
return
|
||||||
self._container_registry.exportProfile(instance_id, path, file_type)
|
|
||||||
|
container_list = [n.getContainer() for n in quality_changes_group.getAllNodes()]
|
||||||
|
self._container_registry.exportQualityProfile(container_list, path, file_type)
|
||||||
|
@ -103,7 +103,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
# \param instance_ids \type{list} the IDs of the profiles to export.
|
# \param instance_ids \type{list} the IDs of the profiles to export.
|
||||||
# \param file_name \type{str} the full path and filename to export to.
|
# \param file_name \type{str} the full path and filename to export to.
|
||||||
# \param file_type \type{str} the file type with the format "<description> (*.<extension>)"
|
# \param file_type \type{str} the file type with the format "<description> (*.<extension>)"
|
||||||
def exportProfile(self, instance_ids, file_name, file_type):
|
def exportQualityProfile(self, container_list, file_name, file_type):
|
||||||
# Parse the fileType to deduce what plugin can save the file format.
|
# Parse the fileType to deduce what plugin can save the file format.
|
||||||
# fileType has the format "<description> (*.<extension>)"
|
# fileType has the format "<description> (*.<extension>)"
|
||||||
split = file_type.rfind(" (*.") # Find where the description ends and the extension starts.
|
split = file_type.rfind(" (*.") # Find where the description ends and the extension starts.
|
||||||
@ -122,31 +122,10 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
catalog.i18nc("@label Don't translate the XML tag <filename>!", "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?").format(file_name))
|
catalog.i18nc("@label Don't translate the XML tag <filename>!", "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?").format(file_name))
|
||||||
if result == QMessageBox.No:
|
if result == QMessageBox.No:
|
||||||
return
|
return
|
||||||
found_containers = []
|
|
||||||
extruder_positions = []
|
|
||||||
for instance_id in instance_ids:
|
|
||||||
containers = ContainerRegistry.getInstance().findInstanceContainers(id = instance_id)
|
|
||||||
if containers:
|
|
||||||
found_containers.append(containers[0])
|
|
||||||
|
|
||||||
# Determine the position of the extruder of this container
|
|
||||||
extruder_id = containers[0].getMetaDataEntry("extruder", "")
|
|
||||||
if extruder_id == "":
|
|
||||||
# Global stack
|
|
||||||
extruder_positions.append(-1)
|
|
||||||
else:
|
|
||||||
extruder_containers = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = extruder_id)
|
|
||||||
if extruder_containers:
|
|
||||||
extruder_positions.append(int(extruder_containers[0].get("position", 0)))
|
|
||||||
else:
|
|
||||||
extruder_positions.append(0)
|
|
||||||
# Ensure the profiles are always exported in order (global, extruder 0, extruder 1, ...)
|
|
||||||
found_containers = [containers for (positions, containers) in sorted(zip(extruder_positions, found_containers))]
|
|
||||||
|
|
||||||
profile_writer = self._findProfileWriter(extension, description)
|
profile_writer = self._findProfileWriter(extension, description)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
success = profile_writer.write(file_name, found_containers)
|
success = profile_writer.write(file_name, container_list)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
Logger.log("e", "Failed to export profile to %s: %s", file_name, str(e))
|
Logger.log("e", "Failed to export profile to %s: %s", file_name, str(e))
|
||||||
m = Message(catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to export profile to <filename>{0}</filename>: <message>{1}</message>", file_name, str(e)),
|
m = Message(catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to export profile to <filename>{0}</filename>: <message>{1}</message>", file_name, str(e)),
|
||||||
|
@ -138,7 +138,7 @@ Item
|
|||||||
text: catalog.i18nc("@action:button", "Import")
|
text: catalog.i18nc("@action:button", "Import")
|
||||||
iconName: "document-import"
|
iconName: "document-import"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
// TODO
|
importDialog.open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ Item
|
|||||||
iconName: "document-export"
|
iconName: "document-export"
|
||||||
enabled: base.hasCurrentItem && !base.currentItem.is_read_only
|
enabled: base.hasCurrentItem && !base.currentItem.is_read_only
|
||||||
onClicked: {
|
onClicked: {
|
||||||
// TODO
|
exportDialog.open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,6 +212,57 @@ Item
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dialog for importing a quality profile
|
||||||
|
FileDialog
|
||||||
|
{
|
||||||
|
id: importDialog
|
||||||
|
title: catalog.i18nc("@title:window", "Import Profile")
|
||||||
|
selectExisting: true
|
||||||
|
nameFilters: qualitiesModel.getFileNameFilters("profile_reader") // TODO: make this easier
|
||||||
|
folder: CuraApplication.getDefaultPath("dialog_profile_path")
|
||||||
|
onAccepted:
|
||||||
|
{
|
||||||
|
var result = Cura.ContainerManager.importProfile(fileUrl);
|
||||||
|
messageDialog.text = result.message;
|
||||||
|
if (result.status == "ok") {
|
||||||
|
messageDialog.icon = StandardIcon.Information;
|
||||||
|
}
|
||||||
|
else if (result.status == "duplicate") {
|
||||||
|
messageDialog.icon = StandardIcon.Warning;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
messageDialog.icon = StandardIcon.Critical;
|
||||||
|
}
|
||||||
|
messageDialog.open();
|
||||||
|
CuraApplication.setDefaultPath("dialog_profile_path", folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dialog for exporting a quality profile
|
||||||
|
FileDialog
|
||||||
|
{
|
||||||
|
id: exportDialog
|
||||||
|
title: catalog.i18nc("@title:window", "Export Profile")
|
||||||
|
selectExisting: false
|
||||||
|
nameFilters: qualitiesModel.getFileNameFilters("profile_writer") // TODO: make this easier
|
||||||
|
folder: CuraApplication.getDefaultPath("dialog_profile_path")
|
||||||
|
onAccepted:
|
||||||
|
{
|
||||||
|
// TODO: make this easier
|
||||||
|
var result = Cura.ContainerManager.exportQualityChangesGroup(base.currentItem.quality_changes_group,
|
||||||
|
fileUrl, selectedNameFilter);
|
||||||
|
|
||||||
|
if (result && result.status == "error") {
|
||||||
|
messageDialog.icon = StandardIcon.Critical;
|
||||||
|
messageDialog.text = result.message;
|
||||||
|
messageDialog.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
// else pop-up Message thing from python code
|
||||||
|
CuraApplication.setDefaultPath("dialog_profile_path", folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: contentsItem
|
id: contentsItem
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user