def core(progress):
            # setup mover thread
            mover = files.move_folder_thread(old_install, new_install)
            mover.activity_update.connect(progress.set_activity)

            def failed(err):
                typ = type(err)
                message = err

                logger.exception("Failed to move folder")
                error_dialogs.general(self, typ, message)

            # start the thread
            with thread.thread_wait(
                    mover.finished,
                    failed_signal=mover.failed,
                    failed_func=failed,
                    update_signal=mover.activity_update,
            ):
                mover.start()

            config.set_key_value(config.MOD_INSTALL_FOLDER_KEY,
                                 new_install,
                                 path=True)
            information_dialogs.disabled_mods_folder(self, new_install)
Exemple #2
0
        def user_selection():
            """Function to keep user in a loop until they select correct folder."""
            # prompt user to select
            self.sim_folder = QtWidgets.QFileDialog.getExistingDirectory(
                parent=self,
                caption="Select the root Microsoft Flight Simulator directory",
                dir=os.getenv("APPDATA"),
            )

            if not self.sim_folder.strip():
                sys.exit()

            elif flight_sim.is_sim_packages_folder(self.sim_folder):
                # save the config file
                config.set_key_value(config.SIM_FOLDER_KEY, self.sim_folder)

            else:
                # show error
                QtWidgets.QMessageBox().warning(
                    self,
                    "Error",
                    "Invalid Microsoft Flight Simulator path."
                    + " Please select the Packages folder manually"
                    + " (which contains the Official and Community folders).",
                )

                # send them through again
                user_selection()
    def find_sim(self):
        """Sets the path to the simulator root folder."""
        def user_selection():
            """Function to keep user in a loop until they select correct folder."""
            # prompt user to select
            self.sim_folder = QtWidgets.QFileDialog.getExistingDirectory(
                parent=self,
                caption="Select the root Microsoft Flight Simulator directory",
                dir=os.getenv("APPDATA"),
            )

            if not self.sim_folder.strip():
                sys.exit()

            elif flight_sim.is_sim_packages_folder(self.sim_folder):
                # save the config file
                config.set_key_value(config.SIM_FOLDER_KEY, self.sim_folder)

            else:
                # show error
                QtWidgets.QMessageBox().warning(
                    self,
                    "Error",
                    "Invalid Microsoft Flight Simulator path." +
                    " Please select the Packages folder manually" +
                    " (which contains the Official and Community folders).",
                )

                # send them through again
                user_selection()

        # try to automatically find the sim
        (
            success,
            self.sim_folder,
        ) = flight_sim.find_sim_folder()

        if not self.sim_folder:
            # show error
            QtWidgets.QMessageBox().warning(
                self,
                "Error",
                "Microsoft Flight Simulator path could not be found." +
                " Please select the Packages folder manually" +
                " (which contains the Official and Community folders).",
            )

            user_selection()

        elif not success:
            # save the config file
            config.set_key_value(config.SIM_FOLDER_KEY, self.sim_folder)
            # notify user
            QtWidgets.QMessageBox().information(
                self,
                "Info",
                "Your Microsoft Flight Simulator folder path was automatically detected to {}"
                .format(self.sim_folder),
            )
def get_last_open_folder() -> str:
    """Gets the last opened directory from the config file."""
    succeeded, value = config.get_key_value(config.LAST_OPEN_FOLDER_KEY,
                                            path=True)
    if not succeeded or not os.path.isdir(value):
        # if mod install folder could not be loaded from config
        value = os.path.abspath(
            os.path.join(os.path.expanduser("~"), "Downloads"))
        config.set_key_value(config.LAST_OPEN_FOLDER_KEY, value, path=True)

    return fix_path(value)
Exemple #5
0
    def check_version(self):
        """Checks the application version and allows user to open browser to update."""
        installed = version.is_installed()
        return_url = version.check_version(self.appctxt, installed)

        if return_url:
            result, remember = version_check_widget(self, installed).exec_()
            if result == QtWidgets.QMessageBox.Yes:
                if installed:
                    # progress bar
                    progress = progress_widget(self, self.appctxt)
                    progress.set_percent()
                    progress.set_activity(
                        "Downloading latest version ({})".format(return_url)
                    )

                    # setup downloader thread
                    downloader = version.download_new_version_thread(return_url)
                    downloader.activity_update.connect(progress.set_percentage)

                    def failed(err):
                        typ = type(err)
                        message = err

                        logger.exception("Failed to download new version")
                        QtWidgets.QMessageBox().warning(
                            self,
                            "Error",
                            "Something went terribly wrong.\n{}: {}".format(
                                typ, message
                            ),
                        )

                    # start the thread
                    with thread.thread_wait(
                        downloader.finished,
                        finish_func=version.install_new_version,
                        failed_signal=downloader.failed,
                        failed_func=failed,
                        update_signal=downloader.activity_update,
                    ):
                        downloader.start()

                    progress.close()
                else:
                    webbrowser.open(return_url)
            elif remember:
                config.set_key_value(config.NEVER_VER_CHEK_KEY, True)
Exemple #6
0
def set_theme(appctxt: ApplicationContext, fs_theme: bool) -> None:
    """Writes theme selection to config file and sets the app stylesheet."""
    logger.debug("Writing theme selection to config file")
    if fs_theme:
        config.set_key_value(config.THEME_KEY, FS_THEME)

        # apply stylesheet
        logger.debug("Applying application stylesheet {}".format(
            appctxt.get_resource("fs_style.qss")))
        stylesheet = appctxt.get_resource("fs_style.qss")
        appctxt.app.setStyleSheet(open(stylesheet, "r").read())
    else:
        config.set_key_value(config.THEME_KEY, "None")

        logger.debug("Clearing application stylesheet")
        appctxt.app.setStyleSheet("")
def get_mod_install_folder() -> str:
    """Gets the current mod install folder value from the config file."""
    succeeded, value = config.get_key_value(config.MOD_INSTALL_FOLDER_KEY,
                                            path=True)
    if not succeeded:
        # if mod install folder could not be loaded from config
        value = os.path.abspath(os.path.join(config.BASE_FOLDER, "modCache"))
        config.set_key_value(config.MOD_INSTALL_FOLDER_KEY, value, path=True)

    mod_install_folder = fix_path(value)

    if not os.path.exists(mod_install_folder):
        logger.debug(
            "Creating mod install folder {}".format(mod_install_folder))
        os.makedirs(mod_install_folder)

    return mod_install_folder
    def check_version(self) -> None:
        """Checks the application version and allows user to open browser to update."""
        installed = version.is_installed()
        return_url = version.check_version(self.appctxt,
                                           installed)  # type: ignore

        def core(progress: Callable) -> None:
            progress.set_mode(progress.PERCENT)
            progress.set_activity(
                "Downloading latest version ({})".format(return_url))

            # setup downloader thread
            downloader = version.download_new_version_thread(
                return_url)  # type: ignore
            downloader.percent_update.connect(
                progress.set_percent)  # type: ignore

            def failed(err: Exception) -> None:
                typ = type(err)
                message = str(err)

                logger.exception("Failed to download new version")
                error_dialogs.general(self, typ, message)

            # start the thread
            with thread.thread_wait(
                    downloader.finished,
                    finish_func=version.install_new_version,
                    failed_signal=downloader.failed,
                    failed_func=failed,
                    update_signal=downloader.percent_update,
            ):
                downloader.start()

        if not return_url:
            return

        result, remember = version_check_dialog(self, installed).exec_()
        if result:
            if installed:
                self.base_action(core, refresh=False)
            else:
                webbrowser.open(return_url)  # type: ignore
        elif remember:
            config.set_key_value(config.NEVER_VER_CHEK_KEY, True)
        def user_selection():
            """Function to keep user in a loop until they select correct folder."""
            # prompt user to select
            self.flight_sim.sim_packages_folder = (
                QtWidgets.QFileDialog.getExistingDirectory(
                    parent=self,
                    caption=
                    "Select the root Microsoft Flight Simulator directory",
                    dir=os.getenv("APPDATA"),
                ))

            if not self.flight_sim.sim_packages_folder.strip():
                sys.exit()

            elif self.flight_sim.is_sim_packages_folder(
                    self.flight_sim.sim_packages_folder):
                # save the config file
                config.set_key_value(
                    config.SIM_FOLDER_KEY,
                    self.flight_sim.sim_packages_folder,
                    path=True,
                )

            elif self.flight_sim.is_sim_packages_folder(
                    os.path.join(self.flight_sim.sim_packages_folder,
                                 "Packages")):
                # save the config file
                config.set_key_value(
                    config.SIM_FOLDER_KEY,
                    os.path.join(self.flight_sim.sim_packages_folder,
                                 "Packages"),
                    path=True,
                )

            else:
                # show error
                warning_dialogs.sim_path_invalid(self)
                # send them through again
                user_selection()
Exemple #10
0
    def move_mod_install_folder(
        self, src: str, dest: str, update_func: Callable = None
    ) -> None:
        """Moves the mod install folder."""
        logger.debug("Moving mod install folder from {} to {}".format(src, dest))
        # first, build a list of the currently enabled mods
        enabled_mod_folders = files.listdir_dirs(self.get_sim_mod_folder())

        # move the install folder
        files.move_folder(src, dest, update_func=update_func)

        # set new config value
        config.set_key_value(config.MOD_INSTALL_FOLDER_KEY, dest, path=True)
        # clear the cache
        self.clear_mod_cache()
        config.get_key_value.cache_clear()

        # now, go through mods in the install folder and re-enable them
        # if they were enabled before.
        moved_mod_folders = files.listdir_dirs(dest)

        for mod_folder in moved_mod_folders:
            if mod_folder in enabled_mod_folders:
                self.enable_mod(mod_folder, update_func=update_func)
    def install_folder(self):
        """Installs selected mod folders."""

        # first, let user select a folder
        mod_folder = QtWidgets.QFileDialog.getExistingDirectory(
            parent=self,
            caption="Select mod folder",
            dir=files.get_last_open_folder(),
        )

        succeeded = []

        def core(progress):
            def finish(result):
                # this function is required as the results will be a list,
                # which is not a hashable type
                succeeded.extend(result)

            def failed(error):
                mapping = {
                    flight_sim.NoManifestError:
                    lambda: warning_dialogs.mod_parsing(self, [mod_folder]),
                    files.AccessError:
                    lambda: error_dialogs.permission(self, mod_folder, error),
                    flight_sim.NoModsError:
                    lambda: error_dialogs.no_mods(self, mod_folder),
                }

                self.base_fail(
                    error,
                    mapping,
                    "Failed to install mod folder",
                )

            # setup installer thread
            installer = flight_sim.install_mods_thread(self.flight_sim,
                                                       mod_folder)
            installer.activity_update.connect(progress.set_activity)

            # start the thread
            with thread.thread_wait(
                    installer.finished,
                    finish_func=finish,
                    failed_signal=installer.failed,
                    failed_func=failed,
                    update_signal=installer.activity_update,
            ):
                installer.start()

        self.base_action(
            core,
            button=self.install_button,
            empty_check=True,
            empty_val=mod_folder,
        )

        if succeeded:
            config.set_key_value(config.LAST_OPEN_FOLDER_KEY,
                                 os.path.dirname(mod_folder),
                                 path=True)
            information_dialogs.mods_installed(self, succeeded)
    def install_archive(self):
        """Installs selected mod archives."""

        # first, let user select multiple archives
        mod_archives = QtWidgets.QFileDialog.getOpenFileNames(
            parent=self,
            caption="Select mod archive(s)",
            dir=files.get_last_open_folder(),
            filter=ARCHIVE_FILTER,
        )[0]

        succeeded = []

        def core(progress):
            # for each archive, try to install it
            for mod_archive in mod_archives:

                def finish(result):
                    # this function is required as the results will be a list,
                    # which is not a hashable type
                    succeeded.extend(result)

                def failed(error):
                    mapping = {
                        files.ExtractionError:
                        lambda: error_dialogs.archive_extract(
                            self, mod_archive, error),
                        flight_sim.NoManifestError:
                        lambda: warning_dialogs.mod_parsing(
                            self, [mod_archive]),
                        files.AccessError:
                        lambda: error_dialogs.permission(
                            self, mod_archive, error),
                        flight_sim.NoModsError:
                        lambda: error_dialogs.no_mods(self, mod_archive),
                    }

                    self.base_fail(
                        error,
                        mapping,
                        "Failed to install mod archive",
                    )

                # setup installer thread
                installer = flight_sim.install_mod_archive_thread(
                    self.flight_sim, mod_archive)
                installer.activity_update.connect(progress.set_activity)
                installer.percent_update.connect(progress.set_percent)

                # start the thread
                with thread.thread_wait(
                        installer.finished,
                        finish_func=finish,
                        failed_signal=installer.failed,
                        failed_func=failed,
                        update_signal=installer.activity_update,
                        timeout=1200000,
                ):
                    installer.start()

        self.base_action(
            core,
            button=self.install_button,
            empty_check=True,
            empty_val=mod_archives,
        )

        if succeeded:
            config.set_key_value(config.LAST_OPEN_FOLDER_KEY,
                                 os.path.dirname(mod_archives[0]),
                                 path=True)
            information_dialogs.mods_installed(self, succeeded)
Exemple #13
0
def check_version(appctxt, installed=False):
    """Returns the release URL if a new version is installed.
    Otherwise, returns False."""
    logger.debug("Checking if a new version is available")
    time_format = "%Y-%m-%d %H:%M:%S"

    if not check_version_config(time_format):
        return False

    # open the remote url
    url = "https://api.github.com/repos/NathanVaughn/msfs-mod-manager/releases/latest"

    try:
        logger.debug("Attempting to open url {}".format(url))
        # always will be opening the above hard-coded URL
        page = urllib.request.urlopen(url)  # nosec
    except Exception:
        logger.exception("Opening url {} failed".format(url))
        return False

    # read page contents
    logger.debug("Reading page contents")
    data = page.read()
    data = data.decode("utf-8")

    # parse the json
    try:
        logger.debug("Attemping to parse page contents")
        parsed_data = json.loads(data)
        remote_version = parsed_data["tag_name"]
    except Exception:
        logger.exception("Parsing page contents failed")
        return False

    logger.debug("Remote version found is: {}".format(remote_version))

    # write the config file back out
    logger.debug("Writing out last version check time to config file")
    config.set_key_value(
        config.LAST_VER_CHECK_KEY,
        datetime.datetime.strftime(datetime.datetime.now(), time_format),
    )

    # check if remote version is newer than local version
    if remote_version > get_version(appctxt):
        # if so, return release url
        logger.debug("Remote version is newer than local version")
        download_url = False

        if installed:
            # return setup.exe url
            for asset in parsed_data["assets"]:
                if asset["name"].endswith(".exe"):
                    download_url = asset["browser_download_url"]
                    break
        else:
            # return release url
            download_url = parsed_data["html_url"]

        logger.debug("New release url: {}".format(download_url))
        return download_url
    else:
        logger.debug("Remote version is not newer than local version")
        return False
    def find_sim(self) -> None:
        """Sets the path to the simulator root folder."""
        def user_selection() -> None:
            """Function to keep user in a loop until they select correct folder."""
            # prompt user to select
            self.flight_sim.sim_packages_folder = (
                QtWidgets.QFileDialog.getExistingDirectory(
                    parent=self,
                    caption=
                    "Select the root Microsoft Flight Simulator directory",
                    dir=os.getenv("APPDATA"),  # type: ignore
                ))

            if not self.flight_sim.sim_packages_folder.strip():
                sys.exit()

            elif self.flight_sim.is_sim_packages_folder(
                    self.flight_sim.sim_packages_folder):
                # save the config file
                config.set_key_value(
                    config.SIM_FOLDER_KEY,
                    self.flight_sim.sim_packages_folder,
                    path=True,
                )

            elif self.flight_sim.is_sim_packages_folder(
                    os.path.join(self.flight_sim.sim_packages_folder,
                                 "Packages")):
                # save the config file
                config.set_key_value(
                    config.SIM_FOLDER_KEY,
                    os.path.join(self.flight_sim.sim_packages_folder,
                                 "Packages"),
                    path=True,
                )

            else:
                # show error
                warning_dialogs.sim_path_invalid(self)
                # send them through again
                user_selection()

        # try to automatically find the sim
        (
            success,
            self.flight_sim.sim_packages_folder,  # type: ignore
        ) = self.flight_sim.find_sim_packages_folder()

        if not self.flight_sim.sim_packages_folder:
            # show error
            warning_dialogs.sim_not_detected(self)
            # let user select folder
            user_selection()

        elif not success:
            # save the config file
            config.set_key_value(config.SIM_FOLDER_KEY,
                                 self.flight_sim.sim_packages_folder,
                                 path=True)
            # notify user
            information_dialogs.sim_detected(
                self, self.flight_sim.sim_packages_folder)