Skip to content

Commit

Permalink
New UI for plugin management, stored/retrieved plugin states and new …
Browse files Browse the repository at this point in the history
…PluginWrapper for UI
  • Loading branch information
Rexeh committed Jan 30, 2024
1 parent 1ffe61a commit 34e9413
Show file tree
Hide file tree
Showing 11 changed files with 893 additions and 246 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ htmlcov
/data
.ruff*
/local_test_data
test_export/

# IDE
*.code-workspace
Expand Down
5 changes: 2 additions & 3 deletions joystick_diagrams/db/db_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
Author: Robert Cox
"""

from db import db_device_management

from joystick_diagrams.db import db_value_store
from joystick_diagrams.db import db_device_management, db_plugin_data, db_value_store


def init():
db_device_management.create_new_db_if_not_exist()
db_value_store.create_new_db_if_not_exist()
db_plugin_data.create_new_db_if_not_exist()


if __name__ == "__main__":
Expand Down
55 changes: 55 additions & 0 deletions joystick_diagrams/db/db_plugin_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import os
from sqlite3 import connect

DB_DIR = "data"
DB_NAME = "plugins.db"
TABLE_NAME = "plugins"


def create_new_db_if_not_exist():
path = os.path.join(os.getcwd(), DB_DIR, DB_NAME)
connection = connect(path)
cur = connection.cursor()
cur.execute(f"CREATE TABLE IF NOT EXISTS {TABLE_NAME}(plugin_name TEXT PRIMARY KEY, enabled BOOL)")


def add__update_plugin_configuration(plugin_name: str, enabled: bool):
path = os.path.join(os.getcwd(), DB_DIR, DB_NAME)
connection = connect(path)
cur = connection.cursor()

query = "SELECT * from plugins WHERE plugin_name = ?"
params = (plugin_name,)

cur.execute(query, params)
result = cur.fetchall()

if result:
query = "UPDATE plugins SET enabled = ? WHERE plugin_name = ? "
params = (enabled, plugin_name)
cur.execute(query, params)

else:
query = "INSERT INTO plugins (plugin_name, enabled) VALUES(?,?)"
params = (plugin_name, enabled)
cur.execute(query, params)

connection.commit()


def get_plugin_configuration(plugin_name: str):
path = os.path.join(os.getcwd(), DB_DIR, DB_NAME)
connection = connect(path)
cur = connection.cursor()

query = "SELECT * from plugins WHERE plugin_name = ?"
params = [plugin_name]

cur.execute(query, params)
result = cur.fetchone()

return result if result else None


if __name__ == "__main__":
pass
149 changes: 149 additions & 0 deletions joystick_diagrams/ui/mock_main/plugin_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import logging
import sys
from pathlib import Path

from PySide6.QtCore import QMetaMethod, Qt, Signal, Slot
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import (
QApplication,
QFileDialog,
QListWidgetItem,
QMainWindow,
QMessageBox,
)
from qt_material import apply_stylesheet

from joystick_diagrams import app_init
from joystick_diagrams.app_state import AppState
from joystick_diagrams.exceptions import JoystickDiagramsException
from joystick_diagrams.plugins.plugin_interface import PluginInterface
from joystick_diagrams.ui.mock_main.qt_designer import plugin_settings_ui
from joystick_diagrams.ui.plugin_wrapper import PluginWrapper

_logger = logging.getLogger(__name__)

RECONFIGURE_TEXT = "Reconfigure"


class PluginSettings(QMainWindow, plugin_settings_ui.Ui_Form): # Refactor pylint: disable=too-many-instance-attributes
pluginModified = Signal(object)
pluginPathConfigured = Signal(object)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setupUi(self)
self.plugin = None

# Attributes

# Connections
self.pluginEnabled.stateChanged.connect(self.handle_enabled_change)
self.configureLink.clicked.connect(self.open_file_dialog)

# Setup

# Style Overrides
self.configureLink.setStyleSheet("color: white !important;")

def setup(self):
"""Initialise the widget configuration"""

# Setup labels
self.pluginEnabled.setChecked(self.plugin.enabled)
self.plugin_name_label.setText(self.plugin.plugin_name)
self.plugin_version_label.setText(self.plugin.plugin_version)

# Setup file selection
self.configureLink.setText(self.get_plugin_path_type().dialog_title)
self.configureLink.setDescription("")

if self.plugin.plugin.path:
self.set_plugin_path(self.plugin.plugin.path)

# TODO if file already set from storage...

def handle_enabled_change(self, data):
self.plugin.enabled = data if data == 0 else 1
print(f"Plugin enabled state is now {self.plugin.enabled}")
self.pluginModified.emit(self.plugin)

def get_plugin_file_extensions(self):
return []

def get_plugin_path_type(self) -> PluginInterface.FilePath | PluginInterface.FolderPath:
return self.plugin.plugin.path_type

def set_plugin_path(self, path: Path):
if not isinstance(path, Path):
return

try:
load = self.plugin.plugin.set_path(path)

if not load:
raise JoystickDiagramsException("Error loading plugin")
if load:
self.configureLink.setText(RECONFIGURE_TEXT)
self.configureLink.setDescription(path.__str__())
self.pluginPathConfigured.emit(self.plugin)
except JoystickDiagramsException:
QMessageBox.warning(
self,
"Plugin failure",
"Something went very wrong.",
buttons=QMessageBox.Discard,
defaultButton=QMessageBox.Discard,
)

def open_file_dialog(self) -> None:
plugin_path = self.get_plugin_path_type()

match type(plugin_path):
case PluginInterface.FilePath:
exts = " ".join(f"*{ext}" for ext in plugin_path.supported_extensions)

_file = QFileDialog.getOpenFileName(
self,
caption=plugin_path.dialog_title,
dir=plugin_path.default_path,
filter=(f"All Files ({exts})"),
)

if _file[0]:
self.set_plugin_path(Path(_file[0]))
case PluginInterface.FolderPath:
_folder = QFileDialog.getExistingDirectory(self, plugin_path.dialog_title, plugin_path.default_path)
if _folder:
self.set_plugin_path(Path(_folder))
case _:
_logger.error("Unexpected plugin path type given.")

# def load_plugin_settings(self, data):


# self.pluginVersionInfo.setText(f"Version {data.version}")
# self.pluginName.setText(f"{data.name} Settings")

# # Path Setup
# self.pluginPath.setText(data.path)

# # Prevents duplicate signals from being connected
# if self.pluginPathButton.isSignalConnected(QMetaMethod.fromSignal(self.pluginPathButton.clicked)):
# self.pluginPathButton.clicked.disconnect()

# # Clean up
# # Additional validation to be added to PluginInterface/Plugin loading
# if isinstance(data.path_type, PluginInterface.FilePath):
# self.pluginPathButton.clicked.connect(lambda: self.file_dialog(data.path_type))

# if isinstance(data.path_type, PluginInterface.FolderPath):
# self.pluginPathButton.clicked.connect(lambda: self.folder_dialog(data.path_type))


if __name__ == "__main__":
app = QApplication(sys.argv)
init = app_init.init()
window = PluginSettings()
window.show()
apply_stylesheet(app, theme="dark_blue.xml", invert_secondary=False)
app.exec()
116 changes: 116 additions & 0 deletions joystick_diagrams/ui/mock_main/qt_designer/plugin_settings_ui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-

################################################################################
## Form generated from reading UI file 'plugin_settings_ui.ui'
##
## Created by: Qt User Interface Compiler version 6.6.1
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################

from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QCheckBox, QCommandLinkButton, QFrame,
QHBoxLayout, QLabel, QSizePolicy, QSpacerItem,
QVBoxLayout, QWidget)

class Ui_Form(object):
def setupUi(self, Form):
if not Form.objectName():
Form.setObjectName(u"Form")
Form.resize(750, 596)
Form.setMaximumSize(QSize(750, 600))
self.verticalLayoutWidget = QWidget(Form)
self.verticalLayoutWidget.setObjectName(u"verticalLayoutWidget")
self.verticalLayoutWidget.setGeometry(QRect(9, 9, 731, 87))
self.verticalLayout_3 = QVBoxLayout(self.verticalLayoutWidget)
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.plugin_name_label = QLabel(self.verticalLayoutWidget)
self.plugin_name_label.setObjectName(u"plugin_name_label")
font = QFont()
font.setPointSize(12)
self.plugin_name_label.setFont(font)

self.horizontalLayout.addWidget(self.plugin_name_label)

self.plugin_version_label = QLabel(self.verticalLayoutWidget)
self.plugin_version_label.setObjectName(u"plugin_version_label")

self.horizontalLayout.addWidget(self.plugin_version_label)


self.verticalLayout_3.addLayout(self.horizontalLayout)

self.horizontalLayout_2 = QHBoxLayout()
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
self.pluginEnabled = QCheckBox(self.verticalLayoutWidget)
self.pluginEnabled.setObjectName(u"pluginEnabled")
sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pluginEnabled.sizePolicy().hasHeightForWidth())
self.pluginEnabled.setSizePolicy(sizePolicy)
font1 = QFont()
font1.setPointSize(14)
self.pluginEnabled.setFont(font1)

self.horizontalLayout_2.addWidget(self.pluginEnabled)

self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum)

self.horizontalLayout_2.addItem(self.horizontalSpacer)

self.configureLink = QCommandLinkButton(self.verticalLayoutWidget)
self.configureLink.setObjectName(u"configureLink")
sizePolicy1 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
sizePolicy1.setHorizontalStretch(0)
sizePolicy1.setVerticalStretch(0)
sizePolicy1.setHeightForWidth(self.configureLink.sizePolicy().hasHeightForWidth())
self.configureLink.setSizePolicy(sizePolicy1)
self.configureLink.setStyleSheet(u"color: rgb(255, 255, 255);\n"
"selection-color: rgb(255, 255, 255);")

self.horizontalLayout_2.addWidget(self.configureLink)


self.verticalLayout_3.addLayout(self.horizontalLayout_2)

self.frame = QFrame(Form)
self.frame.setObjectName(u"frame")
self.frame.setGeometry(QRect(9, 102, 116, 33))
self.frame.setAutoFillBackground(False)
self.frame.setFrameShape(QFrame.Box)
self.frame.setFrameShadow(QFrame.Plain)
self.frame.setLineWidth(0)
self.frame.setMidLineWidth(1)
self.verticalLayout_2 = QVBoxLayout(self.frame)
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
self.label_3 = QLabel(self.frame)
self.label_3.setObjectName(u"label_3")

self.verticalLayout_2.addWidget(self.label_3)


self.retranslateUi(Form)

QMetaObject.connectSlotsByName(Form)
# setupUi

def retranslateUi(self, Form):
Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None))
self.plugin_name_label.setText(QCoreApplication.translate("Form", u"Plugin_Name", None))
self.plugin_version_label.setText(QCoreApplication.translate("Form", u"TextLabel", None))
self.pluginEnabled.setText(QCoreApplication.translate("Form", u"Enable Plugin", None))
self.configureLink.setText(QCoreApplication.translate("Form", u"Configure plugin", None))
self.configureLink.setDescription(QCoreApplication.translate("Form", u"Select your file/folder", None))
self.label_3.setText(QCoreApplication.translate("Form", u"No options available", None))
# retranslateUi

Loading

0 comments on commit 34e9413

Please sign in to comment.