From ac85f22bb5342ab3f0abfb664a5ac6d912528e51 Mon Sep 17 00:00:00 2001 From: Triplehx3 Date: Mon, 10 Nov 2025 21:42:51 +0000 Subject: [PATCH] Implement Plugin Loading. This commit adds plugin laoding which are then added as sub winows onto the main window. This commit also adds 2 plugins however more will follow --- CMakeLists.txt | 3 + plugins/CMakeLists.txt | 2 + plugins/TerminalPlugin/CMakeLists.txt | 21 +++++ plugins/TerminalPlugin/TerminalPlugin.cpp | 38 +++++++++ plugins/TerminalPlugin/TerminalPlugin.h | 29 +++++++ plugins/TerminalPlugin/TerminalPlugin.json | 1 + plugins/WebBrowserPlugin/CMakeLists.txt | 21 +++++ plugins/WebBrowserPlugin/WebBrowserPlugin.cpp | 78 +++++++++++++++++++ plugins/WebBrowserPlugin/WebBrowserPlugin.h | 35 +++++++++ .../WebBrowserPlugin/WebBrowserPlugin.json | 1 + src/interface.h | 16 ++++ src/mainwindow.cpp | 54 +++++++++++++ src/mainwindow.h | 10 +++ 13 files changed, 309 insertions(+) create mode 100644 plugins/CMakeLists.txt create mode 100644 plugins/TerminalPlugin/CMakeLists.txt create mode 100644 plugins/TerminalPlugin/TerminalPlugin.cpp create mode 100644 plugins/TerminalPlugin/TerminalPlugin.h create mode 100644 plugins/TerminalPlugin/TerminalPlugin.json create mode 100644 plugins/WebBrowserPlugin/CMakeLists.txt create mode 100644 plugins/WebBrowserPlugin/WebBrowserPlugin.cpp create mode 100644 plugins/WebBrowserPlugin/WebBrowserPlugin.h create mode 100644 plugins/WebBrowserPlugin/WebBrowserPlugin.json create mode 100644 src/interface.h diff --git a/CMakeLists.txt b/CMakeLists.txt index da28b3e..d44b609 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ qt_add_executable(SOM src/mainwindow.cpp src/mainwindow.h src/mainwindow.ui + src/interface.h ) target_link_libraries(SOM @@ -19,6 +20,8 @@ target_link_libraries(SOM Qt::Widgets ) +add_subdirectory(plugins) + include(GNUInstallDirs) install(TARGETS SOM diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt new file mode 100644 index 0000000..2847241 --- /dev/null +++ b/plugins/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(WebBrowserPlugin) +add_subdirectory(TerminalPlugin) diff --git a/plugins/TerminalPlugin/CMakeLists.txt b/plugins/TerminalPlugin/CMakeLists.txt new file mode 100644 index 0000000..395cea0 --- /dev/null +++ b/plugins/TerminalPlugin/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.16) +project(TerminalPlugin VERSION 1.0 LANGUAGES C CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +include(GNUInstallDirs) + +find_package(QT NAMES Qt6 REQUIRED COMPONENTS Core) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui Widgets) + +qt_add_plugin(TerminalPlugin) +target_sources(TerminalPlugin PRIVATE + TerminalPlugin.cpp TerminalPlugin.h +) + +target_link_libraries(TerminalPlugin PRIVATE + Qt::Core + Qt::Gui + Qt::Widgets + qtermwidget6 +) diff --git a/plugins/TerminalPlugin/TerminalPlugin.cpp b/plugins/TerminalPlugin/TerminalPlugin.cpp new file mode 100644 index 0000000..edd9194 --- /dev/null +++ b/plugins/TerminalPlugin/TerminalPlugin.cpp @@ -0,0 +1,38 @@ +#include "TerminalPlugin.h" +#include +#include +#include + + +QString TerminalPlugin::pname() +{ + return "Terminal Plugin"; +} + +QString TerminalPlugin::pdesc() +{ + return "Simple Terminal Plugin."; +} + +QWidget* TerminalPlugin::pcontent() +{ + QWidget *test = new QWidget(); + QVBoxLayout *mainLayout = new QVBoxLayout; + console = new QTermWidget(test); + + QFont font = QApplication::font(); + font.setFamily("Monospace"); + font.setPointSize(12); + + console->setTerminalFont(font); + console->setScrollBarPosition(QTermWidget::ScrollBarRight); + console->setColorScheme("WhiteOnBlack"); + + test->setWindowTitle(tr("Terminal Plugin")); + test->resize(600, 400); + mainLayout->addWidget(console); + test->setLayout(mainLayout); + QIcon icon = QIcon(":/images/monkey.png"); + test->setWindowIcon(icon); + return test; +} diff --git a/plugins/TerminalPlugin/TerminalPlugin.h b/plugins/TerminalPlugin/TerminalPlugin.h new file mode 100644 index 0000000..60fcc55 --- /dev/null +++ b/plugins/TerminalPlugin/TerminalPlugin.h @@ -0,0 +1,29 @@ +#ifndef TESTPLUGIN_H +#define TESTPLUGIN_H + + +#include <../../src/interface.h> +#include + +#include +#include +#include +#include +#include + +class TerminalPlugin : public QObject, public Interface +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.SOM.Interface" FILE "TerminalPlugin.json") + Q_INTERFACES(Interface) + +public: + QString pname() override; + QString pdesc() override; + QWidget *pcontent() override; + +private: + QTermWidget *console; + +}; +#endif diff --git a/plugins/TerminalPlugin/TerminalPlugin.json b/plugins/TerminalPlugin/TerminalPlugin.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/plugins/TerminalPlugin/TerminalPlugin.json @@ -0,0 +1 @@ +{} diff --git a/plugins/WebBrowserPlugin/CMakeLists.txt b/plugins/WebBrowserPlugin/CMakeLists.txt new file mode 100644 index 0000000..0a6012d --- /dev/null +++ b/plugins/WebBrowserPlugin/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.16) +project(WebBrowserPlugin VERSION 1.0 LANGUAGES C CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +include(GNUInstallDirs) + +find_package(QT NAMES Qt6 REQUIRED COMPONENTS Core) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui WebEngineWidgets Widgets) + +qt_add_plugin(WebBrowserPlugin) +target_sources(WebBrowserPlugin PRIVATE + WebBrowserPlugin.cpp WebBrowserPlugin.h +) + +target_link_libraries(WebBrowserPlugin PRIVATE + Qt::Core + Qt::Gui + Qt::WebEngineWidgets + Qt::Widgets +) diff --git a/plugins/WebBrowserPlugin/WebBrowserPlugin.cpp b/plugins/WebBrowserPlugin/WebBrowserPlugin.cpp new file mode 100644 index 0000000..1bc8579 --- /dev/null +++ b/plugins/WebBrowserPlugin/WebBrowserPlugin.cpp @@ -0,0 +1,78 @@ +#include "WebBrowserPlugin.h" +#include +#include + +QString WebBrowserPlugin::pname() +{ + return "Web Browser Plugin"; +} + +QString WebBrowserPlugin::pdesc() +{ + return "Simple Web Browser Plugin."; +} + +QWidget* WebBrowserPlugin::pcontent() +{ + QWidget *test = new QWidget(); + test->setWindowTitle(tr("Web Browser Plugin")); + test->resize(1024, 750); + QVBoxLayout *mainLayout = new QVBoxLayout; + + view = new QWebEngineView(test); + view->setUrl(QUrl("https://rubenwardy.com/minetest_modding_book/en/index.html")); + view->resize(1024, 750); + + horizontalGroupBox = new QGroupBox(); + QHBoxLayout *layout = new QHBoxLayout; + back = new QPushButton(tr("Back")); + layout->addWidget(back); + connect(back, &QPushButton::clicked, this, &WebBrowserPlugin::backpage); + + forward = new QPushButton(tr("Forward")); + layout->addWidget(forward); + connect(forward, &QPushButton::clicked, this, &WebBrowserPlugin::forwardpage); + + refresh = new QPushButton(tr("Refresh")); + layout->addWidget(refresh); + connect(refresh, &QPushButton::clicked, this, &WebBrowserPlugin::refreshpage); + + smallEditor = new QLineEdit; + layout->addWidget(smallEditor); + smallEditor->setText("https://rubenwardy.com/minetest_modding_book/en/index.html"); + + go = new QPushButton(tr("Go")); + layout->addWidget(go); + connect(go, &QPushButton::clicked, this, &WebBrowserPlugin::gotourl); + + horizontalGroupBox->setLayout(layout); + + + mainLayout->addWidget(horizontalGroupBox); + mainLayout->addWidget(view,1); + test->setLayout(mainLayout); + + QIcon icon = QIcon(":/images/monkey.png"); + test->setWindowIcon(icon); + return test; +} + +void WebBrowserPlugin::gotourl() +{ + view->setUrl(QUrl(smallEditor->text())); +} + +void WebBrowserPlugin::refreshpage() +{ + view->reload(); +} + +void WebBrowserPlugin::backpage() +{ + view->back(); +} + +void WebBrowserPlugin::forwardpage() +{ + view->forward(); +} diff --git a/plugins/WebBrowserPlugin/WebBrowserPlugin.h b/plugins/WebBrowserPlugin/WebBrowserPlugin.h new file mode 100644 index 0000000..ceb681b --- /dev/null +++ b/plugins/WebBrowserPlugin/WebBrowserPlugin.h @@ -0,0 +1,35 @@ +#ifndef WEBBROWSERPLUGIN_H +#define WEBBROWSERPLUGIN_H + + +#include <../../src/interface.h> +#include +#include + +class WebBrowserPlugin : public QObject, public Interface +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.SOM.Interface" FILE "WebBrowserPlugin.json") + Q_INTERFACES(Interface) + +public: + QString pname() override; + QString pdesc() override; + QWidget *pcontent() override; + +private: + QGroupBox *horizontalGroupBox; + QPushButton *back; + QPushButton *forward; + QPushButton *refresh; + QLineEdit *smallEditor; + QPushButton *go; + QWebEngineView *view; + +private slots: + void gotourl(); + void refreshpage(); + void backpage(); + void forwardpage(); +}; +#endif diff --git a/plugins/WebBrowserPlugin/WebBrowserPlugin.json b/plugins/WebBrowserPlugin/WebBrowserPlugin.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/plugins/WebBrowserPlugin/WebBrowserPlugin.json @@ -0,0 +1 @@ +{} diff --git a/src/interface.h b/src/interface.h new file mode 100644 index 0000000..1bacacc --- /dev/null +++ b/src/interface.h @@ -0,0 +1,16 @@ +#include + +#include +#include + +class Interface +{ +public: + virtual ~Interface() = default; + virtual QString pname() = 0; + virtual QString pdesc() = 0; + virtual QWidget* pcontent() = 0; +}; + +#define Interface_iid "org.SOM.Interface/1.0" +Q_DECLARE_INTERFACE(Interface, Interface_iid) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 8ff7a49..eb25c26 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -10,6 +10,9 @@ MainWindow::MainWindow(QWidget *parent) createMenus(); this->setWindowIcon(QIcon::fromTheme(QIcon::ThemeIcon::Computer)); initSettings(); + mdi = new QMdiArea; + this->setCentralWidget(mdi); + loadPlugins(); } MainWindow::~MainWindow() @@ -90,3 +93,54 @@ void MainWindow::settings() settingsWin->resize(300, 200); settingsWin->show(); } + +void MainWindow::loadPlugins() +{ + pluginsDir = QDir(QCoreApplication::applicationDirPath()); + pluginsDir.cd("plugins"); + + const auto entryList = pluginsDir.entryList(QDir::Files); + for (const QString &fileName : entryList) { + + QPluginLoader loader(pluginsDir.absoluteFilePath(fileName)); + QObject *plugin = loader.instance(); + if (plugin) { + + populateMenu(plugin); + pluginFileNames += fileName; + } + } +} + +void MainWindow::changePlugin() +{ + auto action = qobject_cast(sender()); + if (!action) + return; + + auto iPlugin = qobject_cast(action->parent()); + if (!iPlugin) + return; + + QWidget* pluginContent = iPlugin->pcontent(); + auto *sub = mdi->addSubWindow(pluginContent); + sub->setAttribute(Qt::WA_DeleteOnClose); + sub->show(); +} + +void MainWindow::populateMenu(QObject *plugin) +{ + + auto iPlugin = qobject_cast(plugin); + if (iPlugin) + + addToMenu(plugin, iPlugin->pname(), toolsMenu, &MainWindow::changePlugin); +} + +void MainWindow::addToMenu(QObject *plugin, const QString &text, + QMenu *menu, Member member) +{ + auto action = new QAction(text, plugin); + connect(action, &QAction::triggered, this, member); + menu->addAction(action); +} diff --git a/src/mainwindow.h b/src/mainwindow.h index d581bb8..0c95726 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -4,6 +4,8 @@ #include #include +#include "interface.h" + QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; @@ -22,11 +24,15 @@ public: ~MainWindow(); private: + typedef void (MainWindow::*Member)(); Ui::MainWindow *ui; void createActions(); void createMenus(); void initSettings(); void saveSettings(); + void loadPlugins(); + void populateMenu(QObject *plugin); + void addToMenu(QObject *plugin, const QString &text, QMenu *menu,Member member); QMenu *fileMenu; QMenu *editMenu; QMenu *toolsMenu; @@ -35,10 +41,14 @@ private: QAction *aboutAct; QAction *aboutQtAct; QAction *settingsAct; + QStringList pluginFileNames; + QDir pluginsDir; + QMdiArea *mdi; private slots: void about(); void settings(); + void changePlugin(); protected: void closeEvent(QCloseEvent *event) override;