Exemple #1
0
 def add_clicked() -> None:
     assert self.__profile
     add_dir = self.ui.get_persistent_string("import_directory", "")
     file_paths, filter_str, directory = self.get_file_paths_dialog(_("Add Scripts"), add_dir, "Python Files (*.py)", "Python Files (*.py)")
     self.ui.set_persistent_string("import_directory", directory)
     items = list(self.scripts_list_widget.items)
     for file_path_str in file_paths:
         script_item = Profile.FileScriptItem(pathlib.Path(file_path_str))
         self.__profile.append_script_item(script_item)
         script_list_item = ScriptListItem(file_path_str)
         script_list_item.script_item = script_item
         items.append(script_list_item)
     self.update_scripts_list(items)
Exemple #2
0
    def start(self,
              *,
              profile_dir: pathlib.Path = None,
              profile: Profile.Profile = None) -> bool:
        """Start the application.

        Creates the profile object using profile_path parameter (for testing), the profile path constructed from the
        name stored in preferences, or a default profile path.

        Attaches recent projects if profile is freshly created. The recent projects will initially be disabled and
        will require the user to explicitly upgrade them.

        Creates the document model with the profile.

        Creates the document window (aka document controller) with the document model.
        """
        logging.getLogger("migration").setLevel(logging.INFO)
        logging.getLogger("loader").setLevel(logging.INFO)

        # create or load the profile object. allow test to override profile.
        is_created = False
        if not profile:
            # determine the profile_path
            if profile_dir:
                profile_path = profile_dir / pathlib.Path(
                    "Profile").with_suffix(".nsproj")
            else:
                data_dir = pathlib.Path(self.ui.get_data_location())
                profile_name = pathlib.Path(
                    self.ui.get_persistent_string("profile_name", "Profile"))
                profile_path = data_dir / profile_name.with_suffix(".nsproj")
            # create the profile
            profile, is_created = self.__establish_profile(profile_path)
        self.__profile = profile

        # test code to reset script items
        # self.__profile.script_items_updated = False
        # while self.__profile.script_items:
        #     self.__profile.remove_script_item(self.__profile.script_items[-1])

        # migrate the interactive scripts persistent object
        if not self.__profile.script_items_updated:
            items_str = self.ui.get_persistent_string("interactive_scripts_1")
            if items_str:
                for item_dict in json.loads(items_str):
                    item_type = item_dict.get("__type__", None)
                    if item_type == "FolderListItem":
                        folder_path_str = item_dict.get("full_path", None)
                        folder_path = pathlib.Path(
                            folder_path_str) if folder_path_str else None
                        if folder_path:
                            profile.append_script_item(
                                Profile.FolderScriptItem(
                                    pathlib.Path(folder_path)))
                    elif item_type == "ScriptListItem" and item_dict.get(
                            "indent_level", None) == 0:
                        script_path_str = item_dict.get("full_path", None)
                        script_path = pathlib.Path(
                            script_path_str) if script_path_str else None
                        if script_path:
                            profile.append_script_item(
                                Profile.FileScriptItem(
                                    pathlib.Path(script_path)))
            else:
                items_old = self.ui.get_persistent_object(
                    "interactive_scripts_0", list())
                for script_path_str in items_old:
                    script_path = pathlib.Path(
                        script_path_str) if script_path_str else None
                    if script_path:
                        profile.append_script_item(
                            Profile.FileScriptItem(pathlib.Path(script_path)))
            self.__profile.script_items_updated = True

        # configure the document model object.
        DocumentModel.DocumentModel.computation_min_period = 0.1
        DocumentModel.DocumentModel.computation_min_factor = 1.0

        # if it was created, it probably means it is migrating from an old version. so add all recent projects.
        # they will initially be disabled and the user will have to explicitly upgrade them.
        if is_created:
            # present a dialog for showing progress while finding existing projects
            u = Declarative.DeclarativeUI()
            task_message = u.create_label(
                text=_("Looking for existing projects..."))
            progress = u.create_progress_bar(
                value="@binding(progress_value_model.value)", width=300 - 24)
            progress_message = u.create_label(
                text="@binding(message_str_model.value)")
            main_column = u.create_column(task_message,
                                          progress,
                                          progress_message,
                                          spacing=8,
                                          width=300)
            window = u.create_window(main_column,
                                     title=_("Locating Existing Projects"),
                                     margin=12,
                                     window_style="tool")

            # handler for the progress window. defines two value models: progress, an int 0-100; and message, a string.
            class FindExistingProjectsWindowHandler(Declarative.WindowHandler):
                def __init__(self,
                             *,
                             completion_fn: typing.Optional[typing.Callable[
                                 [], None]] = None):
                    super().__init__(completion_fn=completion_fn)
                    self.progress_value_model = Model.PropertyModel(0)
                    self.message_str_model = Model.PropertyModel(str())

            # construct the window handler and run it. when the dialog closes, it will continue by
            # calling open default project.
            window_handler = FindExistingProjectsWindowHandler(
                completion_fn=functools.partial(self.__open_default_project,
                                                profile_dir, is_created))
            window_handler.run(window, app=self)

            # define an async routine that will perform the finding of the existing projects.
            # this is just a loop that yields via asyncio.sleep periodically. the loop loads
            # the projects and updates the progress and message value models in the dialog.
            # when finished, it asks the window to close on its next periodic call. it is
            # necessary to close this way because the close request may close the event loop
            # in which we're executing. so queueing the close request avoids that.
            async def find_existing_projects():
                recent_library_paths = self.get_recent_library_paths()
                for index, library_path in enumerate(recent_library_paths):
                    window_handler.progress_value_model.value = 100 * index // len(
                        recent_library_paths)
                    window_handler.message_str_model.value = str(
                        library_path.name)
                    logging.getLogger("loader").info(
                        f"Adding existing project {index + 1}/{len(recent_library_paths)} {library_path}"
                    )
                    await asyncio.sleep(0)
                    profile.add_project_folder(pathlib.Path(library_path),
                                               load=False)
                window_handler.progress_value_model.value = 100
                window_handler.message_str_model.value = _("Finished")
                await asyncio.sleep(1)
                window_handler.window.queue_request_close()

            # launch the find existing projects task asynchronously.
            window_handler.window.event_loop.create_task(
                find_existing_projects())
            return True
        else:
            # continue with opening the default project
            return self.__open_default_project(profile_dir, is_created)