def _getAllBroadcast(self): ipconfig_process = subprocess.Popen('ifconfig' if Platform.isLinux() or Platform.isOSX() else 'ipconfig', stdout=subprocess.PIPE, shell=True) output = ipconfig_process.stdout.read().decode('utf-8', 'ignore') allIPlist = re.findall('\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}', output) allIP = '' for j in allIPlist: if j.count('255.255') < 1: allIP += j + ' ' ipList = gethostbyname_ex(gethostname()) if len(ipList) == 3: ipList = ipList[2] broadcast = [] for i in range(len(allIPlist)): ipaddr = allIPlist[i] if ipaddr in ipList and ipaddr != '127.0.0.1' and i + 1 <= len(allIPlist): if Platform.isLinux() or Platform.isOSX(): broadcast.append(allIPlist[(i + 1)]) else: broadcast.append(self._generate_broad_addr(ipaddr, allIPlist[(i + 1)])) if not broadcast: Logger.log("w", "Cann't find valid boradcast,use all IP") broadcast = allIPlist return broadcast
def _updateContainerNameFilters(self) -> None: self._container_name_filters = {} plugin_registry = cura.CuraApplication.CuraApplication.getInstance( ).getPluginRegistry() container_registry = cura.CuraApplication.CuraApplication.getInstance( ).getContainerRegistry() for plugin_id, container_type in container_registry.getContainerTypes( ): # Ignore default container types since those are not plugins if container_type in (InstanceContainer, ContainerStack, DefinitionContainer, GlobalStack, ExtruderStack): continue serialize_type = "" try: plugin_metadata = plugin_registry.getMetaData(plugin_id) if plugin_metadata: serialize_type = plugin_metadata["settings_container"][ "type"] else: continue except KeyError as e: continue mime_type = container_registry.getMimeTypeForContainer( container_type) if mime_type is None: continue entry = { "type": serialize_type, "mime": mime_type, "container": container_type } suffix = mime_type.preferredSuffix if Platform.isOSX() and "." in suffix: # OSX's File dialog is stupid and does not allow selecting files with a . in its name suffix = suffix[suffix.index(".") + 1:] suffix_list = "*." + suffix for suffix in mime_type.suffixes: if suffix == mime_type.preferredSuffix: continue if Platform.isOSX() and "." in suffix: # OSX's File dialog is stupid and does not allow selecting files with a . in its name suffix = suffix[suffix.index("."):] suffix_list += ", *." + suffix name_filter = "{0} ({1})".format(mime_type.comment, suffix_list) self._container_name_filters[name_filter] = entry
def register(app): if Platform.isWindows() or Platform.isLinux() or Platform.isOSX(): from . import OpenSCADReader # @UnresolvedImport return {"mesh_reader": OpenSCADReader.OpenSCADReader()} else: Logger.logException("i", "Unsupported OS!") return {}
def getMetaData() -> Dict: # Workarround for osx not supporting double file extensions correclty. if Platform.isOSX(): workspace_extension = "3mf" else: workspace_extension = "curaproject.3mf" metaData = { "plugin": { "name": catalog.i18nc("@label", "3MF Reader"), "author": "Ultimaker", "version": "1.0", "description": catalog.i18nc("@info:whatsthis", "Provides support for reading 3MF files."), "api": 3 } } if "3MFReader.ThreeMFReader" in sys.modules: metaData["mesh_reader"] = [ { "extension": "3mf", "description": catalog.i18nc("@item:inlistbox", "3MF File") } ] metaData["workspace_reader"] = [ { "extension": workspace_extension, "description": catalog.i18nc("@item:inlistbox", "3MF File") } ] return metaData
def get_cura_dir_path(): if Platform.isWindows(): return os.path.expanduser("~/AppData/Roaming/" + CuraAppName) elif Platform.isLinux(): return os.path.expanduser("~/.local/share/" + CuraAppName) elif Platform.isOSX(): return os.path.expanduser("~/Library/Logs/" + CuraAppName)
def _sendCrashReport(self): # Before sending data, the user comments are stored self.data["user_info"] = self.user_description_text_area.toPlainText() # Convert data to bytes binary_data = json.dumps(self.data).encode("utf-8") # Submit data kwoptions = {"data": binary_data, "timeout": 5} if Platform.isOSX(): kwoptions["context"] = ssl._create_unverified_context() Logger.log("i", "Sending crash report info to [%s]...", self.crash_url) try: f = urllib.request.urlopen(self.crash_url, **kwoptions) Logger.log("i", "Sent crash report info.") f.close() except urllib.error.HTTPError: Logger.logException( "e", "An HTTP error occurred while trying to send crash report") except Exception: # We don't want any exception to cause problems Logger.logException( "e", "An exception occurred while trying to send crash report") os._exit(1)
def setBlenderPath(self, outdated=False): """Tries to set the path to blender automatically, if unsuccessful the user can set it manually. :param outdated: Flag if the found blender version is outdated. """ # Stops here because blender path from settings file is correct. if not outdated_blender_version or outdated: # Supports multi-platform if Platform.isWindows(): temp_blender_path = glob.glob( 'C:/Program Files/Blender Foundation/**/*.exe') blender_path = temp_blender_path[len(temp_blender_path) - 1].replace('\\', '/') elif Platform.isOSX(): blender_path = '/Applications/Blender.app/Contents/MacOS/Blender' elif Platform.isLinux(): blender_path = '/usr/bin/blender' else: blender_path = None # If unsuccessful the user can set it manually. if not os.path.exists(blender_path): self._openFileDialog() else: # Adds blender path in settings file. Application.getInstance().getPreferences().setValue( 'cura_blender/blender_path', blender_path) self.verifyBlenderPath(manual=False)
def run(self): if not self.url or not self.data: Logger.log("e", "URL or DATA for sending slice info was not set!") return # Submit data kwoptions = {"data": self.data, "timeout": 5} if Platform.isOSX(): kwoptions["context"] = ssl._create_unverified_context() try: f = urllib.request.urlopen(self.url, **kwoptions) Logger.log("i", "Sent anonymous slice info to %s", self.url) f.close() except urllib.error.HTTPError as http_exception: Logger.log( "e", "An HTTP error occurred while trying to send slice information: %s" % http_exception) except Exception as e: # We don't want any exception to cause problems Logger.log( "e", "An exception occurred while trying to send slice information: %s" % e)
def event(self, event): if event.type == Event.ViewActivateEvent: # FIX: on Max OS X, somehow QOpenGLContext.currentContext() can become None during View switching. # This can happen when you do the following steps: # 1. Start Cura # 2. Load a model # 3. Switch to Custom mode # 4. Select the model and click on the per-object tool icon # 5. Switch view to Layer view or X-Ray # 6. Cura will very likely crash # It seems to be a timing issue that the currentContext can somehow be empty, but I have no clue why. # This fix tries to reschedule the view changing event call on the Qt thread again if the current OpenGL # context is None. if Platform.isOSX(): if QOpenGLContext.currentContext() is None: Logger.log("d", "current context of OpenGL is empty on Mac OS X, will try to create shaders later") Application.getInstance().callLater(lambda e = event: self.event(e)) return if event.type == Event.ViewDeactivateEvent: if self._composite_pass and 'xray' in self._composite_pass.getLayerBindings(): self.getRenderer().removeRenderPass(self._xray_pass) self._composite_pass.setLayerBindings(self._old_layer_bindings) self._composite_pass.setCompositeShader(self._old_composite_shader) self._xray_warning_message.hide()
def __init__(self, *args): super().__init__(*args) self._previous_extension = "" # Only do this on OS X if Platform.isOSX(): self.filterSelected.connect(self._onFilterChanged)
def getMetaData() -> Dict: # Workarround for osx not supporting double file extensions correclty. if Platform.isOSX(): workspace_extension = "3mf" else: workspace_extension = "curaproject.3mf" return { "plugin": { "name": catalog.i18nc("@label", "3MF Reader"), "author": "Ultimaker", "version": "1.0", "description": catalog.i18nc("@info:whatsthis", "Provides support for reading 3MF files."), "api": 3 }, "mesh_reader": [{ "extension": "3mf", "description": catalog.i18nc("@item:inlistbox", "3MF File") }], "workspace_reader": [{ "extension": workspace_extension, "description": catalog.i18nc("@item:inlistbox", "3MF File") }] }
def get_steslicer_dir_path(): if Platform.isWindows(): return os.path.expanduser("~/AppData/Roaming/steslicer") elif Platform.isLinux(): return os.path.expanduser("~/.local/share/steslicer") elif Platform.isOSX(): return os.path.expanduser("~/Library/Logs/steslicer")
def register(app): if Platform.isWindows(): from . import BigtreeWindowsRemovableDrivePlugin return { "output_device": BigtreeWindowsRemovableDrivePlugin. BigtreeWindowsRemovableDrivePlugin() } elif Platform.isOSX(): from . import BigtreeOSXRemovableDrivePlugin return { "output_device": BigtreeOSXRemovableDrivePlugin.BigtreeOSXRemovableDrivePlugin() } elif Platform.isLinux(): from . import BigtreeLinuxRemovableDrivePlugin return { "output_device": BigtreeLinuxRemovableDrivePlugin.BigtreeLinuxRemovableDrivePlugin( ) } else: Logger.log( "e", "Unsupported system, thus no removable device hotplugging support available." ) return {}
def get_cura_dir_path(): if Platform.isWindows(): return os.path.expanduser("~/AppData/Roaming/continuum-test") elif Platform.isLinux(): return os.path.expanduser("~/.local/share/continuum-test") elif Platform.isOSX(): return os.path.expanduser("~/Library/Logs/continuum-test")
def get_cura_dir_for_stdoutputs() -> str: if Platform.isWindows(): return os.path.expanduser("~/AppData/Roaming/cura/") elif Platform.isLinux(): return os.path.expanduser("~/.local/share/cura") elif Platform.isOSX(): return os.path.expanduser("~/Library/Logs/cura")
def get_cura_dir_path(): if Platform.isWindows(): return os.path.expanduser("~/AppData/Local/cura/") elif Platform.isLinux(): return os.path.expanduser("~/.local/share/cura") elif Platform.isOSX(): return os.path.expanduser("~/Library/Logs/cura")
def getMetaData(): # Workarround for osx not supporting double file extensions correctly. if Platform.isOSX(): workspace_extension = "3mf" else: workspace_extension = "curaproject.3mf" metaData = {} if "3MFWriter.ThreeMFWriter" in sys.modules: metaData["mesh_writer"] = { "output": [{ "extension": "3mf", "description": i18n_catalog.i18nc("@item:inlistbox", "3MF file"), "mime_type": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml", "mode": ThreeMFWriter.ThreeMFWriter.OutputMode.BinaryMode }] } metaData["workspace_writer"] = { "output": [{ "extension": workspace_extension, "description": i18n_catalog.i18nc("@item:inlistbox", "Cura Project 3MF file"), "mime_type": "application/x-curaproject+xml", "mode": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter.OutputMode.BinaryMode }] } return metaData
def _sendCrashReport(self): # Before sending data, the user comments are stored self.data["user_info"] = self.user_description_text_area.toPlainText() # Convert data to bytes binary_data = json.dumps(self.data).encode("utf-8") # Submit data kwoptions = {"data": binary_data, "timeout": 5} if Platform.isOSX(): kwoptions["context"] = ssl._create_unverified_context() Logger.log("i", "Sending crash report info to [%s]...", self.crash_url) if not self.has_started: print("Sending crash report info to [%s]...\n" % self.crash_url) try: f = urllib.request.urlopen(self.crash_url, **kwoptions) Logger.log("i", "Sent crash report info.") if not self.has_started: print("Sent crash report info.\n") f.close() except urllib.error.HTTPError as e: Logger.logException("e", "An HTTP error occurred while trying to send crash report") if not self.has_started: print("An HTTP error occurred while trying to send crash report: %s" % e) except Exception as e: # We don't want any exception to cause problems Logger.logException("e", "An exception occurred while trying to send crash report") if not self.has_started: print("An exception occurred while trying to send crash report: %s" % e) os._exit(1)
def event(self, event): if event.type == Event.ViewActivateEvent: # FIX: on Max OS X, somehow QOpenGLContext.currentContext() can become None during View switching. # This can happen when you do the following steps: # 1. Start Cura # 2. Load a model # 3. Switch to Custom mode # 4. Select the model and click on the per-object tool icon # 5. Switch view to Layer view or X-Ray # 6. Cura will very likely crash # It seems to be a timing issue that the currentContext can somehow be empty, but I have no clue why. # This fix tries to reschedule the view changing event call on the Qt thread again if the current OpenGL # context is None. if Platform.isOSX(): if QOpenGLContext.currentContext() is None: Logger.log( "d", "current context of OpenGL is empty on Mac OS X, will try to create shaders later" ) CuraApplication.getInstance().callLater( lambda e=event: self.event(e)) return if not self._xray_pass: # Currently the RenderPass constructor requires a size > 0 # This should be fixed in RenderPass's constructor. self._xray_pass = XRayPass.XRayPass(1, 1) self.getRenderer().addRenderPass(self._xray_pass) if not self._xray_composite_shader: self._xray_composite_shader = OpenGL.getInstance( ).createShaderProgram( Resources.getPath(Resources.Shaders, "xray_composite.shader")) theme = Application.getInstance().getTheme() self._xray_composite_shader.setUniformValue( "u_background_color", Color(*theme.getColor("viewport_background").getRgb())) self._xray_composite_shader.setUniformValue( "u_outline_color", Color(*theme.getColor("model_selection_outline").getRgb())) if not self._composite_pass: self._composite_pass = self.getRenderer().getRenderPass( "composite") self._old_layer_bindings = self._composite_pass.getLayerBindings() self._composite_pass.setLayerBindings( ["default", "selection", "xray"]) self._old_composite_shader = self._composite_pass.getCompositeShader( ) self._composite_pass.setCompositeShader( self._xray_composite_shader) if event.type == Event.ViewDeactivateEvent: self.getRenderer().removeRenderPass(self._xray_pass) self._composite_pass.setLayerBindings(self._old_layer_bindings) self._composite_pass.setCompositeShader(self._old_composite_shader)
def _updateContainerNameFilters(self) -> None: self._container_name_filters = {} for plugin_id, container_type in self._container_registry.getContainerTypes(): # Ignore default container types since those are not plugins if container_type in (InstanceContainer, ContainerStack, DefinitionContainer): continue serialize_type = "" try: plugin_metadata = self._plugin_registry.getMetaData(plugin_id) if plugin_metadata: serialize_type = plugin_metadata["settings_container"]["type"] else: continue except KeyError as e: continue mime_type = self._container_registry.getMimeTypeForContainer(container_type) if mime_type is None: continue entry = { "type": serialize_type, "mime": mime_type, "container": container_type } suffix = mime_type.preferredSuffix if Platform.isOSX() and "." in suffix: # OSX's File dialog is stupid and does not allow selecting files with a . in its name suffix = suffix[suffix.index(".") + 1:] suffix_list = "*." + suffix for suffix in mime_type.suffixes: if suffix == mime_type.preferredSuffix: continue if Platform.isOSX() and "." in suffix: # OSX's File dialog is stupid and does not allow selecting files with a . in its name suffix = suffix[suffix.index("."):] suffix_list += ", *." + suffix name_filter = "{0} ({1})".format(mime_type.comment, suffix_list) self._container_name_filters[name_filter] = entry
def exportContainer(self, container_id: str, file_type: str, file_url_or_string: Union[QUrl, str]) -> Dict[str, str]: if not container_id or not file_type or not file_url_or_string: return {"status": "error", "message": "Invalid arguments"} if isinstance(file_url_or_string, QUrl): file_url = file_url_or_string.toLocalFile() else: file_url = file_url_or_string if not file_url: return {"status": "error", "message": "Invalid path"} if file_type not in self._container_name_filters: try: mime_type = MimeTypeDatabase.getMimeTypeForFile(file_url) except MimeTypeNotFoundError: return {"status": "error", "message": "Unknown File Type"} else: mime_type = self._container_name_filters[file_type]["mime"] containers = cura.CuraApplication.CuraApplication.getInstance().getContainerRegistry().findContainers(id = container_id) if not containers: return {"status": "error", "message": "Container not found"} container = containers[0] if Platform.isOSX() and "." in file_url: file_url = file_url[:file_url.rfind(".")] for suffix in mime_type.suffixes: if file_url.endswith(suffix): break else: file_url += "." + mime_type.preferredSuffix if not Platform.isWindows(): if os.path.exists(file_url): 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_url)) if result == QMessageBox.No: return {"status": "cancelled", "message": "User cancelled"} try: contents = container.serialize() except NotImplementedError: return {"status": "error", "message": "Unable to serialize container"} if contents is None: return {"status": "error", "message": "Serialization returned None. Unable to write to file"} try: with SaveFile(file_url, "w") as f: f.write(contents) except OSError: return {"status": "error", "message": "Unable to write to this location.", "path": file_url} return {"status": "success", "message": "Successfully exported container", "path": file_url}
def getMetaData(): file_extension = "gz" if Platform.isOSX() else "gcode.gz" return { "mesh_reader": [ { "extension": file_extension, "description": i18n_catalog.i18nc("@item:inlistbox", "Compressed G-code File") } ] }
def getMetaData(): file_extension = "gz" if Platform.isOSX() else "gcode.gz" return { "mesh_reader": [{ "extension": file_extension, "description": i18n_catalog.i18nc("@item:inlistbox", "Compressed G-code File") }] }
def get_cura_dir_path(): if Platform.isWindows(): appdata_path = os.getenv("APPDATA") if not appdata_path: #Defensive against the environment variable missing (should never happen). appdata_path = "." return os.path.join(appdata_path, CuraAppName) elif Platform.isLinux(): return os.path.expanduser("~/.local/share/" + CuraAppName) elif Platform.isOSX(): return os.path.expanduser("~/Library/Logs/" + CuraAppName)
def exportContainer(self, container_id: str, file_type: str, file_url_or_string: Union[QUrl, str]) -> Dict[str, str]: if not container_id or not file_type or not file_url_or_string: return { "status": "error", "message": "Invalid arguments"} if isinstance(file_url_or_string, QUrl): file_url = file_url_or_string.toLocalFile() else: file_url = file_url_or_string if not file_url: return { "status": "error", "message": "Invalid path"} mime_type = None if not file_type in self._container_name_filters: try: mime_type = MimeTypeDatabase.getMimeTypeForFile(file_url) except MimeTypeNotFoundError: return { "status": "error", "message": "Unknown File Type" } else: mime_type = self._container_name_filters[file_type]["mime"] containers = self._container_registry.findContainers(None, id = container_id) if not containers: return { "status": "error", "message": "Container not found"} container = containers[0] if Platform.isOSX() and "." in file_url: file_url = file_url[:file_url.rfind(".")] for suffix in mime_type.suffixes: if file_url.endswith(suffix): break else: file_url += "." + mime_type.preferredSuffix if not Platform.isWindows(): if os.path.exists(file_url): 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_url)) if result == QMessageBox.No: return { "status": "cancelled", "message": "User cancelled"} try: contents = container.serialize() except NotImplementedError: return { "status": "error", "message": "Unable to serialize container"} if contents is None: return {"status": "error", "message": "Serialization returned None. Unable to write to file"} with SaveFile(file_url, "w") as f: f.write(contents) return { "status": "success", "message": "Succesfully exported container", "path": file_url}
def _getPossibleConfigStorageRootPathList(cls): # Returns all possible root paths for storing app configurations (in old and new versions) config_root_list = [Resources._getConfigStorageRootPath()] if Platform.isWindows(): # it used to be in LOCALAPPDATA on Windows config_root_list.append(os.getenv("LOCALAPPDATA")) elif Platform.isOSX(): config_root_list.append(os.path.expanduser("~")) config_root_list = [os.path.join(n, cls.ApplicationIdentifier) for n in config_root_list] return config_root_list
def __init__(self): super().__init__() self._application = Application.getInstance() self._i18n_catalog = None settings_definition_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "arcwelder_settings.def.json") try: with open(settings_definition_path, "r", encoding="utf-8") as f: self._settings_dict = json.load(f, object_pairs_hook=OrderedDict) except: Logger.logException( "e", "Could not load arc welder settings definition") return if Platform.isWindows(): arcwelder_executable = "bin/win64/ArcWelder.exe" elif Platform.isLinux(): arcwelder_executable = "bin/linux/ArcWelder" elif Platform.isOSX(): arcwelder_executable = "bin/osx/ArcWelder" self._arcwelder_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), arcwelder_executable) try: os.chmod( self._arcwelder_path, stat.S_IXUSR | stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IWUSR) # Make sure we have the rights to run this. except: Logger.logException("e", "Could modify rights of ArcWelder executable") return version_output = subprocess.check_output( [self._arcwelder_path, "--version"]).decode(locale.getpreferredencoding()) match = re.search("version: (.*)", version_output) if match: Logger.log("d", "Using ArcWelder %s" % match.group(1)) else: Logger.log("w", "Could not determine ArcWelder version") self._application.getPreferences().addPreference( "arcwelderplugin/settings_made_visible", False) ContainerRegistry.getInstance().containerLoadComplete.connect( self._onContainerLoadComplete) self._application.getOutputDeviceManager().writeStarted.connect( self._filterGcode)
def getMetaData(): file_extension = "gz" if Platform.isOSX() else "gcode.gz" return { "mesh_writer": { "output": [{ "extension": file_extension, "description": catalog.i18nc("@item:inlistbox", "Compressed G-code File"), "mime_type": "application/gzip", "mode": GCodeGzWriter.GCodeGzWriter.OutputMode.BinaryMode }] } }
def register(app): if Platform.isWindows(): from . import WindowsRemovableDrivePlugin return { "output_device": WindowsRemovableDrivePlugin.WindowsRemovableDrivePlugin() } elif Platform.isOSX(): from . import OSXRemovableDrivePlugin return { "output_device": OSXRemovableDrivePlugin.OSXRemovableDrivePlugin() } elif Platform.isLinux(): from . import LinuxRemovableDrivePlugin return { "output_device": LinuxRemovableDrivePlugin.LinuxRemovableDrivePlugin() } else: Logger.log("e", "Unsupported system, thus no removable device hotplugging support available.") return { }
def getMetaData(): # Workarround for osx not supporting double file extensions correctly. if Platform.isOSX(): workspace_extension = "3mf" else: workspace_extension = "curaproject.3mf" metaData = { "plugin": { "name": i18n_catalog.i18nc("@label", "3MF Writer"), "author": "Ultimaker", "version": "1.0", "description": i18n_catalog.i18nc("@info:whatsthis", "Provides support for writing 3MF files."), "api": 3 } } if "3MFWriter.ThreeMFWriter" in sys.modules: metaData["mesh_writer"] = { "output": [{ "extension": "3mf", "description": i18n_catalog.i18nc("@item:inlistbox", "3MF file"), "mime_type": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml", "mode": ThreeMFWriter.ThreeMFWriter.OutputMode.BinaryMode }] } metaData["workspace_writer"] = { "output": [{ "extension": workspace_extension, "description": i18n_catalog.i18nc("@item:inlistbox", "Cura Project 3MF file"), "mime_type": "application/x-curaproject+xml", "mode": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter.OutputMode. BinaryMode }] } return metaData
def _getCacheStorageRootPath(cls) -> Optional[str]: # Returns the path where we store different versions of app configurations cache_path = None if Platform.isWindows(): cache_path = os.getenv("LOCALAPPDATA") elif Platform.isOSX(): cache_path = None elif Platform.isLinux(): try: cache_path = os.environ["XDG_CACHE_HOME"] except KeyError: cache_path = os.path.expanduser("~/.cache") return cache_path
def _getCacheStorageRootPath(cls): # Returns the path where we store different versions of app configurations cache_path = None if Platform.isWindows(): cache_path = os.getenv("LOCALAPPDATA") elif Platform.isOSX(): cache_path = None elif Platform.isLinux(): try: cache_path = os.environ["XDG_CACHE_HOME"] except KeyError: cache_path = os.path.expanduser("~/.cache") return cache_path
def _getConfigStorageRootPath(cls): # Returns the path where we store different versions of app configurations config_path = None if Platform.isWindows(): config_path = os.getenv("APPDATA") elif Platform.isOSX(): config_path = os.path.expanduser("~/Library/Application Support") elif Platform.isLinux(): try: config_path = os.environ["XDG_CONFIG_HOME"] except KeyError: config_path = os.path.expanduser("~/.config") else: config_path = "." return config_path
def _openFileDialog(self): """The user can set the path to blender manually. Gets called when blender isn't found in the expected place.""" global verified_blender_path message = Message(text=catalog.i18nc( '@info', 'Set your blender path manually.'), title=catalog.i18nc('@info:title', 'Blender not found')) message.show() dialog = QFileDialog() dialog.setAcceptMode(QFileDialog.AcceptOpen) # Supports multi-platform if Platform.isWindows(): dialog.setDirectory('C:/Program Files') dialog.setNameFilters(["Blender (*.exe)"]) elif Platform.isOSX(): dialog.setDirectory('/Applications') elif Platform.isLinux(): dialog.setDirectory('/usr/bin') else: dialog.setDirectory('') dialog.setFileMode(QFileDialog.ExistingFile) dialog.setViewMode(QFileDialog.Detail) # Opens the file explorer and checks if file is selected. if dialog.exec_(): message.hide() # Gets the selected blender path from file explorer. Application.getInstance().getPreferences().setValue( 'cura_blender/blender_path', ''.join(dialog.selectedFiles())) verified_blender_path = False self.verifyBlenderPath(manual=True) message = Message(text=catalog.i18nc( '@info', Application.getInstance().getPreferences().getValue( 'cura_blender/blender_path')), title=catalog.i18nc('@info:title', 'New Blenderpath set')) message.show() else: message.hide() message = Message(text=catalog.i18nc( '@info', 'No blender path was selected.'), title=catalog.i18nc('@info:title', 'Blender not found')) message.show()
def _getConfigStorageRootPath(cls) -> str: # Returns the path where we store different versions of app configurations if Platform.isWindows(): config_path = os.getenv("APPDATA") if not config_path: # Protect if the getenv function returns None (it should never happen) config_path = "." elif Platform.isOSX(): config_path = os.path.expanduser("~/Library/Application Support") elif Platform.isLinux(): try: config_path = os.environ["XDG_CONFIG_HOME"] except KeyError: config_path = os.path.expanduser("~/.config") else: config_path = "." return config_path
def event(self, event): if event.type == Event.ViewActivateEvent: # FIX: on Max OS X, somehow QOpenGLContext.currentContext() can become None during View switching. # This can happen when you do the following steps: # 1. Start Cura # 2. Load a model # 3. Switch to Custom mode # 4. Select the model and click on the per-object tool icon # 5. Switch view to Layer view or X-Ray # 6. Cura will very likely crash # It seems to be a timing issue that the currentContext can somehow be empty, but I have no clue why. # This fix tries to reschedule the view changing event call on the Qt thread again if the current OpenGL # context is None. if Platform.isOSX(): if QOpenGLContext.currentContext() is None: Logger.log("d", "current context of OpenGL is empty on Mac OS X, will try to create shaders later") CuraApplication.getInstance().callLater(lambda e = event: self.event(e)) return if not self._xray_pass: # Currently the RenderPass constructor requires a size > 0 # This should be fixed in RenderPass's constructor. self._xray_pass = XRayPass.XRayPass(1, 1) self.getRenderer().addRenderPass(self._xray_pass) if not self._xray_composite_shader: self._xray_composite_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("XRayView"), "xray_composite.shader")) theme = Application.getInstance().getTheme() self._xray_composite_shader.setUniformValue("u_background_color", Color(*theme.getColor("viewport_background").getRgb())) self._xray_composite_shader.setUniformValue("u_error_color", Color(*theme.getColor("xray_error").getRgb())) self._xray_composite_shader.setUniformValue("u_outline_color", Color(*theme.getColor("model_selection_outline").getRgb())) if not self._composite_pass: self._composite_pass = self.getRenderer().getRenderPass("composite") self._old_layer_bindings = self._composite_pass.getLayerBindings() self._composite_pass.setLayerBindings(["default", "selection", "xray"]) self._old_composite_shader = self._composite_pass.getCompositeShader() self._composite_pass.setCompositeShader(self._xray_composite_shader) if event.type == Event.ViewDeactivateEvent: self.getRenderer().removeRenderPass(self._xray_pass) self._composite_pass.setLayerBindings(self._old_layer_bindings) self._composite_pass.setCompositeShader(self._old_composite_shader)
def run(self): if not self.url or not self.data: Logger.log("e", "URL or DATA for sending slice info was not set!") return # Submit data kwoptions = {"data" : self.data, "timeout" : 5 } if Platform.isOSX(): kwoptions["context"] = ssl._create_unverified_context() try: f = urllib.request.urlopen(self.url, **kwoptions) Logger.log("i", "Sent anonymous slice info to %s", self.url) f.close() except urllib.error.HTTPError as http_exception: Logger.log("e", "An HTTP error occurred while trying to send slice information: %s" % http_exception) except Exception as e: # We don't want any exception to cause problems Logger.log("e", "An exception occurred while trying to send slice information: %s" % e)
def __compress_gcode(self): exePath = None if Platform.isWindows(): exePath = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'VC_compress_gcode.exe') elif Platform.isOSX(): exePath = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'VC_compress_gcode_MAC') else: self.__log("w", "Could not find gcode compression tool") if exePath is not None and os.path.exists(exePath): cmd = '"' + exePath + '"' + ' "' + self._localTempGcode + '" ' + self._config["x_mm_per_step"] + ' ' + self._config["y_mm_per_step"] + ' ' + self._config["z_mm_per_step"] + ' ' + \ self._config["e_mm_per_step"] + ' "' + os.path.dirname(self._localTempGcode) + '" ' \ + self._config["s_x_max"] + ' ' + self._config["s_y_max"] + ' ' + self._config["s_z_max"] + ' ' + self._config["s_machine_type"] self.__log("d", cmd) ret = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) self.__log("d", ret.stdout.read().decode('utf-8', 'ignore').rstrip()) if os.path.exists(self._localTempGcode + '.tz'): # check whether the compression succedded return True else: return False
def getMetaData() -> Dict: # Workarround for osx not supporting double file extensions correctly. if Platform.isOSX(): workspace_extension = "3mf" else: workspace_extension = "curaproject.3mf" metaData = {} if "3MFReader.ThreeMFReader" in sys.modules: metaData["mesh_reader"] = [ { "extension": "3mf", "description": catalog.i18nc("@item:inlistbox", "3MF File") } ] metaData["workspace_reader"] = [ { "extension": workspace_extension, "description": catalog.i18nc("@item:inlistbox", "3MF File") } ] return metaData
def getMetaData() -> Dict: # Workaround for osx not supporting double file extensions correctly. if Platform.isOSX(): workspace_extension = "3mf" else: workspace_extension = "curaproject.3mf" metaData = {} if "3MFReader.ThreeMFReader" in sys.modules: metaData["mesh_reader"] = [ { "extension": "3mf", "description": catalog.i18nc("@item:inlistbox", "3MF File") } ] metaData["workspace_reader"] = [ { "extension": workspace_extension, "description": catalog.i18nc("@item:inlistbox", "3MF File") } ] return metaData
def event(self, event): modifiers = QApplication.keyboardModifiers() ctrl_is_active = modifiers & Qt.ControlModifier shift_is_active = modifiers & Qt.ShiftModifier if event.type == Event.KeyPressEvent and ctrl_is_active: amount = 10 if shift_is_active else 1 if event.key == KeyEvent.UpKey: self.setLayer(self._current_layer_num + amount) return True if event.key == KeyEvent.DownKey: self.setLayer(self._current_layer_num - amount) return True if event.type == Event.ViewActivateEvent: # FIX: on Max OS X, somehow QOpenGLContext.currentContext() can become None during View switching. # This can happen when you do the following steps: # 1. Start Cura # 2. Load a model # 3. Switch to Custom mode # 4. Select the model and click on the per-object tool icon # 5. Switch view to Layer view or X-Ray # 6. Cura will very likely crash # It seems to be a timing issue that the currentContext can somehow be empty, but I have no clue why. # This fix tries to reschedule the view changing event call on the Qt thread again if the current OpenGL # context is None. if Platform.isOSX(): if QOpenGLContext.currentContext() is None: Logger.log("d", "current context of OpenGL is empty on Mac OS X, will try to create shaders later") CuraApplication.getInstance().callLater(lambda e=event: self.event(e)) return # Make sure the SimulationPass is created layer_pass = self.getSimulationPass() self.getRenderer().addRenderPass(layer_pass) # Make sure the NozzleNode is add to the root nozzle = self.getNozzleNode() nozzle.setParent(self.getController().getScene().getRoot()) nozzle.setVisible(False) Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) self._onGlobalStackChanged() if not self._simulationview_composite_shader: self._simulationview_composite_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("SimulationView"), "simulationview_composite.shader")) theme = Application.getInstance().getTheme() self._simulationview_composite_shader.setUniformValue("u_background_color", Color(*theme.getColor("viewport_background").getRgb())) self._simulationview_composite_shader.setUniformValue("u_outline_color", Color(*theme.getColor("model_selection_outline").getRgb())) if not self._composite_pass: self._composite_pass = self.getRenderer().getRenderPass("composite") self._old_layer_bindings = self._composite_pass.getLayerBindings()[:] # make a copy so we can restore to it later self._composite_pass.getLayerBindings().append("simulationview") self._old_composite_shader = self._composite_pass.getCompositeShader() self._composite_pass.setCompositeShader(self._simulationview_composite_shader) elif event.type == Event.ViewDeactivateEvent: self._wireprint_warning_message.hide() Application.getInstance().globalContainerStackChanged.disconnect(self._onGlobalStackChanged) if self._global_container_stack: self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged) self._nozzle_node.setParent(None) self.getRenderer().removeRenderPass(self._layer_pass) self._composite_pass.setLayerBindings(self._old_layer_bindings) self._composite_pass.setCompositeShader(self._old_composite_shader)
def _onWriteStarted(self, output_device): try: if not Preferences.getInstance().getValue("info/send_slice_info"): Logger.log("d", "'info/send_slice_info' is turned off.") return # Do nothing, user does not want to send data global_container_stack = Application.getInstance().getGlobalContainerStack() # Get total material used (in mm^3) print_information = Application.getInstance().getPrintInformation() material_radius = 0.5 * global_container_stack.getProperty("material_diameter", "value") # TODO: Send material per extruder instead of mashing it on a pile material_used = math.pi * material_radius * material_radius * sum(print_information.materialLengths) #Volume of all materials used # Get model information (bounding boxes, hashes and transformation matrix) models_info = [] for node in DepthFirstIterator(Application.getInstance().getController().getScene().getRoot()): if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None: if not getattr(node, "_outside_buildarea", False): model_info = {} model_info["hash"] = node.getMeshData().getHash() model_info["bounding_box"] = {} model_info["bounding_box"]["minimum"] = {} model_info["bounding_box"]["minimum"]["x"] = node.getBoundingBox().minimum.x model_info["bounding_box"]["minimum"]["y"] = node.getBoundingBox().minimum.y model_info["bounding_box"]["minimum"]["z"] = node.getBoundingBox().minimum.z model_info["bounding_box"]["maximum"] = {} model_info["bounding_box"]["maximum"]["x"] = node.getBoundingBox().maximum.x model_info["bounding_box"]["maximum"]["y"] = node.getBoundingBox().maximum.y model_info["bounding_box"]["maximum"]["z"] = node.getBoundingBox().maximum.z model_info["transformation"] = str(node.getWorldTransformation().getData()) models_info.append(model_info) # Bundle the collected data submitted_data = { "processor": platform.processor(), "machine": platform.machine(), "platform": platform.platform(), "settings": global_container_stack.serialize(), # global_container with references on used containers "version": Application.getInstance().getVersion(), "modelhash": "None", "printtime": print_information.currentPrintTime.getDisplayString(), "filament": material_used, "language": Preferences.getInstance().getValue("general/language"), } for container in global_container_stack.getContainers(): container_id = container.getId() try: container_serialized = container.serialize() except NotImplementedError: Logger.log("w", "Container %s could not be serialized!", container_id) continue if container_serialized: submitted_data["settings_%s" %(container_id)] = container_serialized # This can be anything, eg. INI, JSON, etc. else: Logger.log("i", "No data found in %s to be serialized!", container_id) # Convert data to bytes submitted_data = urllib.parse.urlencode(submitted_data) binary_data = submitted_data.encode("utf-8") # Submit data kwoptions = {"data" : binary_data, "timeout" : 1 } if Platform.isOSX(): kwoptions["context"] = ssl._create_unverified_context() try: f = urllib.request.urlopen(self.info_url, **kwoptions) Logger.log("i", "Sent anonymous slice info to %s", self.info_url) f.close() except Exception as e: Logger.logException("e", "An exception occurred while trying to send slice information") except: # We really can't afford to have a mistake here, as this would break the sending of g-code to a device # (Either saving or directly to a printer). The functionality of the slice data is not *that* important. pass