"""
This module defines the `PluginCollection` class responsible for managing a collection
of plugins within a PyQt6 application.
"""
import inspect
import os
import pkgutil
import sys
from src.plugin_interface import PluginInterface
sys.path.append("..")
[docs]
class PluginCollection:
"""
A class for managing a collection of plugins within a PyQt6 application.
Attributes:
_plugins (list): A list to store instances of plugin classes.
name_application (list): A list to store names of plugins.
_seen_paths (list): A list to keep track of paths already visited during package scanning.
path_folder (list): A list to store the module paths of plugins.
plugin_package (str): The name of the package containing plugins.
"""
def __init__(self, plugin_package):
self._plugins = None
self.name_application = None
self._seen_paths = None
self.path_folder = None
self.plugin_package = plugin_package
self.reload_plugins()
[docs]
def reload_plugins(self):
"""
Reload the plugins from the specified package.
This function clears the existing plugin list, name list, and folder path list, then
walks through the plugin package and appends any valid plugins to the plugin list.
"""
self._plugins = []
self.name_application = []
self._seen_paths = []
self.path_folder = []
self.walk_package(self.plugin_package)
[docs]
def set_always_pop_up(self, index):
"""
Set the "always popup" property of the plugin at the specified index.
Arg:
index (int): The index of the plugin.
Return:
The value of the "always popup" property for the plugin.
"""
return self._plugins[index].always_pop_up()
[docs]
def get_icon_(self, index):
"""
Return the path of the icon for a given plugin index.
Arg:
index (int): The index of the plugin.
Return:
str or None: The path to the icon file, or None if the plugin has no icon.
"""
path_file = os.path.abspath(".")
icon_source = self._plugins[index].set_icon_apps()
if icon_source is not None:
if icon_source[0] == ".":
icon_source.replace("./", "")
elif icon_source[0] == "/":
icon_source.replace("/", "")
folder = self.path_folder[index]
path = folder.split(".")[1]
path = path_file + '/plugins/' + path + "/" + icon_source
else:
path = None
return path
[docs]
def change_theme(self, index):
"""
Change the stylesheet of the plugin at the given index to the current theme.
Arg:
index (int): The index of the plugin to update.
Return:
None
"""
if len(self._plugins) > 0:
self._plugins[index].change_stylesheet()
[docs]
def get_description(self, index):
"""
Get the description of the plugin at the specified index.
Arg:
index (int): The index of the plugin.
Return:
str: The description of the plugin.
"""
return self._plugins[index].description
[docs]
def walk_package(self, package):
"""
Walk through the specified package and its sub-packages to find all classes
that are a subclass of PluginInterface and add them to the list of plugins.
Arg:
package (str): The name of the package to search for plugins in.
"""
path_file = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, path_file)
imported_package = __import__(package, fromlist=['blah'])
for _, plugin_name, is_pkg in pkgutil.iter_modules(
imported_package.__path__, imported_package.__name__ + '.'):
if not is_pkg:
try:
plugin_module = __import__(plugin_name, fromlist=['blah'])
cls_members = inspect.getmembers(plugin_module, inspect.isclass)
for (_, c) in cls_members:
# only add classes that are a subclass of plugins, but not
# plugins itself
if issubclass(c, PluginInterface) and c is not PluginInterface:
# print(f'Found Plugin class: {c.__name__}')
self.path_folder.append(c.__module__)
self.name_application.append(c.__name__)
self._plugins.append(c())
except ImportError as err:
print("Your will get problem because: " + str(err))
# Now that we have looked at all the modules in the current package, start looking
# recursively for additional modules in sub packages
all_current_paths = list(imported_package.__path__)
for pkg_path in all_current_paths:
if pkg_path not in self._seen_paths:
self._seen_paths.append(pkg_path)
# get subdirectory of current package path directory
child_pkgs = [
p for p in os.listdir(pkg_path) if os.path.isdir(
os.path.join(
pkg_path, p)) and p[0] != '.']
# For each subdirectory, apply the walk_package method
# recursively
for child_pkg in child_pkgs:
self.walk_package(package + '.' + child_pkg)