Esempio n. 1
0
def test_addGetDisplayComponent():
    stage = Stage()
    stage.addDisplayComponent("BLORP", "location")
    assert stage.getDisplayComponent("BLORP") == QUrl.fromLocalFile("location")

    stage.addDisplayComponent("MEEP!", QUrl.fromLocalFile("MEEP"))
    assert stage.getDisplayComponent("MEEP!") == QUrl.fromLocalFile("MEEP")
Esempio n. 2
0
    def createQmlComponent(self, qml_file_path: str, context_properties: Dict[str, "QObject"] = None) -> Optional["QObject"]:
        """Create a QML component from a qml file.
        :param qml_file_path:: The absolute file path to the root qml file.
        :param context_properties:: Optional dictionary containing the properties that will be set on the context of the
        qml instance before creation.
        :return: None in case the creation failed (qml error), else it returns the qml instance.
        :note If the creation fails, this function will ensure any errors are logged to the logging service.
        """

        if self._qml_engine is None: # Protect in case the engine was not initialized yet
            return None
        path = QUrl.fromLocalFile(qml_file_path)
        component = QQmlComponent(self._qml_engine, path)
        result_context = QQmlContext(self._qml_engine.rootContext()) #type: ignore #MyPy doens't realise that self._qml_engine can't be None here.
        if context_properties is not None:
            for name, value in context_properties.items():
                result_context.setContextProperty(name, value)
        result = component.create(result_context)
        for err in component.errors():
            Logger.log("e", str(err.toString()))
        if result is None:
            return None

        # We need to store the context with the qml object, else the context gets garbage collected and the qml objects
        # no longer function correctly/application crashes.
        result.attached_context = result_context
        return result
Esempio n. 3
0
    def test_activeToolPanel(self):
        # There is no active tool, so it should be empty
        assert self.proxy.activeToolPanel == QUrl()

        with patch.object(self.tool, "getMetaData",
                          MagicMock(return_value={"tool_panel": "derp"})):
            with patch("UM.PluginRegistry.PluginRegistry.getPluginPath",
                       MagicMock(return_value="OMG")):
                Application.getInstance().getController().setActiveTool(
                    self.tool)
                assert self.proxy.activeToolPanel == QUrl.fromLocalFile(
                    "OMG/derp")
        # Try again with empty metadata
        with patch("UM.PluginRegistry.PluginRegistry.getMetaData",
                   MagicMock(return_value={"tool": {}})):
            Application.getInstance().getController().setActiveTool("")
            Application.getInstance().getController().setActiveTool(self.tool)
            assert self.proxy.activeToolPanel == QUrl.fromLocalFile("")
Esempio n. 4
0
    def activeToolPanel(self):
        if not self._active_tool:
            return QUrl()
        try:
            panel_file = self._active_tool.getMetaData()["tool_panel"]
        except KeyError:
            return QUrl()

        return QUrl.fromLocalFile(
            os.path.join(
                PluginRegistry.getInstance().getPluginPath(
                    self._active_tool.getPluginId()), panel_file))
Esempio n. 5
0
    def addFileToRecentFiles(self, file_name: str) -> None:
        file_path = QUrl.fromLocalFile(file_name)

        if file_path in self._recent_files:
            self._recent_files.remove(file_path)

        self._recent_files.insert(0, file_path)
        if len(self._recent_files) > 10:
            del self._recent_files[10]

        pref = ""
        for path in self._recent_files:
            pref += path.toLocalFile() + ";"

        self.getPreferences().setValue("%s/recent_files" % self.getApplicationName(), pref)
        self.recentFilesChanged.emit()
    def _onEngineCreated(self) -> None:
        qmlRegisterType(
            MaterialSettingsPluginVisibilityHandler.
            MaterialSettingsPluginVisibilityHandler, "Cura", 1, 0,
            "MaterialSettingsVisibilityHandler")

        # Adding/removing pages from the preferences dialog is handles in QML
        # There is no way to access the preferences dialog directly, so we have to search for it
        preferencesDialog = None
        main_window = CuraApplication.getInstance().getMainWindow()
        if not main_window:
            Logger.log(
                "e",
                "Could not replace Materials preferencepane with patched version because there is no main window"
            )
            return
        for child in main_window.contentItem().children():
            try:
                test = child.setPage  # only PreferencesDialog has a setPage function
                preferencesDialog = child
                break
            except:
                pass

        if preferencesDialog:
            Logger.log(
                "d", "Replacing Materials preferencepane with patched version")

            qml_folder = "qml" if not USE_QT5 else "qml_qt5"
            materialPreferencesPage = QUrl.fromLocalFile(
                os.path.join(os.path.dirname(os.path.abspath(__file__)),
                             qml_folder, "MaterialsPage.qml"))
            if USE_QT5:
                materialPreferencesPage = materialPreferencesPage.toString()

            preferencesDialog.removePage(3)
            preferencesDialog.insertPage(
                3, catalog.i18nc("@title:tab", "Materials"),
                materialPreferencesPage)
        else:
            Logger.log(
                "e",
                "Could not replace Materials preferencepane with patched version"
            )
Esempio n. 7
0
    def openVideoFile(self):
        # self.mediaPlayer.setMedia(QMediaContent())
        if self.sender() == self.openVideoAction:
            self.videoFile, _ = QFileDialog.getOpenFileName(
                self, "Open video", QDir.homePath())
            # if self.videoFile != '':
            #     self.setWindowTitle('{} - {}'.format(os.path.basename(self.videoFile),
            #                                          os.path.basename(self.projectFile)))

        if self.videoFile != '':
            self.setWindowTitle('{} - {}'.format(
                os.path.basename(self.videoFile),
                os.path.basename(self.projectFile)))
            self.saveProjectAction.setEnabled(True)
            self.maskGenAction.setEnabled(True)
            # self.loadGraphAction.setEnabled(True)
            # self.saveGraphAction.setEnabled(True)
            # self.drawPointAction.setEnabled(True)
            # self.drawLineAction.setEnabled(True)
            # self.drawZoneAction.setEnabled(True)

            creation_datetime, width, height = getVideoMetadata(self.videoFile)
            self.videoStartDatetime = self.videoCurrentDatetime = creation_datetime
            self.dateLabel.setText(creation_datetime.strftime('%a, %b %d, %Y'))

            self.gView.setSceneRect(0, 0, width, height)

            self.videoItem = QGraphicsVideoItem()
            self.videoItem.setAspectRatioMode(
                Qt.AspectRatioMode.KeepAspectRatio)
            self.gScene.addItem(self.videoItem)
            self.videoItem.mouseMoveEvent = self.gView.mouseMoveEvent
            self.videoItem.setSize(QSizeF(width, height))

            self.mediaPlayer.setVideoOutput(self.videoItem)
            self.mediaPlayer.setSource(QUrl.fromLocalFile(self.videoFile))

            self.gView.labelSize = width / 50

            self.playButton.setEnabled(True)
            # self.gView.setViewport(QOpenGLWidget())
            self.mediaPlayer.pause()
Esempio n. 8
0
    loaded = pyqtSignal()
    error = pyqtSignal(str, arguments=["errorText"])

    metaDataChanged = pyqtSignal()
    @pyqtProperty("QVariantMap", notify=metaDataChanged)
    def metaData(self):
        return self._metadata

    @pyqtProperty(str, notify=loaded)
    def definitionId(self):
        return self._definition_id

signal.signal(signal.SIGINT, signal.SIG_DFL)

file_name = None
if len(sys.argv) > 1:
    file_name = sys.argv[1]
    del sys.argv[1]

app = QApplication(sys.argv)
engine = QQmlApplicationEngine()

qmlRegisterType(DefinitionLoader, "Example", 1, 0, "DefinitionLoader")
qmlRegisterType(DefinitionTreeModel.DefinitionTreeModel, "Example", 1, 0, "DefinitionTreeModel")

if file_name:
    engine.rootContext().setContextProperty("open_file", QUrl.fromLocalFile(file_name))

engine.load(os.path.join(os.path.dirname(os.path.abspath(__file__)), "main.qml"))
app.exec()
Esempio n. 9
0
def open_local_file(path):
    QDesktopServices.openUrl(QUrl.fromLocalFile(path))
Esempio n. 10
0
 def show_html(self, html, in_current_tab=True):
     if isinstance(html, bytes):
         html = html.decode('utf-8')
     tab = self.get_tab_for_load(in_current_tab=in_current_tab)
     tab.setHtml(html, QUrl.fromLocalFile(os.path.expanduser('~')))
Esempio n. 11
0
    def load(self, path: str, is_first_call: bool = True) -> None:
        if path == self._path:
            return

        theme_full_path = os.path.join(path, "theme.json")
        Logger.log(
            "d", "Loading theme file: {theme_full_path}".format(
                theme_full_path=theme_full_path))
        try:
            with open(theme_full_path, encoding="utf-8") as f:
                data = json.load(f)
        except EnvironmentError as e:
            Logger.error(
                "Unable to load theme file at {theme_full_path}: {err}".format(
                    theme_full_path=theme_full_path, err=e))
            return
        except UnicodeDecodeError:
            Logger.error(
                "Theme file at {theme_full_path} is corrupt (invalid UTF-8 bytes)."
                .format(theme_full_path=theme_full_path))
            return
        except json.JSONDecodeError:
            Logger.error(
                "Theme file at {theme_full_path} is corrupt (invalid JSON syntax)."
                .format(theme_full_path=theme_full_path))
            return

        # Iteratively load inherited themes
        try:
            theme_id = data["metadata"]["inherits"]
            self.load(Resources.getPath(Resources.Themes, theme_id),
                      is_first_call=False)
        except FileNotFoundError:
            Logger.log("e", "Could not find inherited theme %s", theme_id)
        except KeyError:
            pass  # No metadata or no inherits keyword in the theme.json file

        if "colors" in data:
            for name, value in data["colors"].items():

                if not is_first_call and isinstance(value, str):
                    # Keep parent theme string colors as strings and parse later
                    self._colors[name] = value
                    continue

                if isinstance(value, str) and is_first_call:
                    # value is reference to base_colors color name
                    try:
                        color = data["base_colors"][value]
                    except IndexError:
                        Logger.log(
                            "w",
                            "Colour {value} could not be found in base_colors".
                            format(value=value))
                        continue
                else:
                    color = value

                try:
                    c = QColor(color[0], color[1], color[2], color[3])
                except IndexError:  # Color doesn't have enough components.
                    Logger.log(
                        "w",
                        "Colour {name} doesn't have enough components. Need to have 4, but had {num_components}."
                        .format(name=name, num_components=len(color)))
                    continue  # Skip this one then.
                self._colors[name] = c

        if "base_colors" in data:
            for name, color in data["base_colors"].items():
                try:
                    c = QColor(color[0], color[1], color[2], color[3])
                except IndexError:  # Color doesn't have enough components.
                    Logger.log(
                        "w",
                        "Colour {name} doesn't have enough components. Need to have 4, but had {num_components}."
                        .format(name=name, num_components=len(color)))
                    continue  # Skip this one then.
                self._colors[name] = c

        if is_first_call and self._colors:
            #Convert all string value colors to their referenced color
            for name, color in self._colors.items():
                if isinstance(color, str):
                    try:
                        c = self._colors[color]
                        self._colors[name] = c
                    except:
                        Logger.log(
                            "w",
                            "Colour {name} {color} does".format(name=name,
                                                                color=color))

        fonts_dir = os.path.join(path, "fonts")
        if os.path.isdir(fonts_dir):
            for root, dirnames, filenames in os.walk(fonts_dir):
                for filename in filenames:
                    if filename.lower().endswith(".ttf"):
                        QFontDatabase.addApplicationFont(
                            os.path.join(root, filename))

        if "fonts" in data:
            system_font_size = QCoreApplication.instance().font().pointSize()
            for name, font in data["fonts"].items():
                q_font = QFont()
                q_font.setFamily(
                    font.get("family",
                             QCoreApplication.instance().font().family()))

                if font.get("bold"):
                    q_font.setBold(font.get("bold", False))
                else:
                    q_font.setWeight(font.get("weight", 500))

                q_font.setLetterSpacing(QFont.SpacingType.AbsoluteSpacing,
                                        font.get("letterSpacing", 0))
                q_font.setItalic(font.get("italic", False))
                q_font.setPointSize(int(
                    font.get("size", 1) * system_font_size))
                q_font.setCapitalization(QFont.Capitalization.AllUppercase
                                         if font.get("capitalize", False) else
                                         QFont.Capitalization.MixedCase)

                self._fonts[name] = q_font

        if "sizes" in data:
            for name, size in data["sizes"].items():
                s = QSizeF()
                s.setWidth(round(size[0] * self._em_width))
                s.setHeight(round(size[1] * self._em_height))

                self._sizes[name] = s

        iconsdir = os.path.join(path, "icons")
        if os.path.isdir(iconsdir):
            try:
                for base_path, _, icons in os.walk(iconsdir):
                    detail_level = base_path.split(os.sep)[-1]
                    if detail_level not in self._icons:
                        self._icons[detail_level] = {}
                    for icon in icons:
                        name = os.path.splitext(icon)[0]
                        self._icons[detail_level][name] = QUrl.fromLocalFile(
                            os.path.join(base_path, icon))
            except EnvironmentError as err:  # Exception when calling os.walk, e.g. no access rights.
                Logger.error(
                    f"Can't access icons of theme ({iconsdir}): {err}")
                # Won't get any icons then. Images will show as black squares.

            deprecated_icons_file = os.path.join(iconsdir,
                                                 "deprecated_icons.json")
            if os.path.isfile(deprecated_icons_file):
                try:
                    with open(deprecated_icons_file, encoding="utf-8") as f:
                        data = json.load(f)
                        for icon in data:
                            self._deprecated_icons[icon] = data[icon]
                except (UnicodeDecodeError, json.decoder.JSONDecodeError,
                        EnvironmentError):
                    Logger.logException(
                        "w", "Could not parse deprecated icons list %s",
                        deprecated_icons_file)

        imagesdir = os.path.join(path, "images")
        if os.path.isdir(imagesdir):
            try:
                for image in os.listdir(imagesdir):
                    name = os.path.splitext(image)[0]
                    self._images[name] = QUrl.fromLocalFile(
                        os.path.join(imagesdir, image))
            except EnvironmentError as err:  # Exception when calling os.listdir, e.g. no access rights.
                Logger.error(
                    f"Can't access image of theme ({imagesdir}): {err}")
                # Won't get any images then. They will show as black squares.

        Logger.log("d", "Loaded theme %s", path)
        Logger.info(f"System's em size is {self._em_height}px.")
        self._path = path

        # only emit the theme loaded signal once after all the themes in the inheritance chain have been loaded
        if is_first_call:
            self.themeLoaded.emit()
Esempio n. 12
0
def test_knownImage(theme):
    image_location = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                  "test_theme", "images", "kitten.jpg")
    assert theme.getImage("kitten") == QUrl.fromLocalFile(image_location)
Esempio n. 13
0
def test_getKnownIcon(theme):
    icon_location = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                 "test_theme", "icons", "test.svg")
    assert theme.getIcon("test") == QUrl.fromLocalFile(icon_location)
Esempio n. 14
0
 def getDefaultPath(self) -> QUrl:
     return QUrl.fromLocalFile(os.path.expanduser("~/"))
	def _getArticle(self, article_id, language="en_US") -> List[List[str]]:
		"""
		Gets the rich text of a specified article.

		This function lazily loads an article from a file. If it's never been
		loaded before the article gets parsed and stored. Otherwise it'll get
		taken from the cache.
		:param article_id: The ID of the article to get.
		:param language: The language to get the article in.
		:return: A list of article "parts". Each article part is a list, where
		the first element indicates the type of part and the rest contains the
		content. Possible types of parts are "rich_text", "images" or
		"checkbox".
		"""
		if article_id in self.articles and language in self.articles[article_id]:
			return self.articles[article_id][language]

		images_path = os.path.join(os.path.dirname(__file__), "resources", "articles", "images")
		try:
			if language not in self.article_locations[article_id]:
				language = "en_US"  # Fall back to English if the preferred language is not available.
			markdown_file = self.article_locations[article_id][language]
			with open(markdown_file, encoding="utf-8") as f:
				markdown_str = f.read()
			images_path = os.path.dirname(markdown_file)
		except (OSError, KeyError):  # File doesn't exist or is otherwise not readable.
			if self.definition_container and article_id in self.definition_container.getAllKeys():
				markdown_str = self.definition_container.getProperty(article_id, "label") + "\n====\n"
				markdown_str += "*" + self.definition_container.getProperty(article_id, "description") + "*"  # Use the setting description as fallback.
			else:
				markdown_str = "There is no article on this topic."

		# Store this unparsed for later.
		if language not in self.articles_source:
			self.articles_source[language] = {}
		self.articles_source[language][article_id] = markdown_str

		if images_path not in self._markdown_per_folder:
			renderer = QtMarkdownRenderer.QtMarkdownRenderer(images_path)
			self._markdown_per_folder[images_path] = mistune.Markdown(renderer=renderer)  # Renders the Markdown articles into the subset of HTML supported by Qt.

		# Pre-process so that comments and conditionals don't influence the business.
		markdown_str = QtMarkdownRenderer.QtMarkdownRenderer.preprocess_conditionals(markdown_str)
		markdown_str = QtMarkdownRenderer.QtMarkdownRenderer.preprocess_comments(markdown_str)

		find_images = re.compile(r"!\[(.*)\]\(([^\)]+)\)")
		find_checkboxes = re.compile(r"\[ \]\s*([^\n]+)")
		image_description = None
		parts = []  # type: List[List[str]]  # List of items in the article. Each item starts with a type ID, and then a variable number of data items.
		for index, part_between_images in enumerate(find_images.split(markdown_str)):
			# The parts of the regex split alternate between text, image description and image URL.
			if index % 3 == 0:
				part_between_images = part_between_images.strip()
				if part_between_images or index == 0:
					parts_between_checkboxes = find_checkboxes.split(part_between_images)
					for index2, part_between_checkboxes in enumerate(parts_between_checkboxes):
						part_between_checkboxes = part_between_checkboxes.strip()
						# The parts of the regex split alternate between text and checkbox description.
						if index2 % 2 == 0:
							if part_between_checkboxes:
								rich_text = self._markdown_per_folder[images_path](part_between_checkboxes)
								parts.append(["rich_text", rich_text])
						else:  # if index2 == 1:
							preference_key = "settings_guide/" + urllib.parse.quote_plus(part_between_checkboxes).lower()
							parts.append(["checkbox", preference_key, part_between_checkboxes])
			elif index % 3 == 1:
				image_description = mistune.markdown(part_between_images)
			else:  # if index % 3 == 2:
				if image_description is not None:
					if parts[-1][0] != "images":  # List of images.
						parts.append(["images"])
					image_url = os.path.join(images_path, part_between_images)
					parts[-1].append(QUrl.fromLocalFile(image_url).toString() + "|" + image_description)
					image_description = None

		if article_id not in self.articles:
			self.articles[article_id] = {}
		self.articles[article_id][language] = parts
		if article_id not in self.articles_rich_text:
			self.articles_rich_text[article_id] = {}
		self.articles_rich_text[article_id][language] = self._markdown_per_folder[images_path](markdown_str)

		return self.articles[article_id][language]
Esempio n. 16
0
    def addDisplayComponent(self, name: str, source: Union[str, QUrl]) -> None:
        """Add a QML component to the stage"""

        if type(source) == str:
            source = QUrl.fromLocalFile(source)
        self._components[name] = source
Esempio n. 17
0
 def getImageSourceAsQUrl(image_source: Union[QUrl, str]) -> QUrl:
     if type(image_source) is str:
         return QUrl.fromLocalFile(image_source)
     elif type(image_source) is QUrl:
         return image_source
     return QUrl.fromLocalFile("")
Esempio n. 18
0
 def addDisplayComponent(self, name: str, source: Union[str, QUrl]) -> None:
     """Add a QML component that is provided by this View."""
     if type(source) == str:
         source = QUrl.fromLocalFile(source)
     self._components[name] = source
Esempio n. 19
0
def openHtmlPage(page_name, html_contents):
    target = os.path.join(tempfile.gettempdir(), page_name)
    with open(target, 'w', encoding='utf-8') as fhandle:
        fhandle.write(html_contents)
    QDesktopServices.openUrl(QUrl.fromLocalFile(target))
Esempio n. 20
0
 def _onMessageActionTriggered(self, message, action):
     if action == "open_folder" and hasattr(message, "_folder"):
         QDesktopServices.openUrl(QUrl.fromLocalFile(message._folder))
Esempio n. 21
0
    def startSplashWindowPhase(self) -> None:
        super().startSplashWindowPhase()
        i18n_catalog = i18nCatalog("uranium")
        self.showSplashMessage(i18n_catalog.i18nc("@info:progress", "Initializing package manager..."))
        self._package_manager.initialize()

        signal.signal(signal.SIGINT, signal.SIG_DFL)
        # This is done here as a lot of plugins require a correct gl context. If you want to change the framework,
        # these checks need to be done in your <framework>Application.py class __init__().

        self._configuration_error_message = ConfigurationErrorMessage(self,
              i18n_catalog.i18nc("@info:status", "Your configuration seems to be corrupt."),
              lifetime = 0,
              title = i18n_catalog.i18nc("@info:title", "Configuration errors")
              )
        # Remove, install, and then loading plugins
        self.showSplashMessage(i18n_catalog.i18nc("@info:progress", "Loading plugins..."))
        # Remove and install the plugins that have been scheduled
        self._plugin_registry.initializeBeforePluginsAreLoaded()
        self._plugin_registry.pluginLoadStarted.connect(self._displayLoadingPluginSplashMessage)
        self._loadPlugins()
        self._plugin_registry.pluginLoadStarted.disconnect(self._displayLoadingPluginSplashMessage)
        self._plugin_registry.checkRequiredPlugins(self.getRequiredPlugins())
        self.pluginsLoaded.emit()

        self.showSplashMessage(i18n_catalog.i18nc("@info:progress", "Updating configuration..."))
        with self._container_registry.lockFile():
            VersionUpgradeManager.getInstance().upgrade()

        # Load preferences again because before we have loaded the plugins, we don't have the upgrade routine for
        # the preferences file. Now that we have, load the preferences file again so it can be upgraded and loaded.
        self.showSplashMessage(i18n_catalog.i18nc("@info:progress", "Loading preferences..."))
        try:
            preferences_filename = Resources.getPath(Resources.Preferences, self._app_name + ".cfg")
            with open(preferences_filename, "r", encoding = "utf-8") as f:
                serialized = f.read()
            # This performs the upgrade for Preferences
            self._preferences.deserialize(serialized)
            self._preferences.setValue("general/plugins_to_remove", "")
            self._preferences.writeToFile(preferences_filename)
        except (EnvironmentError, UnicodeDecodeError):
            Logger.log("i", "The preferences file cannot be opened or it is corrupted, so we will use default values")

        self.processEvents()
        # Force the configuration file to be written again since the list of plugins to remove maybe changed
        try:
            self.readPreferencesFromConfiguration()
        except FileNotFoundError:
            Logger.log("i", "The preferences file '%s' cannot be found, will use default values",
                       self._preferences_filename)
            self._preferences_filename = Resources.getStoragePath(Resources.Preferences, self._app_name + ".cfg")
        Logger.info("Completed loading preferences.")

        # FIXME: This is done here because we now use "plugins.json" to manage plugins instead of the Preferences file,
        # but the PluginRegistry will still import data from the Preferences files if present, such as disabled plugins,
        # so we need to reset those values AFTER the Preferences file is loaded.
        self._plugin_registry.initializeAfterPluginsAreLoaded()

        # Check if we have just updated from an older version
        self._preferences.addPreference("general/last_run_version", "")
        last_run_version_str = self._preferences.getValue("general/last_run_version")
        if not last_run_version_str:
            last_run_version_str = self._version
        last_run_version = Version(last_run_version_str)
        current_version = Version(self._version)
        if last_run_version < current_version:
            self._just_updated_from_old_version = True
        self._preferences.setValue("general/last_run_version", str(current_version))
        self._preferences.writeToFile(self._preferences_filename)

        # Preferences: recent files
        self._preferences.addPreference("%s/recent_files" % self._app_name, "")
        file_names = self._preferences.getValue("%s/recent_files" % self._app_name).split(";")
        for file_name in file_names:
            if not os.path.isfile(file_name):
                continue
            self._recent_files.append(QUrl.fromLocalFile(file_name))

        if not self.getIsHeadLess():
            # Initialize System tray icon and make it invisible because it is used only to show pop up messages
            self._tray_icon = None
            if self._tray_icon_name:
                try:
                    self._tray_icon = QIcon(Resources.getPath(Resources.Images, self._tray_icon_name))
                    self._tray_icon_widget = QSystemTrayIcon(self._tray_icon)
                    self._tray_icon_widget.setVisible(False)
                    Logger.info("Created system tray icon.")
                except FileNotFoundError:
                    Logger.log("w", "Could not find the icon %s", self._tray_icon_name)