mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-14 19:05:54 +08:00
Merge branch 'master' of https://github.com/Ultimaker/Cura
This commit is contained in:
commit
43438dd84f
@ -18,8 +18,8 @@ class ProfileWriter(PluginObject):
|
|||||||
# The profile writer may write its own file format to the specified file.
|
# The profile writer may write its own file format to the specified file.
|
||||||
#
|
#
|
||||||
# \param path \type{string} The file to output to.
|
# \param path \type{string} The file to output to.
|
||||||
# \param profile \type{Profile} The profile to write to the file.
|
# \param profiles \type{Profile} or \type{List} The profile(s) to write to the file.
|
||||||
# \return \code True \endcode if the writing was successful, or \code
|
# \return \code True \endcode if the writing was successful, or \code
|
||||||
# False \endcode if it wasn't.
|
# False \endcode if it wasn't.
|
||||||
def write(self, path, node):
|
def write(self, path, profiles):
|
||||||
raise NotImplementedError("Profile writer plugin was not correctly implemented. No write was specified.")
|
raise NotImplementedError("Profile writer plugin was not correctly implemented. No write was specified.")
|
||||||
|
@ -58,12 +58,10 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
|
|
||||||
## Exports an profile to a file
|
## Exports an profile to a file
|
||||||
#
|
#
|
||||||
# \param instance_id \type{str} the ID of the profile 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_id, file_name, file_type):
|
def exportProfile(self, instance_ids, file_name, file_type):
|
||||||
Logger.log('d', 'exportProfile instance_id: '+str(instance_id))
|
|
||||||
|
|
||||||
# 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.
|
||||||
@ -82,16 +80,16 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
catalog.i18nc("@label", "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?").format(file_name))
|
catalog.i18nc("@label", "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 = []
|
||||||
containers = ContainerRegistry.getInstance().findInstanceContainers(id=instance_id)
|
for instance_id in instance_ids:
|
||||||
if not containers:
|
containers = ContainerRegistry.getInstance().findInstanceContainers(id=instance_id)
|
||||||
return
|
if containers:
|
||||||
container = containers[0]
|
found_containers.append(containers[0])
|
||||||
|
|
||||||
profile_writer = self._findProfileWriter(extension, description)
|
profile_writer = self._findProfileWriter(extension, description)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
success = profile_writer.write(file_name, container)
|
success = profile_writer.write(file_name, found_containers)
|
||||||
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", "Failed to export profile to <filename>{0}</filename>: <message>{1}</message>", file_name, str(e)), lifetime = 0)
|
m = Message(catalog.i18nc("@info:status", "Failed to export profile to <filename>{0}</filename>: <message>{1}</message>", file_name, str(e)), lifetime = 0)
|
||||||
@ -146,7 +144,10 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) }
|
return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) }
|
||||||
else:
|
else:
|
||||||
for profile in profile_or_list:
|
for profile in profile_or_list:
|
||||||
self._configureProfile(profile, name_seed)
|
if profile.getId() != "":
|
||||||
|
ContainerRegistry.getInstance().addContainer(profile)
|
||||||
|
else:
|
||||||
|
self._configureProfile(profile, name_seed)
|
||||||
|
|
||||||
if len(profile_or_list) == 1:
|
if len(profile_or_list) == 1:
|
||||||
return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())}
|
return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())}
|
||||||
@ -160,7 +161,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
def _configureProfile(self, profile, name_seed):
|
def _configureProfile(self, profile, name_seed):
|
||||||
profile.setReadOnly(False)
|
profile.setReadOnly(False)
|
||||||
|
|
||||||
new_name = self.createUniqueName("quality", "", name_seed, catalog.i18nc("@label", "Custom profile"))
|
new_name = self.createUniqueName("quality_changes", "", name_seed, catalog.i18nc("@label", "Custom profile"))
|
||||||
profile.setName(new_name)
|
profile.setName(new_name)
|
||||||
profile._id = new_name
|
profile._id = new_name
|
||||||
|
|
||||||
|
@ -55,6 +55,13 @@ class ExtruderManager(QObject):
|
|||||||
map[position] = self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][position].getId()
|
map[position] = self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][position].getId()
|
||||||
return map
|
return map
|
||||||
|
|
||||||
|
@pyqtSlot(str, result = str)
|
||||||
|
def getQualityChangesIdByExtruderStackId(self, id):
|
||||||
|
for position in self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()]:
|
||||||
|
extruder = self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][position]
|
||||||
|
if extruder.getId() == id:
|
||||||
|
return extruder.findContainer(type = "quality_changes").getId()
|
||||||
|
|
||||||
## The instance of the singleton pattern.
|
## The instance of the singleton pattern.
|
||||||
#
|
#
|
||||||
# It's None if the extruder manager hasn't been created yet.
|
# It's None if the extruder manager hasn't been created yet.
|
||||||
|
@ -4,9 +4,11 @@
|
|||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Settings.InstanceContainer import InstanceContainer #The new profile to make.
|
from UM.Settings.InstanceContainer import InstanceContainer # The new profile to make.
|
||||||
from cura.ProfileReader import ProfileReader
|
from cura.ProfileReader import ProfileReader
|
||||||
|
|
||||||
|
import zipfile
|
||||||
|
|
||||||
## A plugin that reads profile data from Cura profile files.
|
## A plugin that reads profile data from Cura profile files.
|
||||||
#
|
#
|
||||||
# It reads a profile from a .curaprofile file, and returns it as a profile
|
# It reads a profile from a .curaprofile file, and returns it as a profile
|
||||||
@ -24,19 +26,19 @@ class CuraProfileReader(ProfileReader):
|
|||||||
# not be read or didn't contain a valid profile, \code None \endcode is
|
# not be read or didn't contain a valid profile, \code None \endcode is
|
||||||
# returned.
|
# returned.
|
||||||
def read(self, file_name):
|
def read(self, file_name):
|
||||||
# Create an empty profile.
|
archive = zipfile.ZipFile(file_name, "r")
|
||||||
profile = InstanceContainer(os.path.basename(os.path.splitext(file_name)[0]))
|
results = []
|
||||||
profile.addMetaDataEntry("type", "quality")
|
for profile_id in archive.namelist():
|
||||||
try:
|
# Create an empty profile.
|
||||||
with open(file_name) as f: # Open file for reading.
|
profile = InstanceContainer(profile_id)
|
||||||
|
profile.addMetaDataEntry("type", "quality_changes")
|
||||||
|
serialized = ""
|
||||||
|
with archive.open(profile_id) as f:
|
||||||
serialized = f.read()
|
serialized = f.read()
|
||||||
except IOError as e:
|
try:
|
||||||
Logger.log("e", "Unable to open file %s for reading: %s", file_name, str(e))
|
profile.deserialize(serialized.decode("utf-8") )
|
||||||
return None
|
except Exception as e: # Parsing error. This is not a (valid) Cura profile then.
|
||||||
|
Logger.log("e", "Error while trying to parse profile: %s", str(e))
|
||||||
try:
|
continue
|
||||||
profile.deserialize(serialized)
|
results.append(profile)
|
||||||
except Exception as e: # Parsing error. This is not a (valid) Cura profile then.
|
return results
|
||||||
Logger.log("e", "Error while trying to parse profile: %s", str(e))
|
|
||||||
return None
|
|
||||||
return profile
|
|
@ -5,22 +5,31 @@
|
|||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.SaveFile import SaveFile
|
from UM.SaveFile import SaveFile
|
||||||
from cura.ProfileWriter import ProfileWriter
|
from cura.ProfileWriter import ProfileWriter
|
||||||
|
import zipfile
|
||||||
|
|
||||||
## Writes profiles to Cura's own profile format with config files.
|
## Writes profiles to Cura's own profile format with config files.
|
||||||
class CuraProfileWriter(ProfileWriter):
|
class CuraProfileWriter(ProfileWriter):
|
||||||
## Writes a profile to the specified file path.
|
## Writes a profile to the specified file path.
|
||||||
#
|
#
|
||||||
# \param path \type{string} The file to output to.
|
# \param path \type{string} The file to output to.
|
||||||
# \param profile \type{Profile} The profile to write to that file.
|
# \param profiles \type{Profile} \type{List} The profile(s) to write to that file.
|
||||||
# \return \code True \endcode if the writing was successful, or \code
|
# \return \code True \endcode if the writing was successful, or \code
|
||||||
# False \endcode if it wasn't.
|
# False \endcode if it wasn't.
|
||||||
def write(self, path, profile):
|
def write(self, path, profiles):
|
||||||
serialized = profile.serialize()
|
if type(profiles) != list:
|
||||||
|
profiles = [profiles]
|
||||||
|
|
||||||
|
stream = open(path, "wb") # Open file for writing in binary.
|
||||||
|
archive = zipfile.ZipFile(stream, "w", compression=zipfile.ZIP_DEFLATED)
|
||||||
try:
|
try:
|
||||||
with SaveFile(path, "wt", -1, "utf-8") as f: # Open the specified file.
|
# Open the specified file.
|
||||||
f.write(serialized)
|
for profile in profiles:
|
||||||
|
serialized = profile.serialize()
|
||||||
|
profile_file = zipfile.ZipInfo(profile.getId())
|
||||||
|
archive.writestr(profile_file, serialized)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
Logger.log("e", "Failed to write profile to %s: %s", path, str(e))
|
Logger.log("e", "Failed to write profile to %s: %s", path, str(e))
|
||||||
return False
|
return False
|
||||||
|
finally:
|
||||||
|
archive.close()
|
||||||
return True
|
return True
|
||||||
|
@ -99,7 +99,7 @@ class RemovableDriveOutputDevice(OutputDevice):
|
|||||||
self._writing = False
|
self._writing = False
|
||||||
self.writeFinished.emit(self)
|
self.writeFinished.emit(self)
|
||||||
if job.getResult():
|
if job.getResult():
|
||||||
message = Message(catalog.i18nc("@info:status", "Saved to Removable Drive {0} as {1}").format(self.getName(), os.path.basename(job.getFileName())), lifetime = 0)
|
message = Message(catalog.i18nc("@info:status", "Saved to Removable Drive {0} as {1}").format(self.getName(), os.path.basename(job.getFileName())))
|
||||||
message.addAction("eject", catalog.i18nc("@action:button", "Eject"), "eject", catalog.i18nc("@action", "Eject removable device {0}").format(self.getName()))
|
message.addAction("eject", catalog.i18nc("@action:button", "Eject"), "eject", catalog.i18nc("@action", "Eject removable device {0}").format(self.getName()))
|
||||||
message.actionTriggered.connect(self._onActionTriggered)
|
message.actionTriggered.connect(self._onActionTriggered)
|
||||||
message.show()
|
message.show()
|
||||||
@ -112,5 +112,5 @@ class RemovableDriveOutputDevice(OutputDevice):
|
|||||||
|
|
||||||
def _onActionTriggered(self, message, action):
|
def _onActionTriggered(self, message, action):
|
||||||
if action == "eject":
|
if action == "eject":
|
||||||
Application.getInstance().getOutputDeviceManager().getOutputDevicePlugin("RemovableDriveOutputDevice").ejectDevice(self)
|
if Application.getInstance().getOutputDeviceManager().getOutputDevicePlugin("RemovableDriveOutputDevice").ejectDevice(self):
|
||||||
|
message.hide()
|
@ -51,6 +51,7 @@ class RemovableDrivePlugin(OutputDevicePlugin):
|
|||||||
else:
|
else:
|
||||||
message = Message(catalog.i18nc("@info:status", "Failed to eject {0}. Maybe it is still in use?").format(device.getName()))
|
message = Message(catalog.i18nc("@info:status", "Failed to eject {0}. Maybe it is still in use?").format(device.getName()))
|
||||||
message.show()
|
message.show()
|
||||||
|
return result
|
||||||
|
|
||||||
def performEjectDevice(self, device):
|
def performEjectDevice(self, device):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -13,6 +13,8 @@ UM.ManagementPage
|
|||||||
id: base;
|
id: base;
|
||||||
|
|
||||||
title: catalog.i18nc("@title:tab", "Profiles");
|
title: catalog.i18nc("@title:tab", "Profiles");
|
||||||
|
property var extrudersModel: Cura.ExtrudersModel{}
|
||||||
|
//Cura.ExtrudersModel { id: extrudersModel}
|
||||||
|
|
||||||
model: UM.InstanceContainersModel
|
model: UM.InstanceContainersModel
|
||||||
{
|
{
|
||||||
@ -106,15 +108,13 @@ UM.ManagementPage
|
|||||||
text: catalog.i18nc("@action:button", "Import");
|
text: catalog.i18nc("@action:button", "Import");
|
||||||
iconName: "document-import";
|
iconName: "document-import";
|
||||||
onClicked: importDialog.open();
|
onClicked: importDialog.open();
|
||||||
enabled: false
|
|
||||||
},
|
},
|
||||||
Button
|
Button
|
||||||
{
|
{
|
||||||
text: catalog.i18nc("@action:button", "Export")
|
text: catalog.i18nc("@action:button", "Export")
|
||||||
iconName: "document-export"
|
iconName: "document-export"
|
||||||
onClicked: exportDialog.open()
|
onClicked: exportDialog.open()
|
||||||
// enabled: currentItem != null
|
enabled: currentItem != null
|
||||||
enabled: false
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -206,7 +206,7 @@ UM.ManagementPage
|
|||||||
|
|
||||||
Repeater
|
Repeater
|
||||||
{
|
{
|
||||||
model: Cura.ExtrudersModel { }
|
model: base.extrudersModel
|
||||||
|
|
||||||
ProfileTab
|
ProfileTab
|
||||||
{
|
{
|
||||||
@ -299,7 +299,12 @@ UM.ManagementPage
|
|||||||
folder: CuraApplication.getDefaultPath("dialog_profile_path")
|
folder: CuraApplication.getDefaultPath("dialog_profile_path")
|
||||||
onAccepted:
|
onAccepted:
|
||||||
{
|
{
|
||||||
var result = base.model.exportProfile(base.currentItem.id, fileUrl, selectedNameFilter)
|
var profiles_to_export = [base.currentItem.id]
|
||||||
|
for(var extruder_nr in base.extrudersModel.items)
|
||||||
|
{
|
||||||
|
profiles_to_export.push(ExtruderManager.getQualityChangesIdByExtruderStackId(base.extrudersModel.items[extruder_nr].id))
|
||||||
|
}
|
||||||
|
var result = base.model.exportProfile(profiles_to_export, fileUrl, selectedNameFilter)
|
||||||
if(result && result.status == "error")
|
if(result && result.status == "error")
|
||||||
{
|
{
|
||||||
messageDialog.icon = StandardIcon.Critical
|
messageDialog.icon = StandardIcon.Critical
|
||||||
|
Loading…
x
Reference in New Issue
Block a user