def importData(self) -> None: # thanks to Aldo Hoeben / fieldOfView for this part of the code file_name = "" if VERSION_QT5: file_name = QFileDialog.getOpenFileName( parent = None, caption = catalog.i18nc("@title:window", "Open File"), directory = self._preferences.getValue("import_export_tools/dialog_path"), filter = "CSV files (*.csv)", options = self._dialog_options )[0] else: dialog = QFileDialog() dialog.setWindowTitle(catalog.i18nc("@title:window", "Open File")) dialog.setDirectory(self._preferences.getValue("import_export_tools/dialog_path")) dialog.setNameFilters(["CSV files (*.csv)"]) dialog.setAcceptMode(QFileDialog.AcceptMode.AcceptOpen) dialog.setFileMode(QFileDialog.FileMode.ExistingFile) if dialog.exec(): file_name = dialog.selectedFiles()[0] if not file_name: Logger.log("d", "No file to import from selected") return self._preferences.setValue("import_export_tools/dialog_path", os.path.dirname(file_name)) # ----- machine_manager = CuraApplication.getInstance().getMachineManager() stack = CuraApplication.getInstance().getGlobalContainerStack() global_stack = machine_manager.activeMachine #Get extruder count extruder_count=stack.getProperty("machine_extruder_count", "value") #extruders = list(global_stack.extruders.values()) extruder_stack = CuraApplication.getInstance().getExtruderManager().getActiveExtruderStacks() imported_count = 0 CPro = "" try: with open(file_name, 'r', newline='') as csv_file: C_dialect = csv.Sniffer().sniff(csv_file.read(1024)) # Reset to begining file position csv_file.seek(0, 0) Logger.log("d", "Csv Import %s : Delimiter = %s Quotechar = %s", file_name, C_dialect.delimiter, C_dialect.quotechar) # csv.QUOTE_MINIMAL or csv.QUOTE_NONNUMERIC ? # csv_reader = csv.reader(csv_file, delimiter=';', quotechar='"', quoting=csv.QUOTE_MINIMAL) csv_reader = csv.reader(csv_file, dialect=C_dialect) line_number = -1 for row in csv_reader: line_number += 1 if line_number == 0: if len(row) < 4: continue else: # Logger.log("d", "Import Data = %s | %s | %s | %s | %s",row[0], row[1], row[2], row[3], row[4]) try: #(section, extrud, kkey, ktype, kvalue) = row[0:4] section=row[0] extrud=int(row[1]) extrud -= 1 kkey=row[2] ktype=row[3] kvalue=row[4] #Logger.log("d", "Current Data = %s | %d | %s | %s | %s", section,extrud, kkey, ktype, kvalue) if extrud<extruder_count: try: container=extruder_stack[extrud] try: prop_value = container.getProperty(kkey, "value") if prop_value != None : settable_per_extruder= container.getProperty(kkey, "settable_per_extruder") # Logger.log("d", "%s settable_per_extruder : %s", kkey, str(settable_per_extruder)) if ktype == "str" or ktype == "enum": if prop_value != kvalue : if extrud == 0 : stack.setProperty(kkey,"value",kvalue) if settable_per_extruder == True : container.setProperty(kkey,"value",kvalue) Logger.log("d", "prop_value changed: %s = %s / %s", kkey ,kvalue, prop_value) else: Logger.log("d", "%s not settable_per_extruder", kkey) imported_count += 1 elif ktype == "bool" : if kvalue == "True" or kvalue == "true" : C_bool=True else: C_bool=False if prop_value != C_bool : if extrud == 0 : stack.setProperty(kkey,"value",C_bool) if settable_per_extruder == True : container.setProperty(kkey,"value",C_bool) Logger.log("d", "prop_value changed: %s = %s / %s", kkey ,C_bool, prop_value) else: Logger.log("d", "%s not settable_per_extruder", kkey) imported_count += 1 elif ktype == "int" : if prop_value != int(kvalue) : if extrud == 0 : stack.setProperty(kkey,"value",int(kvalue)) if settable_per_extruder == True : container.setProperty(kkey,"value",int(kvalue)) Logger.log("d", "prop_value changed: %s = %s / %s", kkey ,kvalue, prop_value) else: Logger.log("d", "%s not settable_per_extruder", kkey) imported_count += 1 elif ktype == "float" : TransVal=round(float(kvalue),4) if round(prop_value,4) != TransVal : if extrud == 0 : stack.setProperty(kkey,"value",TransVal) if settable_per_extruder == True : container.setProperty(kkey,"value",TransVal) Logger.log("d", "prop_value changed: %s = %s / %s", kkey ,TransVal, prop_value) else: Logger.log("d", "%s not settable_per_extruder", kkey) imported_count += 1 else : Logger.log("d", "Value type Else = %d | %s | %s | %s",extrud, kkey, ktype, kvalue) else: # Logger.log("d", "Value None = %d | %s | %s | %s",extrud, kkey, ktype, kvalue) if kkey=="Profile" : CPro=kvalue except: Logger.log("e", "Error kkey: %s" % kkey) continue except: Logger.log("e", "Error Extruder: %s" % row) continue except: Logger.log("e", "Row does not have enough data: %s" % row) continue except: Logger.logException("e", "Could not import settings from the selected file") return Message().hide() Message("Imported profil %d changed keys from %s" % (imported_count, CPro) , title = "Import Export CSV Profiles Tools").show()
def requestWrite(self, nodes, file_name = None, limit_mimetypes = None, file_handler = None, **kwargs): """Request the specified nodes to be written to a file. :param nodes: A collection of scene nodes that should be written to the file. :param file_name: A suggestion for the file name to write to. Can be freely ignored if providing a file name makes no sense. :param limit_mimetypes: Should we limit the available MIME types to the MIME types available to the currently active machine? :param kwargs: Keyword arguments. """ if self._writing: raise OutputDeviceError.DeviceBusyError() # Set up and display file dialog dialog = QFileDialog() dialog.setWindowTitle(catalog.i18nc("@title:window", "Save to Disk")) dialog.setFileMode(QFileDialog.FileMode.AnyFile) dialog.setAcceptMode(QFileDialog.AcceptMode.AcceptSave) # Ensure platform never ask for overwrite confirmation since we do this ourselves dialog.setOption(QFileDialog.Option.DontConfirmOverwrite) filters = [] mime_types = [] selected_filter = None if "preferred_mimetypes" in kwargs and kwargs["preferred_mimetypes"] is not None: preferred_mimetypes = kwargs["preferred_mimetypes"] else: preferred_mimetypes = Application.getInstance().getPreferences().getValue("local_file/last_used_type") preferred_mimetype_list = preferred_mimetypes.split(";") if not file_handler: file_handler = Application.getInstance().getMeshFileHandler() file_types = file_handler.getSupportedFileTypesWrite() file_types.sort(key = lambda k: k["description"]) if limit_mimetypes: file_types = list(filter(lambda i: i["mime_type"] in limit_mimetypes, file_types)) file_types = [ft for ft in file_types if not ft["hide_in_file_dialog"]] if len(file_types) == 0: Logger.log("e", "There are no file types available to write with!") raise OutputDeviceError.WriteRequestFailedError(catalog.i18nc("@info:warning", "There are no file types available to write with!")) # Find the first available preferred mime type preferred_mimetype = None for mime_type in preferred_mimetype_list: if any(ft["mime_type"] == mime_type for ft in file_types): preferred_mimetype = mime_type break extension_added = False for item in file_types: type_filter = "{0} (*.{1})".format(item["description"], item["extension"]) filters.append(type_filter) mime_types.append(item["mime_type"]) if preferred_mimetype == item["mime_type"]: selected_filter = type_filter if file_name and not extension_added: extension_added = True file_name += "." + item["extension"] # CURA-6411: This code needs to be before dialog.selectFile and the filters, because otherwise in macOS (for some reason) the setDirectory call doesn't work. stored_directory = Application.getInstance().getPreferences().getValue("local_file/dialog_save_path") if stored_directory and stored_directory != "" and os.path.exists(stored_directory): dialog.setDirectory(stored_directory) # Add the file name before adding the extension to the dialog if file_name is not None: dialog.selectFile(file_name) dialog.setNameFilters(filters) if selected_filter is not None: dialog.selectNameFilter(selected_filter) if not dialog.exec(): raise OutputDeviceError.UserCanceledError() save_path = dialog.directory().absolutePath() Application.getInstance().getPreferences().setValue("local_file/dialog_save_path", save_path) selected_type = file_types[filters.index(dialog.selectedNameFilter())] Application.getInstance().getPreferences().setValue("local_file/last_used_type", selected_type["mime_type"]) # Get file name from file dialog file_name = dialog.selectedFiles()[0] Logger.log("d", "Writing to [%s]..." % file_name) if os.path.exists(file_name): result = QMessageBox.question(None, catalog.i18nc("@title:window", "File Already Exists"), 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.StandardButton.No: raise OutputDeviceError.UserCanceledError() # Actually writing file if file_handler: file_writer = file_handler.getWriter(selected_type["id"]) else: file_writer = Application.getInstance().getMeshFileHandler().getWriter(selected_type["id"]) if isinstance(file_writer, WorkspaceWriter): self.setLastOutputName(file_name) self.writeStarted.emit(self) try: mode = selected_type["mode"] if mode == MeshWriter.OutputMode.TextMode: Logger.log("d", "Writing to Local File %s in text mode", file_name) stream = open(file_name, "wt", encoding = "utf-8") elif mode == MeshWriter.OutputMode.BinaryMode: Logger.log("d", "Writing to Local File %s in binary mode", file_name) stream = open(file_name, "wb") else: Logger.log("e", "Unrecognised OutputMode.") return None job = WriteFileJob(file_writer, stream, nodes, mode) job.setFileName(file_name) job.setAddToRecentFiles(True) # The file will be added into the "recent files" list upon success job.progress.connect(self._onJobProgress) job.finished.connect(self._onWriteJobFinished) message = Message(catalog.i18nc("@info:progress Don't translate the XML tags <filename>!", "Saving to <filename>{0}</filename>").format(file_name), 0, False, -1 , catalog.i18nc("@info:title", "Saving")) message.show() job.setMessage(message) self._writing = True job.start() except PermissionError as e: Logger.log("e", "Permission denied when trying to write to %s: %s", file_name, str(e)) raise OutputDeviceError.PermissionDeniedError(catalog.i18nc("@info:status Don't translate the XML tags <filename>!", "Permission denied when trying to save <filename>{0}</filename>").format(file_name)) from e except OSError as e: Logger.log("e", "Operating system would not let us write to %s: %s", file_name, str(e)) raise OutputDeviceError.WriteRequestFailedError(catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Could not save to <filename>{0}</filename>: <message>{1}</message>").format(file_name, str(e))) from e
def exportData(self) -> None: # thanks to Aldo Hoeben / fieldOfView for this part of the code file_name = "" if VERSION_QT5: file_name = QFileDialog.getSaveFileName( parent = None, caption = catalog.i18nc("@title:window", "Save as"), directory = self._preferences.getValue("import_export_tools/dialog_path"), filter = "CSV files (*.csv)", options = self._dialog_options )[0] else: dialog = QFileDialog() dialog.setWindowTitle(catalog.i18nc("@title:window", "Save as")) dialog.setDirectory(self._preferences.getValue("import_export_tools/dialog_path")) dialog.setNameFilters(["CSV files (*.csv)"]) dialog.setAcceptMode(QFileDialog.AcceptMode.AcceptSave) dialog.setFileMode(QFileDialog.FileMode.AnyFile) if dialog.exec(): file_name = dialog.selectedFiles()[0] if not file_name: Logger.log("d", "No file to export selected") return self._preferences.setValue("import_export_tools/dialog_path", os.path.dirname(file_name)) # ----- machine_manager = CuraApplication.getInstance().getMachineManager() stack = CuraApplication.getInstance().getGlobalContainerStack() global_stack = machine_manager.activeMachine # Get extruder count extruder_count=stack.getProperty("machine_extruder_count", "value") # for name in sorted(csv.list_dialects()): # Logger.log("d", "Dialect = %s" % name) # dialect = csv.get_dialect(name) # Logger.log("d", "Delimiter = %s" % dialect.delimiter) exported_count = 0 try: with open(file_name, 'w', newline='') as csv_file: # csv.QUOTE_MINIMAL or csv.QUOTE_NONNUMERIC ? csv_writer = csv.writer(csv_file, delimiter=';', quotechar='"', quoting=csv.QUOTE_MINIMAL) # E_dialect = csv.get_dialect("excel") # csv_writer = csv.writer(csv_file, dialect=E_dialect) csv_writer.writerow([ "Section", "Extruder", "Key", "Type", "Value" ]) # Date self._WriteRow(csv_writer,"general",0,"Date","str",datetime.now().strftime("%d/%m/%Y %H:%M:%S")) # Platform self._WriteRow(csv_writer,"general",0,"Os","str",str(platform.system()) + " " + str(platform.version())) # Version self._WriteRow(csv_writer,"general",0,"Cura_Version","str",CuraVersion) # Profile P_Name = global_stack.qualityChanges.getMetaData().get("name", "") self._WriteRow(csv_writer,"general",0,"Profile","str",P_Name) # Quality Q_Name = global_stack.quality.getMetaData().get("name", "") self._WriteRow(csv_writer,"general",0,"Quality","str",Q_Name) # Extruder_Count self._WriteRow(csv_writer,"general",0,"Extruder_Count","int",str(extruder_count)) # Material # extruders = list(global_stack.extruders.values()) extruder_stack = CuraApplication.getInstance().getExtruderManager().getActiveExtruderStacks() # Define every section to get the same order as in the Cura Interface # Modification from global_stack to extruders[0] i=0 for Extrud in extruder_stack: i += 1 self._doTree(Extrud,"resolution",csv_writer,0,i) # Shell before 4.9 and now Walls self._doTree(Extrud,"shell",csv_writer,0,i) # New section Arachne and 4.9 ? if self.Major > 4 or ( self.Major == 4 and self.Minor >= 9 ) : self._doTree(Extrud,"top_bottom",csv_writer,0,i) self._doTree(Extrud,"infill",csv_writer,0,i) self._doTree(Extrud,"material",csv_writer,0,i) self._doTree(Extrud,"speed",csv_writer,0,i) self._doTree(Extrud,"travel",csv_writer,0,i) self._doTree(Extrud,"cooling",csv_writer,0,i) # If single extruder doesn't export the data if extruder_count>1 : self._doTree(Extrud,"dual",csv_writer,0,i) self._doTree(Extrud,"support",csv_writer,0,i) self._doTree(Extrud,"platform_adhesion",csv_writer,0,i) self._doTree(Extrud,"meshfix",csv_writer,0,i) self._doTree(Extrud,"blackmagic",csv_writer,0,i) self._doTree(Extrud,"experimental",csv_writer,0,i) # machine_settings self._Section ="machine_settings" # self._doTree(Extrud,"machine_nozzle_size",csv_writer,0,i) except: Logger.logException("e", "Could not export profile to the selected file") return Message().hide() Message("Exported data for profil %s" % P_Name, title = "Import Export CSV Profiles Tools").show()