Esempio n. 1
0
def test_getFail404() -> None:
    app = QCoreApplication([])
    http_request_manager = HttpRequestManager.getInstance()

    cbo = mock.Mock()

    def callback(*args, **kwargs):
        cbo.callback(*args, **kwargs)
        # quit now so we don't need to wait
        http_request_manager.callLater(0, app.quit)

    def error_callback(*args, **kwargs):
        cbo.error_callback(*args, **kwargs)
        # quit now so we don't need to wait
        http_request_manager.callLater(0, app.quit)

    request_data = http_request_manager.get(
        url="http://localhost:8080/do_not_exist",
        callback=callback,
        error_callback=error_callback)
    # Make sure that if something goes wrong, we quit after 10 seconds
    http_request_manager.callLater(10.0, app.quit)

    app.exec()
    http_request_manager.cleanup()  # Remove all unscheduled events

    cbo.error_callback.assert_called_once_with(
        request_data.reply, QNetworkReply.NetworkError.ContentNotFoundError)
    cbo.callback.assert_not_called()
Esempio n. 2
0
    def cleanup(self) -> None:
        for event in list(self._delayed_events.keys()):
            self._cleanupDelayedCallEvent(event)
        self._delayed_events.clear()

        # Removes all events that have been posted to the QApplication.
        QCoreApplication.instance().removePostedEvents(None, self._event_type)
Esempio n. 3
0
    def __init__(self, engine, parent=None) -> None:
        super().__init__(parent)

        self._engine = engine
        self._path = ""
        self._icons = {}  # type: Dict[str, Dict[str, QUrl]]
        self._deprecated_icons = {}  # type: Dict[str, Dict[str, str]]
        self._images = {}  # type: Dict[str, QUrl]

        # Workaround for incorrect default font on Windows
        if sys.platform == "win32":
            default_font = QFont()
            default_font.setPointSize(9)
            QCoreApplication.instance().setFont(default_font)

        self._em_height = int(
            QFontMetrics(QCoreApplication.instance().font()).ascent())
        self._em_width = self._em_height

        # Cache the initial language in the preferences. For fonts, a special font can be defined with, for example,
        # "medium" and "medium_nl_NL". If the special one exists, getFont() will return that, otherwise the default
        # will be returned. We cache the initial language here is because Cura can only change its language if it gets
        # restarted, so we need to keep the fonts consistent in a single Cura run.
        self._preferences = UM.Application.Application.getInstance(
        ).getPreferences()
        self._lang_code = self._preferences.getValue("general/language")

        self._initializeDefaults()

        self._check_if_trusted = False
        self.reload()
Esempio n. 4
0
def test_getBasicAuthSuccess() -> None:
    app = QCoreApplication([])
    http_request_manager = HttpRequestManager.getInstance()

    cbo = mock.Mock()

    def callback(*args, **kwargs):
        cbo.callback(*args, **kwargs)
        # quit now so we don't need to wait
        http_request_manager.callLater(0, app.quit)

    def error_callback(*args, **kwargs):
        cbo.callback(*args, **kwargs)
        # quit now so we don't need to wait
        http_request_manager.callLater(0, app.quit)

    request_data = http_request_manager.get(
        url="http://localhost:8080/auth",
        headers_dict={"Authorization": "Basic dXNlcjp1c2Vy"},
        callback=callback,
        error_callback=error_callback)
    # Make sure that if something goes wrong, we quit after 10 seconds
    http_request_manager.callLater(10.0, app.quit)

    app.exec()
    http_request_manager.cleanup()  # Remove all unscheduled events

    cbo.callback.assert_called_once_with(request_data.reply)
    cbo.error_callback.assert_not_called()
Esempio n. 5
0
    def execute(self, data):
        Logger.log("d", "[Woodgrain Effect] Begin processing")

        # Show the progress bar
        self.progress_bar = Message(title="Apply Woodgrain Effect", text="This may take several minutes, please be patient.\n\n",
                                    lifetime=0, dismissable=False, progress=-1)
        self.progress_bar.show()

        # Start the processing thread
        self._locks = {}
        self._locks["metadata"] = threading.Lock()
        self._locks["output"] = threading.Lock()

        self.progress = (-1,0)
        self.output_gcode=[]

        self.apply_woodgrain_thread = threading.Thread(target=self.apply_woodgrain, args=(data,))
        self.apply_woodgrain_thread.start()

        # Keep the GUI responsive while we wait, even though this script blocks the UI thread
        GUI_UPDATE_FREQUENCY = 50           # as used in cura source
        PROGRESS_CHECK_INTERVAL = 1000      # milliseconds

        update_period = 1 / GUI_UPDATE_FREQUENCY
        updates_per_check = int(GUI_UPDATE_FREQUENCY * (PROGRESS_CHECK_INTERVAL / 1000))
        
        # Wait until the processing thread is done
        while True:
            for i in range(0, updates_per_check):
                QCoreApplication.processEvents()  # Ensure that the GUI does not freeze.
                sleep(update_period)
            
            # Grab an update on the progress
            self._locks["metadata"].acquire()
            progress = self.progress
            self._locks["metadata"].release()

            # Update progress bar
            self.progress_bar.setProgress((progress[0] / progress[1]) * 100)    # float(100) means complete

            # Check if Cura is still open.. 
            # If it's not, this loop will just run forever
            main_window = QtApplication.getInstance().getMainWindow()  
            if main_window is None:
                return None     #close out the loop

            #Check if we're done
            if progress[0] >= progress[1]:
                self.apply_woodgrain_thread.join()
                break

        # Wrap things up and pass the modified gcode back to cura
        Logger.log("d", "[Woodgrain Effect] End processing. " + str(progress[1]) + " iterations performed")
        self.progress_bar.hide()
        return self.output_gcode
Esempio n. 6
0
    def loadPlugins(self, metadata: Optional[Dict[str, Any]] = None) -> None:
        """Load all plugins matching a certain set of metadata

        :param metadata: The meta data that needs to be matched.
        NOTE: This is the method which kicks everything off at app launch.
        """

        start_time = time.time()

        # First load all of the pre-loaded plug-ins.
        for preloaded_plugin in self.preloaded_plugins:
            self.loadPlugin(preloaded_plugin)

        # Get a list of all installed plugins:
        plugin_ids = self._findInstalledPlugins()
        for plugin_id in plugin_ids:
            if plugin_id in self.preloaded_plugins:
                continue  # Already loaded this before.

            self.pluginLoadStarted.emit(plugin_id)

            # Get the plugin metadata:
            try:
                plugin_metadata = self.getMetaData(plugin_id)
            except TrustException:
                Logger.error(
                    "Plugin {} was not loaded because it could not be verified.",
                    plugin_id)
                message_text = i18n_catalog.i18nc(
                    "@error:untrusted",
                    "Plugin {} was not loaded because it could not be verified.",
                    plugin_id)
                Message(text=message_text,
                        message_type=Message.MessageType.ERROR).show()
                continue

            # Save all metadata to the metadata dictionary:
            self._metadata[plugin_id] = plugin_metadata
            if metadata is None or self._subsetInDict(
                    self._metadata[plugin_id], metadata):
                #
                try:
                    self.loadPlugin(plugin_id)
                    QCoreApplication.processEvents(
                    )  # Ensure that the GUI does not freeze.
                    # Add the plugin to the list after actually load the plugin:
                    self._all_plugins.append(plugin_id)
                    self._plugins_installed.append(plugin_id)
                except PluginNotFoundError:
                    pass

        self.pluginLoadStarted.emit("")
        Logger.log("d", "Loading all plugins took %s seconds",
                   time.time() - start_time)
Esempio n. 7
0
    def _initializeDefaults(self) -> None:
        self._fonts = {
            "system": QCoreApplication.instance().font(),
            "fixed":
            QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont)
        }

        palette = QCoreApplication.instance().palette()
        self._colors = {
            "system_window": palette.window(),
            "system_text": palette.text()
        }

        self._sizes = {"line": QSizeF(self._em_width, self._em_height)}
Esempio n. 8
0
 def _hashFile(cls, file_path: str) -> str:
     """
     Returns a SHA-256 hash of the specified file.
     :param file_path: The path to a file to get the hash of.
     :return: A cryptographic hash of the specified file.
     """
     block_size = 2**16
     hasher = hashlib.sha256()
     with open(file_path, "rb") as f:
         contents = f.read(block_size)
         while len(contents) > 0:
             hasher.update(contents)
             contents = f.read(block_size)
     QCoreApplication.processEvents(
     )  # Process events to allow the interface to update
     return hasher.hexdigest()
Esempio n. 9
0
    def callLater(self, delay: float, callback: Callable, *args,
                  **kwargs) -> None:
        if delay < 0:
            raise ValueError(
                "delay must be a non-negative value, but got [%s] instead." %
                delay)

        delay_to_use = None if delay <= 0 else delay
        event = _CallFunctionEvent(self,
                                   callback,
                                   args,
                                   kwargs,
                                   delay=delay_to_use)
        if delay_to_use is None:
            QCoreApplication.instance().postEvent(self, event)
        else:
            self._scheduleDelayedCallEvent(event)
Esempio n. 10
0
def test_getSuccessful() -> None:
    app = QCoreApplication([])
    http_request_manager = HttpRequestManager.getInstance()

    cbo = mock.Mock()

    def callback(*args, **kwargs):
        cbo.callback(*args, **kwargs)
        # quit now so we don't need to wait
        http_request_manager.callLater(0, app.quit)

    request_data = http_request_manager.get(
        url="http://localhost:8080/success", callback=callback)
    # Make sure that if something goes wrong, we quit after 10 seconds
    http_request_manager.callLater(10.0, app.quit)

    app.exec()
    http_request_manager.cleanup()  # Remove all unscheduled events

    cbo.callback.assert_called_once_with(request_data.reply)
Esempio n. 11
0
 def _screenScaleFactor(self) -> float:
     # OSX handles sizes of dialogs behind our backs, but other platforms need
     # to know about the device pixel ratio
     if sys.platform == "darwin":
         return 1.0
     else:
         # determine a device pixel ratio from font metrics, using the same logic as UM.Theme
         fontPixelRatio = QFontMetrics(QCoreApplication.instance().font()).ascent() / 11
         # round the font pixel ratio to quarters
         fontPixelRatio = int(fontPixelRatio * 4) / 4
         return fontPixelRatio
Esempio n. 12
0
    def upgrade(self) -> bool:
        """Performs the version upgrades of all configuration files to the most
        recent version.

        The upgrade plug-ins must all be loaded at this point, or no upgrades
        can be performed.

        :return: True if anything was upgraded, or False if it was already up to date.
        """
        start_time = time.time()
        Logger.log("i", "Looking for old configuration files to upgrade.")
        self._upgrade_tasks.extend(
            self._getUpgradeTasks())  # Get the initial files to upgrade.
        self._upgrade_routes = self._findShortestUpgradeRoutes(
        )  # Pre-compute the upgrade routes.

        upgraded = False  # Did we upgrade something?
        while self._upgrade_tasks:
            upgrade_task = self._upgrade_tasks.popleft()
            self._upgradeFile(
                upgrade_task.storage_path, upgrade_task.file_name,
                upgrade_task.configuration_type)  # Upgrade this file.
            QCoreApplication.processEvents(
            )  # Ensure that the GUI does not freeze.
        if upgraded:
            message = UM.Message.Message(text=catalogue.i18nc(
                "@info:version-upgrade",
                "A configuration from an older version of {0} was imported.",
                Application.getInstance().getApplicationName()),
                                         title=catalogue.i18nc(
                                             "@info:title", "Version Upgrade"),
                                         message_type=UM.Message.Message.
                                         MessageType.POSITIVE)
            message.show()
        Logger.log("i", "Checking and performing updates took %s",
                   time.time() - start_time)
        return upgraded
Esempio n. 13
0
def test_getTimeout() -> None:
    app = QCoreApplication([])
    http_request_manager = HttpRequestManager.getInstance()

    cbo = mock.Mock()

    def error_callback(*args, **kwargs):
        cbo.error_callback(*args, **kwargs)
        # quit now so we don't need to wait
        http_request_manager.callLater(0, app.quit)

    request_data = http_request_manager.get(
        url="http://localhost:8080/timeout",
        error_callback=error_callback,
        timeout=1)
    # Make sure that if something goes wrong, we quit after 10 seconds
    http_request_manager.callLater(10.0, app.quit)

    app.exec()
    http_request_manager.cleanup()  # Remove all unscheduled events

    cbo.error_callback.assert_called_once_with(
        request_data.reply, QNetworkReply.NetworkError.OperationCanceledError)
    assert request_data.is_aborted_due_to_timeout
Esempio n. 14
0
    def __init__(self, parent=None):
        super().__init__(parent)

        self._name = None
        self._catalog = None

        # Slightly hacky way of getting at the QML engine defined by QtApplication.
        engine = QCoreApplication.instance()._qml_engine

        self._i18n_function = self._wrapFunction(engine, self, self._call_i18n)
        self._i18nc_function = self._wrapFunction(engine, self,
                                                  self._call_i18nc)
        self._i18np_function = self._wrapFunction(engine, self,
                                                  self._call_i18np)
        self._i18ncp_function = self._wrapFunction(engine, self,
                                                   self._call_i18ncp)
Esempio n. 15
0
    def __init__(self, tray_icon_name: str = None, **kwargs) -> None:
        self.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
        QQuickWindow.setGraphicsApi(QSGRendererInterface.GraphicsApi.OpenGL)

        plugin_path = ""
        if sys.platform == "win32":
            if hasattr(sys, "frozen"):
                plugin_path = os.path.join(os.path.dirname(os.path.abspath(sys.executable)), "PyQt6", "plugins")
                Logger.log("i", "Adding QT6 plugin path: %s", plugin_path)
                QCoreApplication.addLibraryPath(plugin_path)
            else:
                import site
                for sitepackage_dir in site.getsitepackages():
                    QCoreApplication.addLibraryPath(os.path.join(sitepackage_dir, "PyQt6", "plugins"))
        elif sys.platform == "darwin":
            plugin_path = os.path.join(self.getInstallPrefix(), "Resources", "plugins")

        if plugin_path:
            Logger.log("i", "Adding QT5 plugin path: %s", plugin_path)
            QCoreApplication.addLibraryPath(plugin_path)

        # use Qt Quick Scene Graph "basic" render loop
        os.environ["QSG_RENDER_LOOP"] = "basic"

        # Force using Fusion style for consistency between Windows, mac OS and Linux
        os.environ["QT_QUICK_CONTROLS_STYLE"] = "Fusion"

        super().__init__(sys.argv, **kwargs)

        self._qml_import_paths: List[str] = []
        self._main_qml: str = "main.qml"
        self._qml_engine: Optional[QQmlApplicationEngine] = None
        self._main_window: Optional[MainWindow] = None
        self._tray_icon_name: Optional[str] = tray_icon_name
        self._tray_icon: Optional[str] = None
        self._tray_icon_widget: Optional[QSystemTrayIcon] = None
        self._theme: Optional[Theme] = None
        self._renderer: Optional[QtRenderer] = None

        self._job_queue: Optional[JobQueue] = None
        self._version_upgrade_manager: Optional[VersionUpgradeManager] = None

        self._is_shutting_down: bool = False

        self._recent_files: List[QUrl] = []

        self._configuration_error_message: Optional[ConfigurationErrorMessage] = None

        self._http_network_request_manager: Optional[HttpRequestManager] = None

        #Metadata required for the file dialogues.
        self.setOrganizationDomain("https://ultimaker.com/")
        self.setOrganizationName("Ultimaker B.V.")
Esempio n. 16
0
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self._background_color = QColor(204, 204, 204, 255)

        self.beforeRenderPassRecording.connect(
            self._render, type=Qt.ConnectionType.DirectConnection)

        self._mouse_device = QtMouseDevice(self)
        self._mouse_device.setPluginId("qt_mouse")
        self._key_device = QtKeyDevice()
        self._key_device.setPluginId("qt_key")
        self._previous_focus = None  # type: Optional["QQuickItem"]

        self._app = QCoreApplication.instance()

        # Remove previously added input devices (if any). This can happen if the window was re-loaded.
        self._app.getController().removeInputDevice("qt_mouse")
        self._app.getController().removeInputDevice("qt_key")

        self._app.getController().addInputDevice(self._mouse_device)
        self._app.getController().addInputDevice(self._key_device)
        self._app.getController().getScene().sceneChanged.connect(
            self._onSceneChanged)
        self._app.getController().activeViewChanged.connect(
            self._onActiveViewChanged)
        Selection.selectionChanged.connect(self._onSceneChanged)
        self._preferences = Application.getInstance().getPreferences()

        self._preferences.addPreference("general/window_width",
                                        self.DEFAULT_WINDOW_WIDTH)
        self._preferences.addPreference("general/window_height",
                                        self.DEFAULT_WINDOW_HEIGHT)
        self._preferences.addPreference("general/window_left",
                                        self.DEFAULT_WINDOW_LEFT)
        self._preferences.addPreference("general/window_top",
                                        self.DEFAULT_WINDOW_TOP)
        self._preferences.addPreference("general/window_state",
                                        Qt.WindowState.WindowNoState.value)
        self._preferences.addPreference("general/restore_window_geometry",
                                        True)

        restored_geometry = QRect(
            int(self._preferences.getValue("general/window_left")),
            int(self._preferences.getValue("general/window_top")),
            int(self._preferences.getValue("general/window_width")),
            int(self._preferences.getValue("general/window_height")))

        if not self._preferences.getValue("general/restore_window_geometry"):
            # Ignore whatever the preferences said.
            Logger.log(
                "i",
                "Not restoring window geometry from preferences because 'restore_window_geometry' is false"
            )
            restored_geometry = QRect(self.DEFAULT_WINDOW_LEFT,
                                      self.DEFAULT_WINDOW_TOP,
                                      self.DEFAULT_WINDOW_WIDTH,
                                      self.DEFAULT_WINDOW_HEIGHT)

        # Make sure restored geometry is not outside the currently available screens
        screen_found = False
        for screen in self._app.screens():
            if restored_geometry.intersects(screen.availableGeometry()):
                screen_found = True
                break

        if not screen_found:
            Logger.log(
                "w",
                "Could not restore to previous location on screen, since the sizes or number of monitors "
                "have changed since then")
            # Unable to find the screen that this window used to be on, so just use the defaults
            restored_geometry = QRect(self.DEFAULT_WINDOW_LEFT,
                                      self.DEFAULT_WINDOW_TOP,
                                      self.DEFAULT_WINDOW_WIDTH,
                                      self.DEFAULT_WINDOW_HEIGHT)

        self.setGeometry(restored_geometry)
        # Translate window state back to enum.
        try:
            window_state = int(
                self._preferences.getValue("general/window_state"))
        except ValueError:
            self._preferences.resetPreference("general/window_state")
            window_state = int(
                self._preferences.getValue("general/window_state"))

        if window_state == Qt.WindowState.WindowNoState.value:
            self.setWindowState(Qt.WindowState.WindowNoState)
        elif window_state == Qt.WindowState.WindowMaximized.value:
            self.setWindowState(Qt.WindowState.WindowMaximized)

        self._mouse_x = 0
        self._mouse_y = 0

        self._mouse_pressed = False

        self._viewport_rect = QRectF(0, 0, 1.0, 1.0)

        self.closing.connect(self.preClosing)

        Application.getInstance().setMainWindow(self)
        self._fullscreen = False

        self._full_render_required = True

        self._allow_resize = True
Esempio n. 17
0
def handle_exception(exc_type, exc_value, trace):
    try:
        exc_tuple = (exc_type, exc_value, trace)
        error_message = ''.join(traceback.format_exception(*exc_tuple))

        popup = ErrorPopup(error_message)
        popup.exec()

        if popup.sending:
            send_error_report(exc_tuple)

        stacks = inspect.stack()
        if len(stacks) >= 2:
            stack = stacks[1]
            module = inspect.getmodule(stack.frame)
            if module:
                module_name = module.__name__
            else:
                path = pathlib.Path(stack.filename)
                module_name = f"{path.parent.name}.{path.stem}"
        else:
            for filename in map(
                lambda frame: frame.filename,
                reversed(traceback.extract_tb(exc_tuple[-1]))
            ):
                path = pathlib.Path(filename)
                if path.parent.name == 'beskar' and not path.stem.startswith('__'):
                    module_name = f"beskar.{path.stem}"
                    break
            else:
                module_name = None

        if module_name in sys.modules:
            logger = logging.getLogger(module_name)
        else:
            logger = logging.getLogger('beskar.unknown')
            logger.warning(
                'Failed to determine which module caused '
                'the error in the upcoming logging message.'
            )

        logger.critical('The following error occured:', exc_info=exc_tuple)
        if pool is not None:
            pool.clear()
    except Exception as second_error:
        second_error.__context__ = exc_value
        if popup.sending:
            send_error_report(second_error)
        logger = logging.getLogger('beskar.unknown')
        logger.error(
            'Two exceptions occured in handle_exception:',
            exc_info=second_error
        )
    finally:
        try:
            # NOTE: Trying to close the application even
            # if there is an error in the try block above
            # however, despite this we MUST exit the app
            # no matter what. In an abudance of caution
            # wrap this in a try finally block.
            QCoreApplication.quit()
        finally:
            sys.exit(1)
Esempio n. 18
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. 19
0
 def _onDelayReached(self, event: "_CallFunctionEvent") -> None:
     QCoreApplication.instance().postEvent(self, event)
Esempio n. 20
0
    def _installPackage(self, installation_package_data: PackageData) -> None:
        package_info = installation_package_data["package_info"]
        filename = installation_package_data["filename"]

        package_id = package_info["package_id"]
        Logger.log("i", "Installing package [%s] from file [%s]", package_id,
                   filename)

        # Load the cached package file and extract all contents to a temporary directory
        if not os.path.exists(filename):
            Logger.log(
                "w",
                "Package [%s] file '%s' is missing, cannot install this package",
                package_id, filename)
            return
        try:
            with zipfile.ZipFile(filename, "r") as archive:
                name_list = archive.namelist()
                temp_dir = tempfile.TemporaryDirectory()
                for archive_filename in name_list:
                    archive.extract(archive_filename, temp_dir.name)
                    QCoreApplication.processEvents()
        except Exception:
            Logger.logException("e",
                                "Failed to install package from file [%s]",
                                filename)
            return

        # Remove it first and then install
        try:
            self._purgePackage(package_id)
        except Exception as e:
            message = Message(catalog.i18nc(
                "@error:update",
                "There was an error uninstalling the package {package} before installing "
                "new version:\n{error}.\nPlease try to upgrade again later.".
                format(package=package_id, error=str(e))),
                              title=catalog.i18nc("@info:title",
                                                  "Updating error"),
                              message_type=Message.MessageType.ERROR)
            message.show()
            return

        # Copy the folders there
        for sub_dir_name, installation_root_dir in self._installation_dirs_dict.items(
        ):
            src_dir_path = os.path.join(temp_dir.name, "files", sub_dir_name)
            dst_dir_path = os.path.join(installation_root_dir, package_id)

            if not os.path.exists(src_dir_path):
                Logger.log(
                    "w",
                    "The path %s does not exist, so not installing the files",
                    src_dir_path)
                continue
            try:
                self.__installPackageFiles(package_id, src_dir_path,
                                           dst_dir_path)
            except EnvironmentError as e:
                Logger.log(
                    "e",
                    "Can't install package due to EnvironmentError: {err}".
                    format(err=str(e)))
                continue

        # Remove the file
        try:
            os.remove(filename)
        except Exception:
            Logger.log("w", "Tried to delete file [%s], but it failed",
                       filename)

        # Move the info to the installed list of packages only when it succeeds
        self._installed_package_dict[
            package_id] = self._to_install_package_dict[package_id]
        self._installed_package_dict[package_id]["package_info"][
            "is_installed"] = True
Esempio n. 21
0
# -*- coding: utf-8 -*-


import sys
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton
from PyQt6.QtCore import QCoreApplication

if __name__ == '__main__':
    app = QApplication(sys.argv)
    btn = QPushButton("Hello PyQt6")
    btn.clicked.connect(QCoreApplication.instance().quit)
    btn.resize(400,100)
    btn.move(50,50)
    btn.show()
    sys.exit(app.exec())
Esempio n. 22
0
 def functionEvent(self, event: QEvent) -> None:
     e = _QtFunctionEvent(event)
     QCoreApplication.postEvent(self, e)