예제 #1
0
def add_config_file_button(path: pathlib.Path) -> None:
    """
    Add a button to *Settings/Config Files* that opens a file in Porcupine when
    it's clicked.
    """
    get_menu("Settings/Config Files").add_command(
        label=path.name,
        command=(lambda: get_tab_manager().add_tab(
            tabs.FileTab.open_file(get_tab_manager(), path))),
    )
예제 #2
0
    def open_files() -> None:
        paths = filedialog.askopenfilenames(**filedialog_kwargs)  # "" or tuple
        for path in map(pathlib.Path, paths):
            try:
                tab = tabs.FileTab.open_file(get_tab_manager(), path)
            except (UnicodeError, OSError) as e:
                log.exception(f"opening '{path}' failed")
                utils.errordialog(
                    type(e).__name__, "Opening failed!",
                    traceback.format_exc())
                continue

            get_tab_manager().add_tab(tab)
예제 #3
0
 def save_file(save_as: bool) -> None:
     tab = get_tab_manager().select()
     assert isinstance(tab, tabs.FileTab)
     if save_as:
         tab.save_as()
     else:
         tab.save()
예제 #4
0
def set_enabled_based_on_tab(
        path: str, callback: Callable[[Optional[tabs.Tab]],
                                      bool]) -> Callable[..., None]:
    """Use this for disabling menu items depending on the currently selected tab.

    When the selected :class:`~porcupine.tabs.Tab` changes, ``callback`` will
    be called with the selected tab as an argument, or ``None`` if there are
    no tabs. If the callback returns ``False``, then the menu item given by
    *path* is disabled (so that it looks grayed out and can't be clicked).

    The *path* works similarly to :func:`get_menu`, except that it refers to a
    menu item rather than a submenu. For example, ``"Tools/Python/Black"``
    means a menu item labelled *Black* in the *Tools/Python* menu.

    For example, this creates a menu item ``Foo/Bar`` and disables it whenever
    the currently selected tab is not a :class:`porcupine.tabs.FileTab`::

        from porcupine import menubar, tabs

        def do_something():
            ...

        def setup():
            menubar.get_menu("Foo").add_command(label="Bar", command=do_something)
            menubar.set_enabled_based_on_tab("Foo/Bar", (lambda tab: isinstance(tab, tabs.FileTab)))

    Sometimes you need to update the enabled-ness of a menu item for other
    reasons than changing the currently selected tab. To do that, call the
    callback that this function returns. It's always called when the selected
    tab changes, but you can call it at other times too. The returned callback
    ignores all arguments given to it, which makes using it with ``.bind()``
    easier.
    """
    def update_enabledness(*junk: object) -> None:
        tab = get_tab_manager().select()
        menu = get_menu(path.rsplit("/", 1)[0] if "/" in path else None)
        index = _find_item(menu, path.split("/")[-1])
        if index is None:
            raise LookupError(f"menu item {path!r} not found")
        menu.entryconfig(index,
                         state=("normal" if callback(tab) else "disabled"))

    update_enabledness()
    get_tab_manager().bind("<<NotebookTabChanged>>",
                           update_enabledness,
                           add=True)
    return update_enabledness
예제 #5
0
 def update_enabledness(*junk: object) -> None:
     tab = get_tab_manager().select()
     menu = get_menu(path.rsplit("/", 1)[0] if "/" in path else None)
     index = _find_item(menu, path.split("/")[-1])
     if index is None:
         raise LookupError(f"menu item {path!r} not found")
     menu.entryconfig(index,
                      state=("normal" if callback(tab) else "disabled"))
예제 #6
0
 def on_tab_changed(junk: object = None) -> None:
     tab = get_tab_manager().select()
     menu = get_menu(path.rsplit('/', 1)[0] if '/' in path else None)
     index = _find_item(menu, path.split('/')[-1])
     if index is None:
         raise LookupError(f"menu item {path!r} not found")
     menu.entryconfig(index,
                      state=('normal' if callback(tab) else 'disabled'))
예제 #7
0
    def open_files() -> None:
        paths: Sequence[str] = filedialog.askopenfilenames(
            **filedialog_kwargs)  # type: ignore

        # tkinter returns '' if the user cancels, and i'm arfaid that python
        # devs might "fix" a future version to return None
        if not paths:
            return

        for path in map(pathlib.Path, paths):
            try:
                tab = tabs.FileTab.open_file(get_tab_manager(), path)
            except (UnicodeError, OSError) as e:
                log.exception("opening '%s' failed", path)
                utils.errordialog(
                    type(e).__name__, "Opening failed!",
                    traceback.format_exc())
                continue

            get_tab_manager().add_tab(tab)
예제 #8
0
def set_enabled_based_on_tab(
        path: str, callback: Callable[[Optional[tabs.Tab]], bool]) -> None:
    """Use this for disabling menu items depending on the currently selected tab.

    When the selected :class:`~porcupine.tabs.Tab` changes, ``callback`` will
    be called with the selected tab as an argument, or ``None`` if there are
    no tabs. If the callback returns ``False``, then the menu item given by
    *path* is disabled (so that it looks grayed out and can't be clicked).

    The *path* works similarly to :func:`get_menu`, except that it refers to a
    menu item rather than a submenu. For example, ``"Tools/Python/Black"``
    means a menu item labelled *Black* in the *Tools/Python* menu.

    For example, this creates a menu item ``Foo/Bar`` and disables it whenever
    the currently selected tab is not a :class:`porcupine.tabs.FileTab`::

        from porcupine import menubar, tabs

        def do_something():
            ...

        def setup():
            menubar.get_menu("Foo").add_command(label="Bar", command=do_something)
            set_enabled_based_on_tab("Foo/Bar", (lambda tab: isinstance(tab, tabs.FileTab)))
    """
    def on_tab_changed(junk: object = None) -> None:
        tab = get_tab_manager().select()
        menu = get_menu(path.rsplit('/', 1)[0] if '/' in path else None)
        index = _find_item(menu, path.split('/')[-1])
        if index is None:
            raise LookupError(f"menu item {path!r} not found")
        menu.entryconfig(index,
                         state=('normal' if callback(tab) else 'disabled'))

    on_tab_changed()
    get_tab_manager().bind('<<NotebookTabChanged>>', on_tab_changed, add=True)
예제 #9
0
 def close_selected_tab() -> None:
     tab = get_tab_manager().select()
     assert tab is not None
     if tab.can_be_closed():
         get_tab_manager().close_tab(tab)
예제 #10
0
 def new_file() -> None:
     get_tab_manager().add_tab(tabs.FileTab(get_tab_manager()))