def requestWrite(self, node, fileName=None, *args, **kwargs): if self._stage != OutputStage.ready or self._qidi._isPrinting: Message(catalog.i18nc('@info:status', 'Cannot Print, printer is busy'), title=catalog.i18nc("@info:title", "BUSY")).show() raise OutputDeviceError.DeviceBusyError() # Make sure post-processing plugin are run on the gcode self.writeStarted.emit(self) if fileName: fileName = os.path.splitext(fileName)[0] else: fileName = "%s" % Application.getInstance().getPrintInformation( ).jobName self.targetSendFileName = fileName path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'qml', 'UploadFilename.qml') self._dialog = CuraApplication.getInstance().createQmlComponent( path, {"manager": self}) self._dialog.textChanged.connect(self.onFilenameChanged) self._dialog.accepted.connect(self.onFilenameAccepted) self._dialog.show() self._dialog.findChild(QObject, "autoPrint").setProperty( 'checked', self._autoPrint) self._dialog.findChild(QObject, "nameField").setProperty( 'text', self.targetSendFileName) self._dialog.findChild(QObject, "nameField").select( 0, len(self.targetSendFileName)) self._dialog.findChild(QObject, "nameField").setProperty('focus', True)
def requestWrite(self, nodes: List[SceneNode], file_name: Optional[str] = None, limit_mimetypes: bool = False, file_handler: Optional[FileHandler] = None, **kwargs) -> None: """Request the specified nodes to be written. Function called every time the 'To Digital Factory' option of the 'Save Project' submenu is triggered or when the "Save to Library" action button is pressed (upon slicing). :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. :param limit_mimetypes: Limit the possible mimetypes to use for writing to these types. :param file_handler: The handler responsible for reading and writing mesh files. :param kwargs: Keyword arguments. """ if self._writing: raise OutputDeviceError.DeviceBusyError() self.loadWindow() if self._account.isLoggedIn and self._controller.userAccountHasLibraryAccess( ): self._controller.nodes = nodes df_workspace_information = self._current_workspace_information.getPluginMetadata( "digital_factory") self._controller.initialize( preselected_project_id=df_workspace_information.get( "library_project_id")) self._dialog.show()
def requestWrite(self, node, fileName=None, *args, **kwargs): if self._stage != OutputStage.ready: raise OutputDeviceError.DeviceBusyError() if fileName: fileName = os.path.splitext(fileName)[0] + '.gcode' else: fileName = "%s.gcode" % Application.getInstance( ).getPrintInformation().jobName self._fileName = fileName path = QUrl.fromLocalFile( os.path.join(os.path.dirname(os.path.abspath(__file__)), 'UploadFilename.qml')) self._component = QQmlComponent(Application.getInstance()._engine, path) Logger.log("d", "Errors:", self._component.errors()) self._context = QQmlContext( Application.getInstance()._engine.rootContext()) self._context.setContextProperty("manager", self) self._dialog = self._component.create(self._context) self._dialog.textChanged.connect(self.onFilenameChanged) self._dialog.accepted.connect(self.onFilenameAccepted) self._dialog.open() self._dialog.findChild(QObject, "nameField").setProperty( 'text', self._fileName) self._dialog.findChild(QObject, "nameField").select(0, len(self._fileName) - 6) self._dialog.findChild(QObject, "nameField").setProperty('focus', True)
def sendPrintJob(self): nodes, file_name, filter_by_machine, file_handler, kwargs = self._request_job output_build_plate_number = self._job_list.pop(0) gcode = getattr(Application.getInstance().getController().getScene(), "gcode_list")[output_build_plate_number] self._send_gcode_start = time.time() Logger.log("d", "Sending print job [%s] to host, build plate [%s]..." % (file_name, output_build_plate_number)) if self._stage != OutputStage.ready: Logger.log("d", "Unable to send print job as the state is %s", self._stage) raise OutputDeviceError.DeviceBusyError() self._stage = OutputStage.uploading if self._add_build_plate_number: self._file_name = "%s_%d.gcode.gz" % (file_name, output_build_plate_number) else: self._file_name = "%s.gcode.gz" % (file_name) self._showProgressMessage() require_printer_name = self._selected_printer["unique_name"] new_request = self._buildSendPrintJobHttpRequest(require_printer_name, gcode) if new_request is None or self._stage != OutputStage.uploading: return self._request = new_request self._reply = self._manager.post(self._request, self._multipart) self._reply.uploadProgress.connect(self._onUploadProgress)
def requestWrite(self, node, fileName=None, *args, **kwargs): if self._stage != OutputStage.ready: raise OutputDeviceError.DeviceBusyError() # Make sure post-processing plugin are run on the gcode self.writeStarted.emit(self) # The presliced print should always be send using `GCodeWriter` print_info = CuraApplication.getInstance().getPrintInformation() if self._output_format != "ufp" or not print_info or print_info.preSliced: self._output_format = "gcode" code_writer = cast( MeshWriter, PluginRegistry.getInstance().getPluginObject("GCodeWriter")) self._stream = StringIO() else: code_writer = cast( MeshWriter, PluginRegistry.getInstance().getPluginObject("UFPWriter")) self._stream = BytesIO() if not code_writer.write(self._stream, None): Logger.log("e", "MeshWriter failed: %s" % code_writer.getInformation()) return # Prepare filename for upload if fileName: fileName = os.path.basename(fileName) else: fileName = "%s." % Application.getInstance().getPrintInformation( ).jobName # Translate filename if self._trans_input and self._trans_output: transFileName = fileName.translate( fileName.maketrans( self._trans_input, self._trans_output, self._trans_remove if self._trans_remove else "")) fileName = transFileName self._fileName = fileName + "." + self._output_format # Display upload dialog path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'resources', 'qml', 'MoonrakerUpload.qml') self._dialog = CuraApplication.getInstance().createQmlComponent( path, {"manager": self}) self._dialog.textChanged.connect(self.onFilenameChanged) self._dialog.accepted.connect(self.onFilenameAccepted) self._dialog.show() self._dialog.findChild(QObject, "nameField").setProperty( 'text', self._fileName) self._dialog.findChild(QObject, "nameField").select( 0, len(self._fileName) - len(self._output_format) - 1) self._dialog.findChild(QObject, "nameField").setProperty('focus', True) self._dialog.findChild(QObject, "printField").setProperty( 'checked', self._upload_start_print_job)
def requestWrite(self, node, file_name=None): if self._writing: raise OutputDeviceError.DeviceBusyError() 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() if 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( "@info:progress", "Saving to Removable Drive <filename>{0}</filename>"). format(self.getName()), 0, False, -1) message.show() self.writeStarted.emit(self) job._message = message self._writing = True job.start() except PermissionError as e: raise OutputDeviceError.PermissionDeniedError() from e except OSError as e: raise OutputDeviceError.WriteRequestFailedError() from e
def requestWrite(self, node, file_name = None, filter_by_machine = False): filter_by_machine = True # This plugin is indended to be used by machine (regardless of what it was told to do) if self._writing: raise OutputDeviceError.DeviceBusyError() file_formats = Application.getInstance().getMeshFileHandler().getSupportedFileTypesWrite() #Formats supported by this application. if filter_by_machine: machine_file_formats = Application.getInstance().getMachineManager().getActiveMachineInstance().getMachineDefinition().getFileFormats() file_formats = list(filter(lambda file_format: file_format["mime_type"] in machine_file_formats, file_formats)) #Take the intersection between file_formats and machine_file_formats. if len(file_formats) == 0: Logger.log("e", "There are no file formats available to write with!") raise OutputDeviceError.WriteRequestFailedError() writer = Application.getInstance().getMeshFileHandler().getWriterByMimeType(file_formats[0]["mime_type"]) #Just take the first file format available. extension = file_formats[0]["extension"] if 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() if extension: #Not empty string. extension = "." + extension file_name = os.path.join(self.getId(), os.path.splitext(file_name)[0] + extension) try: Logger.log("d", "Writing to %s", file_name) stream = open(file_name, "wt") job = WriteMeshJob(writer, stream, node, MeshWriter.OutputMode.TextMode) job.setFileName(file_name) job.progress.connect(self._onProgress) job.finished.connect(self._onFinished) message = Message(catalog.i18nc("@info:progress", "Saving to Removable Drive <filename>{0}</filename>").format(self.getName()), 0, False, -1) message.show() self.writeStarted.emit(self) job._message = 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() 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() from e
def deleteMacros(self): if self._stage != OutputStage.ready: raise OutputDeviceError.DeviceBusyError() self.fileStructer(self._url, 'macros') Logger.log('i', 'Macs: '+ str(self._macStruct)) Logger.log('i', 'Dirs: '+str(self._dirStruct)) for mac in self._macStruct: Logger.log('i','1') self._send('delete',[('name',"0:/"+mac),self._timestamp()], self.onMacroDeleted) sleep(.1) for dir in self._dirStruct: Logger.log('i','1') self._send('delete',[('name',"0:/"+dir),self._timestamp()], self.onMacroDeleted) sleep(.1) self.updateMacros()
def requestWrite(self, node, fileName=None, *args, **kwargs): if self._stage != OutputStage.ready: raise OutputDeviceError.DeviceBusyError() if fileName: fileName = self.nameMaker() + '.gcode' else: fileName = "%s.gcode" % Application.getInstance().getPrintInformation().jobName self._fileName = fileName self._baseLength = len(Application.getInstance().getPrintInformation().baseName) path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'qml', 'UploadFilename.qml') self._dialog = CuraApplication.getInstance().createQmlComponent(path, {"manager": self}) self._dialog.textChanged.connect(self.onFilenameChanged) self._dialog.accepted.connect(self.onFilenameAccepted) self._dialog.show() self._dialog.findChild(QObject, "nameField").setProperty('text', self._fileName) self._dialog.findChild(QObject, "nameField").select(0, self._baseLength) self._dialog.findChild(QObject, "nameField").setProperty('focus', True)
def sendPrintJob(self): nodes, file_name, filter_by_machine, file_handler, kwargs = self._request_job require_printer_name = self._selected_printer["unique_name"] self._send_gcode_start = time.time() Logger.log("d", "Sending print job [%s] to host..." % file_name) if self._stage != OutputStage.ready: Logger.log("d", "Unable to send print job as the state is %s", self._stage) raise OutputDeviceError.DeviceBusyError() self._stage = OutputStage.uploading self._file_name = "%s.gcode.gz" % file_name self._showProgressMessage() self._request = self._buildSendPrintJobHttpRequest( require_printer_name) self._reply = self._manager.post(self._request, self._multipart) self._reply.uploadProgress.connect(self._onUploadProgress)
def requestWrite(self, node, file_name=None, filter_by_machine=False): if self._writing: raise OutputDeviceError.DeviceBusyError() self.writeStarted.emit(self) mesh_writer = Application.getInstance().getMeshFileHandler( ).getWriterByMimeType("text/x-gcode") job = OctoprintUploadJob(mesh_writer, node) job.setFileName(file_name + ".gcode") job.progress.connect(self._onJobProgress) job.finished.connect(self._onWriteJobFinished) message = Message("Uploading {0} to {1}".format( job.getFileName(), Preferences.getInstance().getValue("octoprint/base_url")), 0, progress=-1) message.show() job._message = message self._writing = True job.start()
def requestWrite(self, node, fileName=None, *args, **kwargs): if self._stage != OutputStage.ready: raise OutputDeviceError.DeviceBusyError() if fileName: fileName = os.path.splitext(fileName)[0] + '.gcode' else: fileName = "%s.gcode" % Application.getInstance( ).getPrintInformation().jobName self._fileName = fileName # create the temp file for the gcode self._stream = StringIO() self._stage = OutputStage.writing self.writeStarted.emit(self) # show a progress message message = Message( catalog.i18nc("@info:progress", "Saving to <filename>{0}</filename>").format( self.getName()), 0, False, -1) message.show() self._message = message # send all the gcode to self._stream gcode = getattr(Application.getInstance().getController().getScene(), "gcode_list") lines = len(gcode) nextYield = time() + 0.05 i = 0 for line in gcode: i += 1 self._stream.write(line) if time() > nextYield: self._onProgress(i / lines) QCoreApplication.processEvents() nextYield = time() + 0.05 # self._stream now contains the gcode, now upload it self._stage = OutputStage.uploading self._stream.seek(0) # set up a multi-part post self._multipart = QtNetwork.QHttpMultiPart( QtNetwork.QHttpMultiPart.FormDataType) # add the file part part = QtNetwork.QHttpPart() part.setHeader(QtNetwork.QNetworkRequest.ContentDispositionHeader, 'form-data; name="file"; filename="%s"' % fileName) part.setHeader(QtNetwork.QNetworkRequest.ContentTypeHeader, "application/octet-stream") part.setBody(self._stream.getvalue().encode()) self._multipart.append(part) # send the post url = "http://" + self._address + "/print" Logger.log("d", url) self._request = QtNetwork.QNetworkRequest(QUrl(url)) self._request.setRawHeader('User-agent'.encode(), 'Cura WirelessPrinting Plugin'.encode()) self._reply = self._qnam.post(self._request, self._multipart) # connect the reply signals self._reply.error.connect(self._onNetworkError) self._reply.uploadProgress.connect(self._onUploadProgress) self._reply.downloadProgress.connect(self._onDownloadProgress)
def requestWrite(self, node, fileName=None, *args, **kwargs): if self._stage != OutputStage.ready: raise OutputDeviceError.DeviceBusyError() if fileName: fileName = os.path.splitext(fileName)[0] + '.gcode' else: fileName = "%s.gcode" % Application.getInstance( ).getPrintInformation().jobName self._fileName = fileName # create the temp file for the gcode self._stream = StringIO() self._stage = OutputStage.writing self.writeStarted.emit(self) # show a progress message message = Message( catalog.i18nc("@info:progress", "Saving to <filename>{0}</filename>").format( self.getName()), 0, False, -1) message.show() self._message = message # send all the gcode to self._stream gcode = getattr(Application.getInstance().getController().getScene(), "gcode_list") lines = len(gcode) nextYield = time() + 0.05 i = 0 for line in gcode: i += 1 self._stream.write(line) if time() > nextYield: self._onProgress(i / lines) QCoreApplication.processEvents() nextYield = time() + 0.05 # self._stream now contains the gcode, now upload it self._stage = OutputStage.uploading self._stream.seek(0) # set up a multi-part post self._multipart = QtNetwork.QHttpMultiPart( QtNetwork.QHttpMultiPart.FormDataType) # add the file part part = QtNetwork.QHttpPart() part.setHeader(QtNetwork.QNetworkRequest.ContentDispositionHeader, 'form-data; name="file"; filename="%s"' % fileName) part.setHeader(QtNetwork.QNetworkRequest.ContentTypeHeader, "application/octet-stream") part.setBody(self._stream.getvalue().encode()) self._multipart.append(part) # send the post url = "http://" + self._address + "/print" Logger.log("d", url) self._update_timer.stop() #################################################### # This is working but ugly. Pull Requests welcome. fd = open('/tmp/' + fileName, "w") fd.write(self._stream.getvalue()) fd.close() command = 'curl -F "file=@/tmp/' + fileName + '" ' + url Logger.log("d", command) import subprocess, shlex subprocess.Popen(shlex.split(command)) self._stage = OutputStage.ready if self._message: self._message.hide() self._message = None
def requestWrite(self, node, fileName=None, *args, **kwargs): if self._stage != OutputStage.ready: raise OutputDeviceError.DeviceBusyError() if fileName: fileName = os.path.splitext(fileName)[0] + '.gcode' else: fileName = "%s.gcode" % Application.getInstance( ).getPrintInformation().jobName self._fileName = fileName # create the temp file for the gcode self._stream = StringIO() self._stage = OutputStage.writing self.writeStarted.emit(self) # show a progress message message = Message( catalog.i18nc("@info:progress", "Saving to <filename>{0}</filename>").format( self.getName()), 0, False, -1) message.show() self._message = message # find the G-code for the active build plate to print active_build_plate_id = Application.getInstance().getBuildPlateModel( ).activeBuildPlate gcode_dict = getattr( Application.getInstance().getController().getScene(), "gcode_dict") gcode = gcode_dict[active_build_plate_id] # send all the gcode to self._stream lines = len(gcode) nextYield = time() + 0.05 i = 0 for line in gcode: i += 1 self._stream.write(line) if time() > nextYield: self._onProgress(i / lines) QCoreApplication.processEvents() nextYield = time() + 0.05 # self._stream now contains the gcode, now upload it self._stage = OutputStage.uploading self._stream.seek(0) # set up a multi-part post self._multipart = QtNetwork.QHttpMultiPart( QtNetwork.QHttpMultiPart.FormDataType) # add the form variables formvalues = {'select': 'false', 'print': 'false'} for key, value in formvalues.items(): part = QtNetwork.QHttpPart() part.setHeader(QtNetwork.QNetworkRequest.ContentDispositionHeader, 'form-data; name="%s"' % key) part.setBody(value.encode()) self._multipart.append(part) # add the file part part = QtNetwork.QHttpPart() part.setHeader(QtNetwork.QNetworkRequest.ContentDispositionHeader, 'form-data; name="file"; filename="%s"' % fileName) part.setBody(self._stream.getvalue().encode()) self._multipart.append(part) # send the post self._request = QtNetwork.QNetworkRequest( QUrl(self._host + "/api/files/local")) self._request.setRawHeader( 'User-agent'.encode(), 'Cura OctoPrintOutputDevice Plugin'.encode()) self._request.setRawHeader('X-Api-Key'.encode(), self._apiKey.encode()) self._reply = self._qnam.post(self._request, self._multipart) # connect the reply signals self._reply.error.connect(self._onNetworkError) self._reply.uploadProgress.connect(self._onUploadProgress) self._reply.downloadProgress.connect(self._onDownloadProgress)
def requestWrite(self, nodes, file_name=None, limit_mimetypes=None, file_handler=None, **kwargs): if self._writing: raise OutputDeviceError.DeviceBusyError() # Set up and display file dialog dialog = QFileDialog() dialog.setWindowTitle(catalog.i18nc("@title:window", "Save to File")) dialog.setFileMode(QFileDialog.AnyFile) dialog.setAcceptMode(QFileDialog.AcceptSave) # Ensure platform never ask for overwrite confirmation since we do this ourselves dialog.setOption(QFileDialog.DontConfirmOverwrite) if sys.platform == "linux" and "KDE_FULL_SESSION" in os.environ: dialog.setOption(QFileDialog.DontUseNativeDialog) filters = [] mime_types = [] selected_filter = None last_used_type = self._preferences.getValue( "local_file/last_used_type") 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)) if len(file_types) == 0: Logger.log("e", "There are no file types available to write with!") raise OutputDeviceError.WriteRequestFailedError() 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 last_used_type == item["mime_type"]: selected_filter = type_filter if file_name: file_name += "." + item["extension"] dialog.setNameFilters(filters) if selected_filter is not None: dialog.selectNameFilter(selected_filter) if file_name is not None: dialog.selectFile(file_name) stored_directory = self._preferences.getValue( "local_file/dialog_save_path") dialog.setDirectory(stored_directory) if not dialog.exec_(): raise OutputDeviceError.UserCanceledError() save_path = dialog.directory().absolutePath() self._preferences.setValue("local_file/dialog_save_path", save_path) selected_type = file_types[filters.index(dialog.selectedNameFilter())] self._preferences.setValue("local_file/last_used_type", selected_type["mime_type"]) # Get file name from file dialog file_name = dialog.selectedFiles()[0] active_build_plate = Application.getInstance().getMultiBuildPlateModel( ).activeBuildPlate scene = Application.getInstance().getController().getScene() gcode_dict = getattr(scene, "gcode_dict", None) if not gcode_dict: return _gcode = gcode_dict.get(active_build_plate, None) self.save_gcode(file_name, _gcode)
def requestWrite(self, node, file_name=None, filter_by_machine=False): if self._writing: raise OutputDeviceError.DeviceBusyError() self._writing = True # load settings if Preferences.getInstance().getValue("MPSelectMini/ip"): ip = Preferences.getInstance().getValue("MPSelectMini/ip") if Preferences.getInstance().getValue("MPSelectMini/start_print"): start_print = Preferences.getInstance().getValue( "MPSelectMini/start_print") try: start_print except NameError: start_print = False # check for valid ip if not ip: raise OutputDeviceError.WriteRequestFailedError( catalog.i18nc("@info:status", "Invalid IP")) # Get GCode file_formats = Application.getInstance().getMeshFileHandler( ).getSupportedFileTypesWrite() mesh_writer = Application.getInstance().getMeshFileHandler( ).getWriterByMimeType("text/x-gcode") stream = io.StringIO() mesh_writer.write(stream, node, MeshWriter.OutputMode.TextMode) gcode = stream.getvalue() try: # Upload GCode s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((ip, 80)) s.send(bytes('POST /upload HTTP/1.1\r\n', 'ascii')) s.send( bytes( 'Content-Type: multipart/form-data; boundary=------------------------2d30fc993bb09c6a\r\n', 'ascii')) s.send(bytes('\r\n', 'ascii')) s.send( bytes('--------------------------2d30fc993bb09c6a\r\n', 'ascii')) s.send( bytes( 'Content-Disposition: form-data; name="filedata"; filename="cache.gc"\r\n', 'ascii')) s.send(bytes('Content-Type: application/octet-stream\r\n', 'ascii')) s.send(bytes('\r\n', 'ascii')) s.send(bytes(gcode, 'ascii')) s.send(bytes('\r\n', 'ascii')) s.send( bytes('--------------------------2d30fc993bb09c6a--\r\n', 'ascii')) response = str(s.recv(1024), 'ascii') s.close() # Check upload response if response.startswith('HTTP/1.1 200 OK'): message = Message( catalog.i18nc("@info:status", "Upload Success")) message.show() else: Logger.log( "e", "Invalid http response uploading gcode:\n" + response) raise OutputDeviceError.WriteRequestFailedError( catalog.i18nc("@info:status", "Upload Failed")) # Send cancel print (prevents upload bug where printer will start before heating extruder) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((ip, 80)) s.send(bytes('GET /set?cmd={P:X} HTTP/1.1\r\n', 'ascii')) s.send(bytes('\r\n', 'ascii')) response = str(s.recv(1024), 'ascii') s.close() if start_print: # Send start print s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((ip, 80)) s.send(bytes('GET /set?code=M565 HTTP/1.1\r\n', 'ascii')) s.send(bytes('\r\n', 'ascii')) response = str(s.recv(1024), 'ascii') s.close() # Check start print response if response.startswith('HTTP/1.1 200 OK'): message = Message( catalog.i18nc("@info:status", "<b>Printing Started</b>")) message.show() else: Logger.log( "e", "Invalid http response starting print job:\n" + response) raise OutputDeviceError.WriteRequestFailedError( catalog.i18nc("@info:status", "Start Print Failed")) except (TimeoutError): raise OutputDeviceError.WriteRequestFailedError( catalog.i18nc("@info:status", "Connection Timeout")) self._writing = False
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 requestWrite(self, nodes, file_name=None, filter_by_machine=False, file_handler=None, **kwargs): filter_by_machine = True # This plugin is intended to be used by machine (regardless of what it was told to do) if self._writing: raise OutputDeviceError.DeviceBusyError() # Formats supported by this application (File types that we can actually write) if file_handler: file_formats = file_handler.getSupportedFileTypesWrite() else: file_formats = Application.getInstance().getMeshFileHandler( ).getSupportedFileTypesWrite() if filter_by_machine: container = Application.getInstance().getGlobalContainerStack( ).findContainer({"file_formats": "*"}) # Create a list from supported file formats string machine_file_formats = [ file_type.strip() for file_type in container.getMetaDataEntry( "file_formats").split(";") ] # Take the intersection between file_formats and machine_file_formats. format_by_mimetype = { format["mime_type"]: format for format in file_formats } file_formats = [ format_by_mimetype[mimetype] for mimetype in machine_file_formats ] #Keep them ordered according to the preference in machine_file_formats. if len(file_formats) == 0: Logger.log("e", "There are no file formats available to write with!") raise OutputDeviceError.WriteRequestFailedError( catalog.i18nc( "@info:status", "There are no file formats available to write with!")) preferred_format = file_formats[0] # Just take the first file format available. if file_handler is not None: writer = file_handler.getWriterByMimeType( preferred_format["mime_type"]) else: writer = Application.getInstance().getMeshFileHandler( ).getWriterByMimeType(preferred_format["mime_type"]) extension = preferred_format["extension"] if file_name is None: file_name = self._automaticFileName(nodes) if extension: # Not empty string. extension = "." + extension file_name = os.path.join(self.getId(), os.path.splitext(file_name)[0] + extension) try: Logger.log("d", "Writing to %s", file_name) # Using buffering greatly reduces the write time for many lines of gcode if preferred_format["mode"] == FileWriter.OutputMode.TextMode: self._stream = open(file_name, "wt", buffering=1, encoding="utf-8") else: #Binary mode. self._stream = open(file_name, "wb", buffering=1) job = WriteFileJob(writer, self._stream, nodes, preferred_format["mode"]) job.setFileName(file_name) job.progress.connect(self._onProgress) job.finished.connect(self._onFinished) message = Message( catalog.i18nc( "@info:progress Don't translate the XML tags <filename>!", "Saving to Removable Drive <filename>{0}</filename>"). format(self.getName()), 0, False, -1, catalog.i18nc("@info:title", "Saving")) message.show() self.writeStarted.emit(self) 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> or <message>!", "Could not save to <filename>{0}</filename>: <message>{1}</message>" ).format(file_name, str(e))) 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 requestWrite(self, nodes, file_name=None, limit_mimetypes=None, file_handler=None): if self._writing: raise OutputDeviceError.DeviceBusyError() dialog = QFileDialog() dialog.setWindowTitle(catalog.i18nc("@title:window", "Save to File")) dialog.setFileMode(QFileDialog.AnyFile) dialog.setAcceptMode(QFileDialog.AcceptSave) # Ensure platform never ask for overwrite confirmation since we do this ourselves dialog.setOption(QFileDialog.DontConfirmOverwrite) if sys.platform == "linux" and "KDE_FULL_SESSION" in os.environ: dialog.setOption(QFileDialog.DontUseNativeDialog) filters = [] mime_types = [] selected_filter = None last_used_type = Preferences.getInstance().getValue( "local_file/last_used_type") 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)) if len(file_types) == 0: Logger.log("e", "There are no file types available to write with!") raise OutputDeviceError.WriteRequestFailedError() 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 last_used_type == item["mime_type"]: selected_filter = type_filter if file_name: file_name += "." + item["extension"] dialog.setNameFilters(filters) if selected_filter is not None: dialog.selectNameFilter(selected_filter) if file_name is not None: dialog.selectFile(file_name) stored_directory = Preferences.getInstance().getValue( "local_file/dialog_save_path") dialog.setDirectory(stored_directory) if not dialog.exec_(): raise OutputDeviceError.UserCanceledError() save_path = dialog.directory().absolutePath() Preferences.getInstance().setValue("local_file/dialog_save_path", save_path) selected_type = file_types[filters.index(dialog.selectedNameFilter())] Preferences.getInstance().setValue("local_file/last_used_type", selected_type["mime_type"]) file_name = dialog.selectedFiles()[0] if os.path.exists(file_name): result = QMessageBox.question( None, catalog.i18nc("@title:window", "File Already Exists"), 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: raise OutputDeviceError.UserCanceledError() self.writeStarted.emit(self) if file_handler: file_writer = file_handler.getWriter(selected_type["id"]) else: file_writer = Application.getInstance().getMeshFileHandler( ).getWriter(selected_type["id"]) 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") job = WriteFileJob(file_writer, stream, nodes, mode) job.setFileName(file_name) job.progress.connect(self._onJobProgress) job.finished.connect(self._onWriteJobFinished) message = Message( catalog.i18nc( "@info:progress", "Saving to <filename>{0}</filename>").format(file_name), 0, False, -1) message.show() job._message = 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", "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", "Could not save to <filename>{0}</filename>: <message>{1}</message>" ).format()) from e
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 File")) dialog.setFileMode(QFileDialog.AnyFile) dialog.setAcceptMode(QFileDialog.AcceptSave) # Ensure platform never ask for overwrite confirmation since we do this ourselves dialog.setOption(QFileDialog.DontConfirmOverwrite) if sys.platform == "linux" and "KDE_FULL_SESSION" in os.environ: dialog.setOption(QFileDialog.DontUseNativeDialog) 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") 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) #file_name = file_name.replace('.gcode','.s3d') print(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.No: raise OutputDeviceError.UserCanceledError() self.writeStarted.emit(self) # Actually writing file if file_handler: file_writer = file_handler.getWriter(selected_type["id"]) else: file_writer = Application.getInstance().getMeshFileHandler( ).getWriter(selected_type["id"]) 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 #print("HELLO WRITE FILE") #print(file_writer) #print(stream) #print(nodes) #print(mode) #print("HELLO WRITE FILE DONE") 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) save_name = file_name.replace('.gcode', '.s3d') message = Message( catalog.i18nc( "@info:progress Don't translate the XML tags <filename>!", "Saving to <filename>{0}</filename>").format(save_name), 0, False, -1, catalog.i18nc("@info:title", "Saving")) message.show() job.setMessage(message) self._writing = True import base64 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.fernet import Fernet, InvalidToken key = b'fWn9BDrXryrtcxjXhaO2BR9Oc_bS_zk1k4b6aL_0rbI=' input_file = file_name if '.gcode' in file_name: output_file = file_name.replace('.gcode', '.s3d') else: output_file = file_name + '.s3d' #with open(input_file, 'rb') as f: # data = f.read() # Read the bytes of the input file #f.close() #print(data) fernet = Fernet(key) #encrypted = fernet.encrypt(data) #print(len(encrypted)) #with open(output_file, 'wb') as f: # f.write(encrypted) # Write the encrypted bytes to the output file job.start() with open(input_file, 'rb') as f: data = f.read() #print(data) encrypted = fernet.encrypt(data) with open(output_file, 'wb') as f: f.write(encrypted) #import os if os.path.exists(input_file): os.remove(input_file) # os.remove('/home/akshay/STLS/*') else: print("GCODE FILE MOVED OR TAMPERED WITH") 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 requestWrite(self, nodes, file_name=None, limit_mimetypes=None, file_handler=None, **kwargs): application = cast(CuraApplication, Application.getInstance()) machine_manager = application.getMachineManager() global_stack = machine_manager.activeMachine filename_format = Application.getInstance().getPreferences().getValue( "gcode_filename_format/filename_format") Logger.log("d", "filename_format = %s", filename_format) if filename_format is "": filename_format = DEFAULT_FILENAME_FORMAT if self._writing: raise OutputDeviceError.DeviceBusyError() self.getModifiedPrintSettings(application, global_stack) dialog = QFileDialog() dialog.setWindowTitle(catalog.i18nc("@title:window", "Save to File")) dialog.setFileMode(QFileDialog.AnyFile) dialog.setAcceptMode(QFileDialog.AcceptSave) dialog.setOption(QFileDialog.DontConfirmOverwrite) if sys.platform == "linux" and "KDE_FULL_SESSION" in os.environ: dialog.setOption(QFileDialog.DontUseNativeDialog) 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("gcode_filename_format/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!")) 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 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 file_name = self.parseFilenameFormat(filename_format, file_name, application, global_stack) #file_name += self.filenameTackOn(print_setting) if file_name: file_name += "." + item["extension"] stored_directory = Application.getInstance().getPreferences().getValue( "gcode_filename_format/dialog_save_path") dialog.setDirectory(stored_directory) 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( "gcode_filename_format/dialog_save_path", save_path) selected_type = file_types[filters.index(dialog.selectedNameFilter())] Application.getInstance().getPreferences().setValue( "gcode_filename_format/last_used_type", selected_type["mime_type"]) 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.No: raise OutputDeviceError.UserCanceledError() self.writeStarted.emit(self) if file_handler: file_writer = file_handler.getWriter(selected_type["id"]) else: file_writer = Application.getInstance().getMeshFileHandler( ).getWriter(selected_type["id"]) 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) 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()) from e
def requestWrite(self, nodes, file_name=None, limit_mimetypes=None, file_handler=None, **kwargs): if self._writing: raise OutputDeviceError.DeviceBusyError() # Set up and display file dialog dialog = QFileDialog() dialog.setWindowTitle(self._translations.get("save_file_window")) dialog.setFileMode(QFileDialog.AnyFile) dialog.setAcceptMode(QFileDialog.AcceptSave) # Ensure platform never ask for overwrite confirmation since we do this ourselves dialog.setOption(QFileDialog.DontConfirmOverwrite) if sys.platform == "linux" and "KDE_FULL_SESSION" in os.environ: dialog.setOption(QFileDialog.DontUseNativeDialog) 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( self._translations.get("no_file_warning")) # 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 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: 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") 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, self._translations.get("file_exists_window").format( file_name[file_name.rfind("/") + 1:]), self._translations.get("file_overwrite_label").format( file_name[file_name.rfind("/") + 1:])) if result == QMessageBox.No: raise OutputDeviceError.UserCanceledError() self.writeStarted.emit(self) # Actually writing file if file_handler: file_writer = file_handler.getWriter(selected_type["id"]) else: file_writer = Application.getInstance().getMeshFileHandler( ).getWriter(selected_type["id"]) 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 # Adding screeshot section screenshot_string = utils.add_screenshot() if screenshot_string != "": stream.write(screenshot_string) # End of screeshot section job = WriteFileJob(file_writer, stream, nodes, mode) job.setFileName(file_name) # The file will be added into the "recent files" list upon success job.setAddToRecentFiles(True) job.progress.connect(self._onJobProgress) job.finished.connect(self._onWriteJobFinished) message = Message( self._translations.get("file_saving_progress").format( file_name), 0, False, -1, self._translations.get("file_saving_title")) 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( self._translations.get("permission_denied").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( self._translations.get("permission_denied2").format( file_name, str(e))) from e