This commit is contained in:
fieldOfView 2016-08-26 17:02:35 +02:00
commit 43438dd84f
8 changed files with 69 additions and 44 deletions

View File

@ -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.")

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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