|
Junior Member
Posts: 8
Karma: 10
Join Date: Oct 2025
Device: i dont have one
|
The shim acts as an intermediary layer (or "shim") between the plugin's logic and the underlying Qt GUI framework. Its primary goals are:
Compatibility Handling: It ensures the code works across different Qt versions (PyQt5 and PyQt6) by dynamically importing the appropriate modules and using version-agnostic APIs.
Abstraction of GUI Operations: It simplifies common tasks like adding menu items, toolbar buttons, and dropdowns, without requiring direct manipulation of Qt objects (e.g., QMenu, QToolBar, QAction). This makes the code more maintainable and testable.
Plugin Integration: In applications like Calibre, plugins often need to integrate into the main GUI (e.g., adding items to menus like '&Plugins' or toolbars). The shim provides a standardized way to do this, handling edge cases such as creating submenus or finding existing UI elements.
Testing Support: It includes mock classes (MockGui and MockBoss) to simulate the GUI environment for standalone testing, allowing the code to run outside the full application.
Without the shim, the plugin code would need to directly interact with the application's gui object (e.g., boss.gui.menuBar()), which could lead to version-specific issues or tighter coupling to the host application.
Key Components and Methods of the Shim
The ShimBoss class is initialized with a gui object (typically from the application's boss.gui). It exposes several methods for GUI modifications:
get_plugins_menu():
Searches the main menu bar for an existing '&Plugins' menu.
Returns the menu if found; otherwise, returns None.
This is used as a starting point for plugin-specific menu additions, ensuring they integrate into a standard location.
add_menu_action(menu_path, action_text, callback, shortcut=None, icon_path=None, tooltip=None, name=None):
Adds a new action (menu item) to a specified menu path.
The menu_path is a pipe-separated string (e.g., 'Plugins|Footnotes' or 'Tools|My Plugin'), which the shim parses to create or navigate submenus dynamically.
If the path starts with 'Plugins', it uses the existing '&Plugins' menu as the root.
Configures the action with optional shortcut, icon, tooltip, and object name.
Connects the action's triggered signal to the provided callback function.
Returns the created QAction object.
Example from shim.py: shim.add_menu_action('Plugins|Footnotes', 'Test Action', quick_fn, shortcut='Ctrl+T', tooltip='Test').
add_toolbar_action(action_text, callback, toolbar_name='plugins-toolbar', icon_path=None, tooltip=None, name=None):
Adds a button (action) to a specified toolbar (defaults to 'plugins-toolbar').
If the toolbar doesn't exist, creates it.
Configures the action with optional icon, tooltip, and name.
Connects the action to the callback.
Ensures the button doesn't have a popup mode (flat button).
Returns the created QAction.
Example from shim.py: shim.add_toolbar_action('Quick Action', quick_fn, tooltip='Quick fn', name='quick_action').
add_toolbar_dropdown(button_text, actions_list, toolbar_name='plugins-toolbar', icon_path=None, tooltip=None):
Adds a dropdown button to the toolbar.
actions_list is a list of dictionaries, each defining a sub-action (e.g., {'text': 'Sub1', 'callback': fn1}).
Creates a QToolButton with a QMenu for the dropdown.
Sets popup mode to instant (menu appears on click).
Returns the QToolButton.
This allows grouping related actions under one button for better UI organization.
hide_toolbar_action(name, toolbar_name='plugins-toolbar') and show_toolbar_action(name, toolbar_name='plugins-toolbar'):
Hides or shows a toolbar action by its object name.
Searches the toolbar for matching actions and toggles their visibility.
Useful for dynamic UI control (e.g., enabling/disabling features based on context).
Example from shim.py: shim.hide_toolbar_action('quick_action') followed by shim.show_toolbar_action('quick_action').
|