diff --git a/src/calamares/CMakeLists.txt b/src/calamares/CMakeLists.txt index 901131cdf..53838275c 100644 --- a/src/calamares/CMakeLists.txt +++ b/src/calamares/CMakeLists.txt @@ -10,12 +10,14 @@ set( calamaresSources main.cpp CalamaresApplication.cpp CalamaresWindow.cpp - Module.cpp - ModuleManager.cpp ViewManager.cpp Settings.cpp YamlUtils.cpp + modulesystem/Module.cpp + modulesystem/ModuleManager.cpp + modulesystem/ViewModule.cpp + viewpages/ViewPlugin.cpp viewpages/AbstractPage.cpp ) diff --git a/src/calamares/CalamaresApplication.cpp b/src/calamares/CalamaresApplication.cpp index cfbff0ede..383d26c99 100644 --- a/src/calamares/CalamaresApplication.cpp +++ b/src/calamares/CalamaresApplication.cpp @@ -20,7 +20,7 @@ #include "CalamaresWindow.h" #include "CalamaresVersion.h" -#include "ModuleManager.h" +#include "modulesystem/ModuleManager.h" #include "Settings.h" #include "utils/CalamaresUtils.h" #include "utils/Logger.h" @@ -115,9 +115,9 @@ CalamaresApplication::initPlugins() { m_moduleManager = new Calamares::ModuleManager( Calamares::Settings::instance()->modulesSearchPaths(), this ); - connect( m_moduleManager, &Calamares::ModuleManager::ready, + connect( m_moduleManager, &Calamares::ModuleManager::initDone, this, &CalamaresApplication::onPluginsReady ); - m_moduleManager->start(); + m_moduleManager->init(); } @@ -128,13 +128,11 @@ CalamaresApplication::onPluginsReady() m_mainwindow = new CalamaresWindow(); -// foreach ( QString moduleName, Calamares::Settings::instance()->viewModulesPrepare() ) -// { -// Q_ASSERT( m_moduleManager->availableModules().contains( moduleName ) ); -// m_moduleManager->module( moduleName )->loadSelf(); -// } - - m_mainwindow->show(); + m_moduleManager->loadRequiredModules(); + connect( m_moduleManager, &Calamares::ModuleManager::modulesLoaded, [this] + { + m_mainwindow->show(); + }); } diff --git a/src/calamares/ViewManager.cpp b/src/calamares/ViewManager.cpp index 6e672641b..91192fa69 100644 --- a/src/calamares/ViewManager.cpp +++ b/src/calamares/ViewManager.cpp @@ -19,6 +19,7 @@ #include "ViewManager.h" #include +#include #include namespace Calamares @@ -79,7 +80,9 @@ ViewManager::widget() void ViewManager::addViewPlugin( ViewPlugin* plugin ) { - + plugin->setParent( this ); + m_steps.append( plugin ); + m_stack->addWidget( new QLabel( plugin->prettyName(), m_stack ) ); } diff --git a/src/calamares/ViewManager.h b/src/calamares/ViewManager.h index e115319a4..99f586878 100644 --- a/src/calamares/ViewManager.h +++ b/src/calamares/ViewManager.h @@ -23,8 +23,10 @@ #include "viewpages/ViewPlugin.h" #include +#include #include + namespace Calamares { @@ -52,6 +54,8 @@ public slots: private: static ViewManager* s_instance; + QQueue< ViewPlugin* > m_steps; + QWidget* m_widget; QStackedWidget* m_stack; QPushButton* m_back; diff --git a/src/calamares/Module.cpp b/src/calamares/modulesystem/Module.cpp similarity index 69% rename from src/calamares/Module.cpp rename to src/calamares/modulesystem/Module.cpp index 750b479f8..184858feb 100644 --- a/src/calamares/Module.cpp +++ b/src/calamares/modulesystem/Module.cpp @@ -18,13 +18,15 @@ #include "Module.h" +#include "ViewModule.h" #include "YamlUtils.h" - #include "utils/Logger.h" #include +#include #include +#include #include @@ -40,49 +42,55 @@ requires: [] #list of module names that must also be loaded. only appli */ void -operator>>( const YAML::Node& node, Calamares::Module& m ) +operator>>( const YAML::Node& node, Calamares::Module* m ) { - m.m_name = QString::fromStdString( node[ "name" ].as< std::string >() ); + m->m_name = QString::fromStdString( node[ "name" ].as< std::string >() ); QString typeString = QString::fromStdString( node[ "type" ].as< std::string >() ); if ( typeString == "core" ) { - m.m_type = Calamares::Module::Core; + m->m_type = Calamares::Module::Core; } else if ( typeString == "view" ) { - m.m_type = Calamares::Module::View; - m.m_interface = Calamares::Module::QtPlugin; + m->m_type = Calamares::Module::View; + m->m_interface = Calamares::Module::QtPlugin; } - if ( m.m_type != Calamares::Module::View ) + if ( m->m_type != Calamares::Module::View ) { QString interfaceString = QString::fromStdString( node[ "interface" ].as< std::string >() ); if ( interfaceString == "qtplugin" ) { - m.m_interface = Calamares::Module::QtPlugin; + m->m_interface = Calamares::Module::QtPlugin; } else if ( interfaceString == "python" ) { - m.m_interface = Calamares::Module::Python; + m->m_interface = Calamares::Module::Python; } else if ( interfaceString == "process" ) { - m.m_interface = Calamares::Module::Process; + m->m_interface = Calamares::Module::Process; } } if ( node[ "requires" ] && node[ "requires" ].IsSequence() ) { - node[ "requires" ] >> m.m_requiredModules; + node[ "requires" ] >> m->m_requiredModules; } } +namespace Calamares +{ + +Module::~Module() +{} -Calamares::Module* -Calamares::Module::fromConfigFile( const QString& path ) +Module* +Module::fromConfigFile( const QString& path ) { + Module* m = nullptr; QFile metadataFile( path ); if ( metadataFile.exists() && metadataFile.open( QFile::ReadOnly | QFile::Text ) ) { @@ -99,13 +107,18 @@ Calamares::Module::fromConfigFile( const QString& path ) return nullptr; } - Module* m = new Module(); - moduleDocument >> *m; + m = new ViewModule(); + + QFileInfo mfi( path ); + m->m_directory = mfi.absoluteDir().absolutePath(); + + m->initFrom( moduleDocument ); return m; } catch ( YAML::Exception& e ) { cDebug() << "WARNING: YAML parser error " << e.what(); + delete m; return nullptr; } } @@ -114,14 +127,42 @@ Calamares::Module::fromConfigFile( const QString& path ) } QString -Calamares::Module::name() +Module::name() { return m_name; } QStringList -Calamares::Module::requiredModules() +Module::requiredModules() { return m_requiredModules; } + + +QString +Module::location() +{ + return m_directory; +} + + +bool +Module::isLoaded() +{ + return m_loaded; +} + + +Module::Module() + : m_loaded( false ) +{} + + +void +Module::initFrom( const YAML::Node& node ) +{ + node >> this; +} + +} //ns diff --git a/src/calamares/Module.h b/src/calamares/modulesystem/Module.h similarity index 70% rename from src/calamares/Module.h rename to src/calamares/modulesystem/Module.h index 60ddc3091..5ce2364ea 100644 --- a/src/calamares/Module.h +++ b/src/calamares/modulesystem/Module.h @@ -16,8 +16,8 @@ * along with Calamares. If not, see . */ -#ifndef CALAMARESMODULE_H -#define CALAMARESMODULE_H +#ifndef CALAMARES_MODULE_H +#define CALAMARES_MODULE_H #include "UiDllMacro.h" @@ -34,7 +34,7 @@ namespace Calamares class Module; } -void operator>>( const YAML::Node& node, Calamares::Module& m ); +void operator>>( const YAML::Node& node, Calamares::Module* m ); namespace Calamares { @@ -42,11 +42,6 @@ namespace Calamares class UIDLLEXPORT Module { public: - static Module* fromConfigFile( const QString& path ); - - QString name(); - QStringList requiredModules(); - enum Type { Core, @@ -59,15 +54,35 @@ public: Python, Process }; + virtual ~Module(); + + static Module* fromConfigFile( const QString& path ); + + virtual QString name(); + virtual QStringList requiredModules(); + virtual QString location(); + virtual Type type() = 0; + virtual Interface interface() = 0; + + virtual bool isLoaded(); + + virtual void loadSelf() = 0; + +protected: + explicit Module(); + virtual void initFrom( const YAML::Node& node ); + bool m_loaded; + private: QString m_name; Type m_type; Interface m_interface; QStringList m_requiredModules; + QString m_directory; - friend void ::operator>>( const YAML::Node& node, Calamares::Module& m ); + friend void ::operator>>( const YAML::Node& node, Calamares::Module* m ); }; } -#endif // CALAMARESMODULE_H +#endif // CALAMARES_MODULE_H diff --git a/src/calamares/ModuleManager.cpp b/src/calamares/modulesystem/ModuleManager.cpp similarity index 75% rename from src/calamares/ModuleManager.cpp rename to src/calamares/modulesystem/ModuleManager.cpp index 18977f83d..1b61274de 100644 --- a/src/calamares/ModuleManager.cpp +++ b/src/calamares/modulesystem/ModuleManager.cpp @@ -19,9 +19,11 @@ #include "ModuleManager.h" #include "utils/Logger.h" +#include "Settings.h" #include +#include #include #include @@ -46,9 +48,9 @@ ModuleManager::~ModuleManager() void -ModuleManager::start() +ModuleManager::init() { - QTimer::singleShot( 0, this, SLOT( doWork() ) ); + QTimer::singleShot( 0, this, SLOT( doInit() ) ); } @@ -67,7 +69,14 @@ ModuleManager::module( const QString& name ) void -ModuleManager::doWork() +ModuleManager::loadRequiredModules() +{ + QTimer::singleShot( 0, this, SLOT( doLoadModules() ) ); +} + + +void +ModuleManager::doInit() { // We start from a list of paths in m_paths. Each of those is a directory that // might (should) contain Calamares modules of any type/interface. @@ -120,7 +129,46 @@ ModuleManager::doWork() // At this point m_availableModules is filled with whatever was found in the // search paths. checkDependencies(); - emit ready(); + emit initDone(); +} + + +void +ModuleManager::doLoadModules() +{ + foreach ( const QString& moduleName, Settings::instance()->viewModulesPrepare() ) + { + if ( !m_availableModules.contains( moduleName ) ) + { + cDebug() << "Module" << moduleName << "not found in module search paths." + << "\nCalamares will now quit."; + qApp->quit(); + } + recursiveLoad( moduleName ); + } + emit modulesLoaded(); + + //IDEA: + // 1) deps are already fine. check if we have all the modules needed by the roster + // 2) ask MM to load them from the list provided by Settings + // 3) MM must load them asyncly but one at a time, by calling Module::loadSelf + // 4) Module must have subclasses that reimplement loadSelf for various module types +} + + +void +ModuleManager::recursiveLoad( const QString& moduleName ) +{ + Module* thisModule = m_availableModules.value( moduleName ); + foreach ( const QString& module, thisModule->requiredModules() ) + { + if ( !m_availableModules.value( module )->isLoaded() ) + { + recursiveLoad( module ); + } + } + thisModule->loadSelf(); + cDebug() << ( thisModule->isLoaded() ? "SUCCESS" : "FAILURE" ); } @@ -152,4 +200,5 @@ ModuleManager::checkDependencies() } } + } diff --git a/src/calamares/ModuleManager.h b/src/calamares/modulesystem/ModuleManager.h similarity index 87% rename from src/calamares/ModuleManager.h rename to src/calamares/modulesystem/ModuleManager.h index e7cb11266..55788e892 100644 --- a/src/calamares/ModuleManager.h +++ b/src/calamares/modulesystem/ModuleManager.h @@ -37,18 +37,23 @@ public: explicit ModuleManager( const QStringList& paths, QObject* parent = 0 ); virtual ~ModuleManager(); - void start(); + void init(); QStringList availableModules(); Module* module( const QString& name ); + void loadRequiredModules(); + signals: - void ready(); + void initDone(); + void modulesLoaded(); private slots: - void doWork(); + void doInit(); + void doLoadModules(); private: + void recursiveLoad( const QString& moduleName ); void checkDependencies(); QMap< QString, Module* > m_availableModules; diff --git a/src/calamares/modulesystem/ViewModule.cpp b/src/calamares/modulesystem/ViewModule.cpp new file mode 100644 index 000000000..fe8b460aa --- /dev/null +++ b/src/calamares/modulesystem/ViewModule.cpp @@ -0,0 +1,106 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014, Teo Mrnjavac + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#include "ViewModule.h" + +#include "utils/Logger.h" +#include "viewpages/ViewPlugin.h" +#include "ViewManager.h" + +#include + +#include +#include + +namespace Calamares { + + +Module::Type +ViewModule::type() +{ + return View; +} + + +Module::Interface +ViewModule::interface() +{ + return QtPlugin; +} + + +void +ViewModule::loadSelf() +{ + cDebug() << Q_FUNC_INFO << "for module" << name(); + if ( m_loader ) + { + ViewPlugin *vp = qobject_cast< ViewPlugin* >( m_loader->instance() ); + if ( vp ) + { + ViewManager::instance()->addViewPlugin( vp ); + m_loaded = true; + } + } +} + + +void +ViewModule::initFrom( const YAML::Node& node ) +{ + Module::initFrom( node ); + QDir directory( location() ); + QString load; + if ( node[ "load" ] ) + { + load = QString::fromStdString( node[ "load" ].as() ); + load = directory.absoluteFilePath( load ); + } + // If a load path is not specified, we look for a plugin to load in the directory. + if ( load.isEmpty() || !QLibrary::isLibrary( load ) ) + { + QStringList ls = directory.entryList( QStringList() = { "*.so" } ); + if ( !ls.isEmpty() ) + { + foreach ( QString entry, ls ) + { + entry = directory.absoluteFilePath( entry ); + if ( QLibrary::isLibrary( entry ) ) + { + load = entry; + break; + } + } + } + } + + m_loader = new QPluginLoader( load ); +} + +ViewModule::ViewModule() + : Module() + , m_loader( nullptr ) +{ +} + +ViewModule::~ViewModule() +{ + delete m_loader; +} + +} // namespace Calamares diff --git a/src/calamares/modulesystem/ViewModule.h b/src/calamares/modulesystem/ViewModule.h new file mode 100644 index 000000000..fd1257f2d --- /dev/null +++ b/src/calamares/modulesystem/ViewModule.h @@ -0,0 +1,50 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014, Teo Mrnjavac + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#ifndef CALAMARES_VIEWMODULE_H +#define CALAMARES_VIEWMODULE_H + +#include "UiDllMacro.h" +#include "Module.h" + +class QPluginLoader; + +namespace Calamares { + +class UIDLLEXPORT ViewModule : public Module +{ +public: + Type type() override; + Interface interface() override; + + void loadSelf() override; + +protected: + void initFrom( const YAML::Node &node ) override; + +private: + friend class Module; //so only the superclass can instantiate + explicit ViewModule(); + virtual ~ViewModule(); + + QPluginLoader *m_loader; +}; + +} // namespace Calamares + +#endif // CALAMARES_VIEWMODULE_H diff --git a/src/calamares/viewpages/ViewPlugin.h b/src/calamares/viewpages/ViewPlugin.h index 8bb05cd16..ec6bcdc57 100644 --- a/src/calamares/viewpages/ViewPlugin.h +++ b/src/calamares/viewpages/ViewPlugin.h @@ -35,6 +35,8 @@ public: explicit ViewPlugin( QObject *parent = 0 ); virtual ~ViewPlugin() {} + virtual QString prettyName() = 0; + signals: void done(); diff --git a/src/modules/greeting/GreetingViewPlugin.cpp b/src/modules/greeting/GreetingViewPlugin.cpp index 5c64978dd..bc62c6176 100644 --- a/src/modules/greeting/GreetingViewPlugin.cpp +++ b/src/modules/greeting/GreetingViewPlugin.cpp @@ -18,7 +18,15 @@ #include "GreetingViewPlugin.h" + GreetingViewPlugin::GreetingViewPlugin( QObject *parent ) : Calamares::ViewPlugin( parent ) { } + + +QString +GreetingViewPlugin::prettyName() +{ + return tr( "Welcome" ); +} diff --git a/src/modules/greeting/GreetingViewPlugin.h b/src/modules/greeting/GreetingViewPlugin.h index 4ba5f7bff..345395b09 100644 --- a/src/modules/greeting/GreetingViewPlugin.h +++ b/src/modules/greeting/GreetingViewPlugin.h @@ -30,10 +30,11 @@ class PLUGINDLLEXPORT GreetingViewPlugin : public Calamares::ViewPlugin Q_PLUGIN_METADATA( IID "calamares.ViewPlugin/1.0" ) //FILE "module.json" ) Q_INTERFACES( Calamares::ViewPlugin ) + public: explicit GreetingViewPlugin(QObject *parent = 0); - + QString prettyName() override; }; #endif // GREETINGPAGEPLUGIN_H