374 lines
13 KiB
Python
374 lines
13 KiB
Python
"""
|
|
EU-Utility - Plugins View (Core Framework Component)
|
|
|
|
Built-in plugins interface with Installed and Store tabs.
|
|
"""
|
|
|
|
from PyQt6.QtWidgets import (
|
|
QWidget, QVBoxLayout, QHBoxLayout, QLabel,
|
|
QPushButton, QCheckBox, QTabWidget, QFrame,
|
|
QScrollArea, QGridLayout, QSizePolicy
|
|
)
|
|
from PyQt6.QtCore import Qt
|
|
|
|
from core.icon_manager import get_icon_manager
|
|
|
|
|
|
class PluginsView(QWidget):
|
|
"""Main plugins interface - built into the framework.
|
|
|
|
Features:
|
|
- Installed tab: Manage installed plugins (enable/disable)
|
|
- Store tab: Browse and install new plugins
|
|
"""
|
|
|
|
def __init__(self, overlay_window, parent=None):
|
|
super().__init__(parent)
|
|
self.overlay = overlay_window
|
|
self.plugin_manager = overlay_window.plugin_manager if hasattr(overlay_window, 'plugin_manager') else None
|
|
self.icon_manager = get_icon_manager()
|
|
|
|
self._setup_ui()
|
|
|
|
def _setup_ui(self):
|
|
"""Create the plugins UI."""
|
|
layout = QVBoxLayout(self)
|
|
layout.setSpacing(16)
|
|
layout.setContentsMargins(24, 24, 24, 24)
|
|
|
|
# Header with icon
|
|
header_layout = QHBoxLayout()
|
|
header_layout.setSpacing(12)
|
|
|
|
header_icon = QLabel()
|
|
header_pixmap = self.icon_manager.get_pixmap("plugins", size=28)
|
|
header_icon.setPixmap(header_pixmap)
|
|
header_layout.addWidget(header_icon)
|
|
|
|
header = QLabel("Plugins")
|
|
header.setStyleSheet("font-size: 24px; font-weight: bold; color: white;")
|
|
header_layout.addWidget(header)
|
|
header_layout.addStretch()
|
|
|
|
layout.addLayout(header_layout)
|
|
|
|
# Tabs - Installed and Store
|
|
self.tabs = QTabWidget()
|
|
self.tabs.setStyleSheet("""
|
|
QTabBar::tab {
|
|
background-color: rgba(20, 31, 35, 0.95);
|
|
color: rgba(255,255,255,150);
|
|
padding: 10px 20px;
|
|
border-top-left-radius: 6px;
|
|
border-top-right-radius: 6px;
|
|
}
|
|
QTabBar::tab:selected {
|
|
background-color: #ff8c42;
|
|
color: white;
|
|
font-weight: bold;
|
|
}
|
|
""")
|
|
|
|
# Add tabs
|
|
self.tabs.addTab(self._create_installed_tab(), "Installed")
|
|
self.tabs.addTab(self._create_store_tab(), "Store")
|
|
|
|
layout.addWidget(self.tabs)
|
|
|
|
def _create_installed_tab(self):
|
|
"""Create installed plugins tab."""
|
|
tab = QWidget()
|
|
layout = QVBoxLayout(tab)
|
|
layout.setSpacing(16)
|
|
|
|
# Info label
|
|
info = QLabel("Manage your installed plugins. Enable or disable as needed.")
|
|
info.setStyleSheet("color: rgba(255,255,255,150); font-size: 13px;")
|
|
info.setWordWrap(True)
|
|
layout.addWidget(info)
|
|
|
|
# Scroll area for plugin list
|
|
scroll = QScrollArea()
|
|
scroll.setWidgetResizable(True)
|
|
scroll.setStyleSheet("background: transparent; border: none;")
|
|
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
|
|
|
self.installed_container = QWidget()
|
|
self.installed_layout = QVBoxLayout(self.installed_container)
|
|
self.installed_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
|
|
self.installed_layout.setSpacing(8)
|
|
|
|
self._populate_installed_plugins()
|
|
|
|
scroll.setWidget(self.installed_container)
|
|
layout.addWidget(scroll)
|
|
|
|
return tab
|
|
|
|
def _populate_installed_plugins(self):
|
|
"""Populate the installed plugins list."""
|
|
# Clear existing
|
|
while self.installed_layout.count():
|
|
item = self.installed_layout.takeAt(0)
|
|
if item.widget():
|
|
item.widget().deleteLater()
|
|
|
|
if not self.plugin_manager:
|
|
error = QLabel("Plugin Manager not available")
|
|
error.setStyleSheet("color: #ff4757;")
|
|
self.installed_layout.addWidget(error)
|
|
return
|
|
|
|
# Get discovered plugins
|
|
try:
|
|
all_plugins = self.plugin_manager.get_all_discovered_plugins()
|
|
except AttributeError:
|
|
# Fallback - try different method
|
|
try:
|
|
all_plugins = {p.plugin_id: p for p in self.plugin_manager.plugins.values()}
|
|
except:
|
|
all_plugins = {}
|
|
|
|
if not all_plugins:
|
|
no_plugins = QLabel("No plugins installed.\n\nVisit the Store tab to install plugins.")
|
|
no_plugins.setStyleSheet("color: rgba(255,255,255,100); padding: 40px;")
|
|
no_plugins.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
self.installed_layout.addWidget(no_plugins)
|
|
return
|
|
|
|
# Sort by name
|
|
sorted_plugins = sorted(all_plugins.items(), key=lambda x: x[1].name if hasattr(x[1], 'name') else str(x[0]))
|
|
|
|
for plugin_id, plugin_class in sorted_plugins:
|
|
row = QHBoxLayout()
|
|
row.setSpacing(12)
|
|
|
|
# Enable/Disable checkbox
|
|
cb = QCheckBox()
|
|
try:
|
|
is_enabled = self.plugin_manager.is_plugin_enabled(plugin_id)
|
|
except:
|
|
is_enabled = True
|
|
cb.setChecked(is_enabled)
|
|
cb.stateChanged.connect(lambda state, pid=plugin_id: self._toggle_plugin(pid, state))
|
|
row.addWidget(cb)
|
|
|
|
# Plugin info
|
|
info_layout = QVBoxLayout()
|
|
info_layout.setSpacing(2)
|
|
|
|
name_layout = QHBoxLayout()
|
|
|
|
# Name
|
|
name = QLabel(getattr(plugin_class, 'name', str(plugin_id)))
|
|
name.setStyleSheet("color: white; font-size: 14px; font-weight: 500;")
|
|
name_layout.addWidget(name)
|
|
|
|
# Version
|
|
version = getattr(plugin_class, 'version', '?.?.?')
|
|
version_label = QLabel(f"v{version}")
|
|
version_label.setStyleSheet("color: rgba(255,255,255,100); font-size: 11px;")
|
|
name_layout.addWidget(version_label)
|
|
name_layout.addStretch()
|
|
|
|
info_layout.addLayout(name_layout)
|
|
|
|
# Description
|
|
desc = getattr(plugin_class, 'description', 'No description available')
|
|
desc_label = QLabel(desc)
|
|
desc_label.setStyleSheet("color: rgba(255,255,255,120); font-size: 12px;")
|
|
desc_label.setWordWrap(True)
|
|
info_layout.addWidget(desc_label)
|
|
|
|
# Add Open/Configure buttons
|
|
btn_layout = QHBoxLayout()
|
|
|
|
# Open button
|
|
open_btn = QPushButton("Open")
|
|
open_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background: rgba(255, 140, 66, 0.2);
|
|
color: #ff8c42;
|
|
border: 1px solid rgba(255, 140, 66, 0.3);
|
|
border-radius: 4px;
|
|
padding: 4px 12px;
|
|
font-size: 11px;
|
|
}
|
|
QPushButton:hover {
|
|
background: rgba(255, 140, 66, 0.3);
|
|
}
|
|
""")
|
|
open_btn.clicked.connect(lambda checked, pid=plugin_id: self._open_plugin(pid))
|
|
btn_layout.addWidget(open_btn)
|
|
|
|
# Configure button (if plugin has settings)
|
|
if hasattr(plugin_class, 'get_settings_widget') or hasattr(plugin_class, 'settings'):
|
|
config_btn = QPushButton("Settings")
|
|
config_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background: rgba(100, 100, 100, 0.2);
|
|
color: rgba(255, 255, 255, 0.7);
|
|
border: 1px solid rgba(100, 100, 100, 0.3);
|
|
border-radius: 4px;
|
|
padding: 4px 12px;
|
|
font-size: 11px;
|
|
}
|
|
QPushButton:hover {
|
|
background: rgba(100, 100, 100, 0.3);
|
|
}
|
|
""")
|
|
config_btn.clicked.connect(lambda checked, pid=plugin_id: self._configure_plugin(pid))
|
|
btn_layout.addWidget(config_btn)
|
|
|
|
row.addLayout(btn_layout)
|
|
|
|
self.installed_layout.addLayout(row)
|
|
|
|
# Separator
|
|
sep = QFrame()
|
|
sep.setFrameShape(QFrame.Shape.HLine)
|
|
sep.setStyleSheet("background-color: rgba(255, 140, 66, 0.1);")
|
|
sep.setFixedHeight(1)
|
|
self.installed_layout.addWidget(sep)
|
|
|
|
self.installed_layout.addStretch()
|
|
|
|
def _open_plugin(self, plugin_id: str):
|
|
"""Open a plugin's main interface."""
|
|
print(f"[PluginsView] Opening plugin: {plugin_id}")
|
|
|
|
if not self.plugin_manager:
|
|
return
|
|
|
|
try:
|
|
# Get the plugin instance
|
|
plugin = self.plugin_manager.get_plugin(plugin_id)
|
|
if not plugin:
|
|
print(f"[PluginsView] Plugin not found: {plugin_id}")
|
|
return
|
|
|
|
# Check if plugin has a show_ui or open method
|
|
if hasattr(plugin, 'show_ui'):
|
|
plugin.show_ui()
|
|
elif hasattr(plugin, 'open'):
|
|
plugin.open()
|
|
elif hasattr(plugin, 'get_widget'):
|
|
widget = plugin.get_widget()
|
|
if widget:
|
|
widget.show()
|
|
widget.raise_()
|
|
widget.activateWindow()
|
|
else:
|
|
# Try to create and show the plugin's main window
|
|
print(f"[PluginsView] Plugin {plugin_id} has no standard UI method")
|
|
|
|
except Exception as e:
|
|
print(f"[PluginsView] Error opening plugin {plugin_id}: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
def _configure_plugin(self, plugin_id: str):
|
|
"""Open a plugin's settings/configuration."""
|
|
print(f"[PluginsView] Configuring plugin: {plugin_id}")
|
|
|
|
if not self.plugin_manager:
|
|
return
|
|
|
|
try:
|
|
plugin = self.plugin_manager.get_plugin(plugin_id)
|
|
if not plugin:
|
|
return
|
|
|
|
# Check for settings widget
|
|
if hasattr(plugin, 'get_settings_widget'):
|
|
settings_widget = plugin.get_settings_widget()
|
|
if settings_widget:
|
|
settings_widget.show()
|
|
settings_widget.raise_()
|
|
settings_widget.activateWindow()
|
|
elif hasattr(plugin, 'settings'):
|
|
# Open generic settings dialog
|
|
self._show_generic_settings(plugin)
|
|
|
|
except Exception as e:
|
|
print(f"[PluginsView] Error configuring plugin {plugin_id}: {e}")
|
|
|
|
def _show_generic_settings(self, plugin):
|
|
"""Show a generic settings dialog for a plugin."""
|
|
from PyQt6.QtWidgets import QDialog, QVBoxLayout, QLabel, QDialogButtonBox
|
|
|
|
dialog = QDialog(self)
|
|
dialog.setWindowTitle(f"{plugin.name} - Settings")
|
|
dialog.setMinimumSize(400, 300)
|
|
|
|
layout = QVBoxLayout(dialog)
|
|
|
|
# Plugin info
|
|
name_label = QLabel(f"<b>{plugin.name}</b>")
|
|
name_label.setStyleSheet("font-size: 16px;")
|
|
layout.addWidget(name_label)
|
|
|
|
desc_label = QLabel(plugin.description)
|
|
desc_label.setWordWrap(True)
|
|
layout.addWidget(desc_label)
|
|
|
|
version_label = QLabel(f"Version: {plugin.version}")
|
|
layout.addWidget(version_label)
|
|
|
|
layout.addStretch()
|
|
|
|
# Buttons
|
|
buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok)
|
|
buttons.accepted.connect(dialog.accept)
|
|
layout.addWidget(buttons)
|
|
|
|
dialog.exec()
|
|
|
|
def _toggle_plugin(self, plugin_id: str, state: int):
|
|
"""Enable or disable a plugin."""
|
|
if not self.plugin_manager:
|
|
return
|
|
|
|
try:
|
|
if state == Qt.CheckState.Checked.value:
|
|
self.plugin_manager.enable_plugin(plugin_id)
|
|
print(f"[PluginsView] Enabled plugin: {plugin_id}")
|
|
else:
|
|
self.plugin_manager.disable_plugin(plugin_id)
|
|
print(f"[PluginsView] Disabled plugin: {plugin_id}")
|
|
except Exception as e:
|
|
print(f"[PluginsView] Error toggling plugin {plugin_id}: {e}")
|
|
|
|
def _create_store_tab(self):
|
|
"""Create plugin store tab."""
|
|
try:
|
|
from core.plugin_store import PluginStoreUI
|
|
|
|
if self.plugin_manager:
|
|
return PluginStoreUI(self.plugin_manager)
|
|
except ImportError:
|
|
pass
|
|
|
|
# Fallback
|
|
tab = QWidget()
|
|
layout = QVBoxLayout(tab)
|
|
|
|
info = QLabel("Plugin Store")
|
|
info.setStyleSheet("font-size: 18px; font-weight: bold; color: white;")
|
|
layout.addWidget(info)
|
|
|
|
desc = QLabel("Browse and install plugins from the community repository.")
|
|
desc.setStyleSheet("color: rgba(255,255,255,150);")
|
|
desc.setWordWrap(True)
|
|
layout.addWidget(desc)
|
|
|
|
# Placeholder
|
|
placeholder = QLabel("Plugin Store interface will appear here.")
|
|
placeholder.setStyleSheet("color: rgba(255,255,255,100); padding: 40px;")
|
|
placeholder.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
layout.addWidget(placeholder)
|
|
|
|
layout.addStretch()
|
|
|
|
return tab
|