diff options
-rw-r--r-- | lib/configuration/configuration.cpp | 7 | ||||
-rw-r--r-- | lib/configuration/configuration.h | 12 | ||||
-rw-r--r-- | plugins/interfaces.h | 2 | ||||
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/browser.cpp | 115 | ||||
-rw-r--r-- | src/browser.h | 14 | ||||
-rw-r--r-- | src/main.cpp | 66 | ||||
-rw-r--r-- | src/plugin.h | 93 |
8 files changed, 164 insertions, 147 deletions
diff --git a/lib/configuration/configuration.cpp b/lib/configuration/configuration.cpp index 6d8d1ba..e767c65 100644 --- a/lib/configuration/configuration.cpp +++ b/lib/configuration/configuration.cpp @@ -50,10 +50,7 @@ Configuration::Configuration() ("config,c", po::value<std::string>()->default_value(defaultUserConfigLocation()), "Set the configuration file.") ("socket,s", po::value<std::string>()->default_value(defaultSocketPath()), "Local server socket") - ("command", po::value<std::string>(), "Run a plugin command.") - ("commands", "List all plugin commands.") - - ("url", po::value<std::vector<std::string>>(), "URLs") + ("args", po::value<std::vector<std::string>>(), "arguments") ; configuration_desc.add_options() @@ -123,7 +120,7 @@ Configuration::Configuration() ("downloads.shortcut", po::value<std::string>()->default_value("Ctrl+D")) ; - arguments_desc.add("url", -1); + arguments_desc.add("args", -1); } Configuration::~Configuration() = default; diff --git a/lib/configuration/configuration.h b/lib/configuration/configuration.h index 59c837c..bb1b271 100644 --- a/lib/configuration/configuration.h +++ b/lib/configuration/configuration.h @@ -75,18 +75,6 @@ public: return std::optional<T>(vm[path].as<T>()); } - QStringList positionalArguments() const - { - QStringList l; - if(vm.count("url")) { - std::vector<std::string> urls = vm["url"].as<std::vector<std::string>>(); - for(const std::string &s : urls) { - l.append(QString::fromStdString(s)); - } - } - return l; - } - QHash<QString, QString> section(const std::string &prefix) const; const boost::program_options::options_description commandlineOptions() const { diff --git a/plugins/interfaces.h b/plugins/interfaces.h index 67cd3c6..1a12f02 100644 --- a/plugins/interfaces.h +++ b/plugins/interfaces.h @@ -24,7 +24,7 @@ struct Plugin QString name; QString author; QKeySequence shortcut; - std::shared_ptr<QObject> instance; + QObject *instance; }; class PluginInterface diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 00b556f..5f4aed1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -43,7 +43,7 @@ add_executable(poi webengine/widgets/pagemenu.h # plugin interfaces - #../plugins/interfaces.h + plugin.h ) target_include_directories(poi diff --git a/src/browser.cpp b/src/browser.cpp index 29a02b7..f2c7314 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -24,64 +24,6 @@ #include <QJsonArray> #include <about/aboutdialog.h> -inline Plugin loadPluginFromPath(const QString &path) -{ - Plugin p; - QPluginLoader loader(path); - - if(loader.load()) { -#ifdef QT_DEBUG - qDebug("Loading plugin: %s [ok]", qUtf8Printable(path)); -#endif - - auto meta = loader.metaData().value("MetaData").toObject(); - p.name = meta.value("name").toString(); - p.author = meta.value("author").toString(); - p.shortcut = QKeySequence::fromString(meta.value("shortcut").toString()); - - p.instance = std::shared_ptr<QObject>(loader.instance()); - - } else { - qDebug("Loading pluing: %s [failed]", qUtf8Printable(path)); - qDebug("%s", qUtf8Printable(loader.errorString())); - } - - return p; -} - -inline QVector<Plugin> loadPlugins(const QString &path) -{ - QVector<Plugin> list; - QFileInfo location(path); - if(!location.exists()) { - qDebug("Plugin location doesn't exist."); - return list; - } - - if(location.isFile()) { - // only load this one plugin - auto p = loadPluginFromPath(location.absoluteFilePath()); - if(p.instance) - list.append(p); - - } else if(location.isDir()) { - // load all profiles from this directory - const auto entries = QDir(location.absoluteFilePath()).entryInfoList(QDir::Files | QDir::Readable); - for(const auto &f : entries) { - auto p = loadPluginFromPath(f.absoluteFilePath()); - if(p.instance) - list.append(p); - } - - } else { -#ifdef QT_DEBUG - qDebug("Path is neither file nor folder: %s", qUtf8Printable(path)); -#endif - } - - return list; -} - Browser::Browser(int &argc, char *argv[]) : SingleApplication(argc, argv) { @@ -96,10 +38,7 @@ Browser::~Browser() m_bookmarks->save(); qDeleteAll(m_windows); - m_windows.clear(); - - //qDeleteAll(m_plugins); - m_plugins.clear(); + m_windows.clear(); } @@ -118,31 +57,27 @@ void Browser::setConfiguration(std::shared_ptr<Configuration> &config) m_config = config; } -void Browser::setup(const QString &defaultProfile) +void Browser::registerPlugin(const Plugin &plugin) { - Q_ASSERT_X(m_config, "Browser::setup", "Configuration not set"); - - // load plugins first - m_plugins.append(loadPlugins(QString::fromStdString(m_config->value<std::string>("plugins.path").value()))); + if(plugin.instance->inherits("ProfileInterface")) { + auto *profileEditor = qobject_cast<ProfileInterface *>(plugin.instance); + Q_ASSERT_X(profileEditor != nullptr, "Browser::setup", "profile interface cast failed"); - // register commands - for(const Plugin &p : qAsConst(m_plugins)) { - - if(p.instance->inherits("ProfileInterface")) { - auto *profileEditor = qobject_cast<ProfileInterface *>(p.instance.get()); - Q_ASSERT_X(profileEditor != nullptr, "Browser::setup", "profile interface cast failed"); - - connect(this, &Browser::registerProfile, [=](WebProfile *profile) { - profileEditor->registerProfile(profile); - }); - } - - auto *plugin = qobject_cast<PluginInterface *>(p.instance.get()); - if(plugin) { - m_commands.unite(plugin->commands()); + for(auto it = m_profiles.constBegin(); it != m_profiles.constEnd(); ++it) { + profileEditor->registerProfile(it.value()); } + connect(this, &Browser::registerProfile, [=](WebProfile *profile) { + profileEditor->registerProfile(profile); + }); } + m_plugins.append(plugin); +} + +void Browser::setup(const QString &defaultProfile) +{ + Q_ASSERT_X(m_config, "Browser::setup", "Configuration not set"); + // load profiles { const auto defaults = m_config->section("profile"); @@ -203,16 +138,6 @@ WebProfile *Browser::profile(const QString &name) const return nullptr; } -int Browser::command(const QString &command) -{ - if(m_commands.contains(command)) { - return m_commands.value(command)(); - } else { - qWarning("No such command: %s", qUtf8Printable(command)); - return -1; - } -} - void Browser::createSession(const QString &profileName, bool newWindow, const QStringList &urls) { if(m_windows.isEmpty()) { @@ -249,7 +174,7 @@ MainWindow *Browser::createWindow() bookmarksAction->setShortcut(QKeySequence(QString::fromStdString(m_config->value<std::string>("bookmarks.shortcut").value()))); connect(bookmarksAction, &QAction::triggered, window, [this, window]() { bool wasVisible = m_bookmarks->isVisible(); - for(MainWindow *w : m_windows) { + for(MainWindow *w : qAsConst(m_windows)) { w->removeDockWidget(m_bookmarks.get()); } if(!wasVisible) { @@ -262,7 +187,7 @@ MainWindow *Browser::createWindow() downloadsAction->setShortcut(QKeySequence(QString::fromStdString(m_config->value<std::string>("downloads.shortcut").value()))); connect(downloadsAction, &QAction::triggered, window, [this, window]() { bool wasVisible = m_downloads->isVisible(); - for(MainWindow *w : m_windows) { + for(MainWindow *w : qAsConst(m_windows)) { w->removeDockWidget(m_downloads.get()); } if(!wasVisible) { @@ -273,7 +198,7 @@ MainWindow *Browser::createWindow() for(const Plugin &p : qAsConst(m_plugins)) { if(p.instance->inherits("ProfileInterface")) { - auto *profileEditor = qobject_cast<ProfileInterface *>(p.instance.get()); + auto *profileEditor = qobject_cast<ProfileInterface *>(p.instance); auto *profileAction = new QAction(tr("Profile"), window); profileAction->setShortcut(p.shortcut); connect(profileAction, &QAction::triggered, window, [profileEditor]() { diff --git a/src/browser.h b/src/browser.h index 7163c8f..821583a 100644 --- a/src/browser.h +++ b/src/browser.h @@ -38,6 +38,8 @@ public slots: public: void setConfiguration(std::shared_ptr<Configuration> &config); + void registerPlugin(const Plugin &plugin); + void setup(const QString &defaultProfile); std::shared_ptr<BookmarksWidget> bookmarks() @@ -51,17 +53,6 @@ public: return m_profiles.keys(); } - int command(const QString &command); - const QStringList commands() const - { - return m_commands.keys(); - } - - const QVector<Plugin> plugins() const - { - return m_plugins; - } - signals: void registerProfile(WebProfile *profile); @@ -78,7 +69,6 @@ private: QMap<QString, WebProfile*> m_profiles; QVector<MainWindow *> m_windows; QVector<Plugin> m_plugins; - QHash<QString, std::function<int()>> m_commands; }; #endif // SMOLBOTE_BROWSER_H diff --git a/src/main.cpp b/src/main.cpp index c9b6007..c1060aa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,24 +12,53 @@ #include <configuration/configuration.h> #include <memory> #include <iostream> +#include "plugin.h" int main(int argc, char **argv) { // create and load configuration std::shared_ptr<Configuration> config = std::make_shared<Configuration>(); if(!config->parse(argc, argv)) { - qWarning("Check --help for usage."); + qWarning("Error parsing command line, check --help for usage."); return -1; } if(!config->parse(config->value<std::string>("config").value())) { qWarning("Error parsing config file."); } + // --version + if(config->exists("version")) { + std::cout << "smolbote " << SMOLBOTE_VERSION << std::endl; + return 0; + } + + // --build + if(config->exists("build")) { + std::cout << SMOLBOTE_BRANCH << ":" << SMOLBOTE_COMMIT; + return 0; + } + + QVector<Plugin> plugins = loadPlugins(config->value<QString>("plugins.path").value()); + QHash<QString, std::function<int()>> pluginCommands; + for(const auto &plugin : plugins) { + auto *pluginInterface = qobject_cast<PluginInterface*>(plugin.instance); + Q_CHECK_PTR(pluginInterface); + + pluginCommands.unite(pluginInterface->commands()); + } + if(config->exists("help")) { std::cout << "smolbote " << SMOLBOTE_VERSION << ": yet another no-frills browser" << std::endl; - std::cout << "Usage: " << argv[0] << " [options] URL(s)" << std::endl << std::endl; + std::cout << "Usage: " << argv[0] << " [options] [command/URL(s)]" << std::endl << std::endl; std::cout << "Command-line Options: " << std::endl << config->commandlineOptions() << std::endl; + + std::cout << "Commands: " << std::endl; + for(auto it = pluginCommands.constBegin(); it != pluginCommands.constEnd(); ++it) { + std::cout << it.key().toStdString() << std::endl; + } + std::cout << std::endl; + std::cout << "Configuration Options: " << std::endl << config->configurationOptions() << std::endl; #ifdef Q_OS_LINUX @@ -38,32 +67,27 @@ int main(int argc, char **argv) return 0; } - if(config->exists("version")) { - std::cout << "smolbote " << SMOLBOTE_VERSION << std::endl; - return 0; - } - - if(config->exists("build")) { - std::cout << SMOLBOTE_BRANCH << ":" << SMOLBOTE_COMMIT; - return 0; - } - Browser app(argc, argv); // set this, otherwise the webview becomes black when using a stylesheet app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true); app.setConfiguration(config); app.setup(QString::fromStdString(config->value<std::string>("profile.default").value())); - - if(config->exists("commands")) { - for(const QString &cmd : app.commands()) { - std::cout << cmd.toStdString() << std::endl; - } - exit(0); + for(const Plugin &plugin : plugins) { + app.registerPlugin(plugin); } - if(config->exists("command")) { - exit(app.command(QString::fromStdString(config->value<std::string>("command").value()))); + auto arguments = config->value<std::vector<std::string>>("args"); + QStringList urls; + + if(arguments) { + for(const auto &u : arguments.value()) { + if(pluginCommands.contains(QString::fromStdString(u))) { + return pluginCommands.value(QString::fromStdString(u))(); + } else { + urls.append(QString::fromStdString(u)); + } + } } // set up socket @@ -86,7 +110,7 @@ int main(int argc, char **argv) QObject::connect(&app, &Browser::messageAvailable, &app, &Browser::createSession); } - app.sendMessage("", false, config->positionalArguments()); + app.sendMessage("", false, urls); if(isSingleInstance) return app.exec(); else diff --git a/src/plugin.h b/src/plugin.h new file mode 100644 index 0000000..4de3407 --- /dev/null +++ b/src/plugin.h @@ -0,0 +1,93 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: https://neueland.iserlohn-fortress.net/smolbote.hg + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#ifndef SMOLBOTE_PLUGIN_H +#define SMOLBOTE_PLUGIN_H + +#include <interfaces.h> +#include <QPluginLoader> +#include <QFileInfo> +#include <QDir> + +inline Plugin loadPluginFromPath(const QString &path) +{ + Plugin p; + QPluginLoader loader(path); + + if(loader.load()) { +#ifdef QT_DEBUG + qDebug("Loading plugin: %s [ok]", qUtf8Printable(path)); +#endif + + auto meta = loader.metaData().value("MetaData").toObject(); + p.name = meta.value("name").toString(); + p.author = meta.value("author").toString(); + p.shortcut = QKeySequence::fromString(meta.value("shortcut").toString()); + + p.instance = loader.instance(); + + } else { + qDebug("Loading pluing: %s [failed]", qUtf8Printable(path)); + qDebug("%s", qUtf8Printable(loader.errorString())); + } + + return p; +} + +inline QVector<Plugin> loadPlugins(const QString &path) +{ + QVector<Plugin> list; + + // quit if there's nothing to load + if(path.isEmpty()) + return list; + + // plugins can be a semicolon-separated list + if(path.contains(';')) { + auto pluginList = path.split(';'); + for(const auto &pluginPath : pluginList) { + auto plugin = loadPluginFromPath(pluginPath); + if(plugin.instance) + list.append(plugin); + } + + return list; + } + + // check if path is path to a file or a folder + QFileInfo location(path); + + if(!location.exists()) { + qDebug("Plugin path doesn't exist."); + return list; + } + + if(location.isFile()) { + // only load this one plugin + auto p = loadPluginFromPath(location.absoluteFilePath()); + if(p.instance) + list.append(p); + + } else if(location.isDir()) { + // load all profiles from this directory + const auto entries = QDir(location.absoluteFilePath()).entryInfoList(QDir::Files | QDir::Readable); + for(const auto &f : entries) { + auto p = loadPluginFromPath(f.absoluteFilePath()); + if(p.instance) + list.append(p); + } +#ifdef QT_DEBUG + } else { + qDebug("Path is neither file nor folder: %s", qUtf8Printable(path)); +#endif + } + + return list; +} + +#endif // SMOLBOTE_PLUGIN_H |