From 2145695877cc5aa96cc0495d035cb3dc44f34a05 Mon Sep 17 00:00:00 2001 From: RensDofferhoff <20978635+RensDofferhoff@users.noreply.github.com> Date: Wed, 9 Oct 2024 20:21:17 +0200 Subject: [PATCH] New dev module system (#5690) * initial functional draft * add ugly name thing for now --- Desktop/analysis/analyses.cpp | 3 +- .../JASP/Widgets/FileMenu/PrefsAdvanced.qml | 104 +++++++++++++++++- .../components/JASP/Widgets/ModulesMenu.qml | 2 +- Desktop/gui/preferencesmodel.cpp.in | 16 +++ Desktop/gui/preferencesmodel.h | 14 ++- Desktop/modules/dynamicmodule.cpp | 21 +++- Desktop/modules/dynamicmodule.h | 6 + Desktop/modules/dynamicmodules.cpp | 39 ++++--- Desktop/utilities/settings.cpp | 5 +- Desktop/utilities/settings.h | 5 +- 10 files changed, 187 insertions(+), 28 deletions(-) diff --git a/Desktop/analysis/analyses.cpp b/Desktop/analysis/analyses.cpp index c2ab072b4a..07409aab7e 100644 --- a/Desktop/analysis/analyses.cpp +++ b/Desktop/analysis/analyses.cpp @@ -298,8 +298,7 @@ void Analyses::removeAnalysesOfDynamicModule(Modules::DynamicModule * module) void Analyses::refreshAnalysesOfDynamicModule(Modules::DynamicModule * module) { - //Log::log() << "void Analyses::refreshAnalysesOfDynamicModule(" << module->toString() << ")" << std::endl; - + Log::log() << "void Analyses::refreshAnalysesOfDynamicModule(" << module->toString() << ")" << std::endl; for(auto & keyval : _analysisMap) if(keyval.second->dynamicModule() == module) diff --git a/Desktop/components/JASP/Widgets/FileMenu/PrefsAdvanced.qml b/Desktop/components/JASP/Widgets/FileMenu/PrefsAdvanced.qml index f296dfe11e..1ec7065c6f 100644 --- a/Desktop/components/JASP/Widgets/FileMenu/PrefsAdvanced.qml +++ b/Desktop/components/JASP/Widgets/FileMenu/PrefsAdvanced.qml @@ -140,9 +140,6 @@ ScrollView KeyNavigation.tab: githubPatCustomToken } - - - Item { id: githubPatCustomTokenItem @@ -170,7 +167,7 @@ ScrollView text: preferencesModel.githubPatCustom onEditingFinished: preferencesModel.githubPatCustom = text - nextEl: generateMarkdown + nextEl: directLibpathDevModEnabled height: browseDeveloperFolderButton.height anchors @@ -182,7 +179,7 @@ ScrollView textInput.echoMode: TextInput.Password - KeyNavigation.tab: generateMarkdown + KeyNavigation.tab: directLibpathDevModEnabled } } @@ -197,6 +194,103 @@ ScrollView KeyNavigation.tab: cleanModulesFolder } + + + CheckBox + { + id: directLibpathDevModEnabled + label: qsTr("Enable direct libpath mode") + checked: preferencesModel.directLibpathEnabled + onCheckedChanged: preferencesModel.directLibpathEnabled = checked + toolTip: qsTr("To use JASP Modules enable this option.") + visible: preferencesModel.developerMode + + KeyNavigation.tab: directLibpathFolder + } + + Item + { + id: directLibpath + enabled: preferencesModel.directLibpathEnabled + width: parent.width + height: cranRepoUrl.height + visible: preferencesModel.developerMode && preferencesModel.directLibpathEnabled + + Label + { + id: directLibPathLabel + text: qsTr("DevModule libpath:") + + anchors + { + left: parent.left + verticalCenter: parent.verticalCenter + leftMargin: jaspTheme.subOptionOffset + } + } + + PrefsTextInput + { + id: directLibpathFolder + + text: preferencesModel.directLibpathFolder + onEditingFinished: preferencesModel.directLibpathFolder = text + + nextEl: moduleName + + height: browseDeveloperFolderButton.height + anchors + { + left: directLibPathLabel.right + right: parent.right + margins: jaspTheme.generalAnchorMargin + } + + KeyNavigation.tab: moduleName + } + } + + Item { + + id: directDevMod + enabled: preferencesModel.directLibpathEnabled + width: parent.width + height: cranRepoUrl.height + visible: preferencesModel.developerMode && preferencesModel.directLibpathEnabled + + Label + { + id: directDevModName + text: qsTr("Developer module name:") + + anchors + { + left: parent.left + verticalCenter: parent.verticalCenter + leftMargin: jaspTheme.subOptionOffset + } + } + + PrefsTextInput + { + id: moduleName + + text: preferencesModel.directDevModName + onEditingFinished: preferencesModel.directDevModName = text + + nextEl: cleanModulesFolder + + height: browseDeveloperFolderButton.height + anchors + { + left: directDevModName.right + right: parent.right + margins: jaspTheme.generalAnchorMargin + } + + KeyNavigation.tab: cleanModulesFolder + } + } RoundedButton { diff --git a/Desktop/components/JASP/Widgets/ModulesMenu.qml b/Desktop/components/JASP/Widgets/ModulesMenu.qml index f59f990d51..c5bc1af4d1 100644 --- a/Desktop/components/JASP/Widgets/ModulesMenu.qml +++ b/Desktop/components/JASP/Widgets/ModulesMenu.qml @@ -219,7 +219,7 @@ FocusScope focus: currentIndex === -1 activeFocusOnTab: false - readonly property bool folderSelected: preferencesModel.developerFolder != "" + readonly property bool folderSelected: preferencesModel.developerFolder != "" || (preferencesModel.directLibpathEnabled && preferencesModel.directLibpathFolder != "") } QTC.ToolSeparator diff --git a/Desktop/gui/preferencesmodel.cpp.in b/Desktop/gui/preferencesmodel.cpp.in index 2ee6fcc3c1..c233a78c85 100644 --- a/Desktop/gui/preferencesmodel.cpp.in +++ b/Desktop/gui/preferencesmodel.cpp.in @@ -138,6 +138,10 @@ GET_PREF_FUNC_BOOL( checkUpdates, Settings::CHECK_UPDATES ) GET_PREF_FUNC_INT( maxScaleLevels, Settings::MAX_SCALE_LEVELS ) GET_PREF_FUNC_BOOL( pdfLandscape, Settings::PDF_LANDSCAPE ) GET_PREF_FUNC_INT( pdfPageSize, Settings::PDF_PAGESIZE ) +GET_PREF_FUNC_BOOL( directLibpathEnabled, Settings::DIRECT_LIBPATH_ENABLED ) +GET_PREF_FUNC_STR( directLibpathFolder, Settings::DIRECT_LIBPATH_FOLDER ) +GET_PREF_FUNC_STR( directDevModName, Settings::DIRECT_DEVMOD_NAME ) + int PreferencesModel::maxEngines() const { @@ -314,6 +318,9 @@ SET_PREF_FUNCTION( bool, setCheckUpdates, checkUpdates, checkUpdatesCha SET_PREF_FUNCTION( int, setMaxScaleLevels, maxScaleLevels, maxScaleLevelsChanged, Settings::MAX_SCALE_LEVELS ) SET_PREF_FUNCTION( bool, setPdfLandscape, pdfLandscape, pdfLandscapeChanged, Settings::PDF_LANDSCAPE ) SET_PREF_FUNCTION( int, setPdfPageSize, pdfPageSize, pdfPageSizeChanged, Settings::PDF_PAGESIZE ) +SET_PREF_FUNCTION( bool, setDirectLibpathEnabled, directLibpathEnabled, directLibpathEnabledChanged, Settings::DIRECT_LIBPATH_ENABLED ) +SET_PREF_FUNCTION( QString, setDirectDevModName, directDevModName, directDevModNameChanged, Settings::DIRECT_DEVMOD_NAME ) + void PreferencesModel::setGithubPatCustom(QString newPat) { @@ -551,3 +558,12 @@ QStringList PreferencesModel::_splitValues(const QString &values) const return QStringList(orderedValues.begin(), orderedValues.end()); } + +void PreferencesModel::setDirectLibpathFolder(QString libpath) +{ + if (libpath != "") + { + Settings::setValue(Settings::DIRECT_LIBPATH_FOLDER, libpath); + emit directLibpathFolderChanged(); + } +} diff --git a/Desktop/gui/preferencesmodel.h b/Desktop/gui/preferencesmodel.h index 472dcba94b..e85fb4e51b 100644 --- a/Desktop/gui/preferencesmodel.h +++ b/Desktop/gui/preferencesmodel.h @@ -29,6 +29,9 @@ class PreferencesModel : public PreferencesModelBase Q_PROPERTY(int defaultPPI READ defaultPPI WRITE setDefaultPPI NOTIFY defaultPPIChanged ) Q_PROPERTY(bool developerMode READ developerMode WRITE setDeveloperMode NOTIFY developerModeChanged ) Q_PROPERTY(QString developerFolder READ developerFolder WRITE setDeveloperFolder NOTIFY developerFolderChanged ) + Q_PROPERTY(bool directLibpathEnabled READ directLibpathEnabled WRITE setDirectLibpathEnabled NOTIFY directLibpathEnabledChanged ) + Q_PROPERTY(QString directLibpathFolder READ directLibpathFolder WRITE setDirectLibpathFolder NOTIFY directLibpathFolderChanged ) + Q_PROPERTY(QString directDevModName READ directDevModName WRITE setDirectDevModName NOTIFY directDevModNameChanged ) Q_PROPERTY(int thresholdScale READ thresholdScale WRITE setThresholdScale NOTIFY thresholdScaleChanged ) Q_PROPERTY(bool logToFile READ logToFile WRITE setLogToFile NOTIFY logToFileChanged ) Q_PROPERTY(int logFilesMax READ logFilesMax WRITE setLogFilesMax NOTIFY logFilesMaxChanged ) @@ -146,7 +149,10 @@ class PreferencesModel : public PreferencesModelBase QVariantList pdfPageSizeModel() const { return _pdfPageSizeModel; } int pdfPageSize() const; bool pdfLandscape() const; - + bool directLibpathEnabled() const; + QString directLibpathFolder() const; + QString directDevModName() const; + bool checkUpdatesAskUser() const; void setCheckUpdatesAskUser(bool newCheckUpdatesAskUser); @@ -213,6 +219,9 @@ public slots: void setMaxScaleLevels( int maxScaleLevels); void setPdfPageSize( int pdfPageSize); void setPdfLandscape( bool pdfLandscape); + void setDirectLibpathEnabled( bool setDirectLibpathEnabled); + void setDirectLibpathFolder( QString libpath); + void setDirectDevModName( QString name); signals: void fixedDecimalsChanged( bool fixedDecimals); @@ -268,6 +277,9 @@ public slots: void maxScaleLevelsChanged( int maxScaleLevels); void pdfPageSizeChanged( int pdfPageSize); void pdfLandscapeChanged( bool pdfLandscape); + void directLibpathEnabledChanged( bool directLibpathEnabled); + void directLibpathFolderChanged(); + void directDevModNameChanged( QString name); private slots: void dataLabelNAChangedSlot(QString label); diff --git a/Desktop/modules/dynamicmodule.cpp b/Desktop/modules/dynamicmodule.cpp index 5dcd7190fa..248ad2adf6 100644 --- a/Desktop/modules/dynamicmodule.cpp +++ b/Desktop/modules/dynamicmodule.cpp @@ -100,6 +100,24 @@ DynamicModule::DynamicModule(QObject * parent) : QObject(parent), _isDeveloperMo } +///This constructor is meant specifically for the development module from a libpath *it*! +DynamicModule::DynamicModule(QObject * parent, QString libpath) : QObject(parent), _isDeveloperMod(true), _isLibpathDevMod(true) +{ + _modulePackage = fq(libpath + "/" + Settings::value(Settings::DIRECT_DEVMOD_NAME).toString() + "/"); + _moduleFolder = QFileInfo(libpath + "/"); + _name = extractPackageNameFromFolder(_modulePackage); + + if(_name == "") _name = defaultDevelopmentModuleName(); + + Log::log() << "Development Module is constructed with name: '" << _name << "' and will intialized from libpath: " << _moduleFolder.absoluteFilePath().toStdString() << std::endl; + + _developmentModuleName = _name; + + loadDescriptionFromFolder(_modulePackage); + setInstalled(true); +} + + void DynamicModule::initialize() { @@ -112,7 +130,6 @@ void DynamicModule::initialize() // else if(!_moduleFolder.isWritable()) throw std::runtime_error(_moduleFolder.absolutePath().toStdString() + " is not writable!"); setInitialized(true); - auto checkForExistence = [&](std::string name, bool isFile = false) { QString modPath = _moduleFolder.absolutePath() + "/" + nameQ() + "/" + QString::fromStdString(name); @@ -499,7 +516,7 @@ std::string DynamicModule::generateModuleUninstallingR() std::string DynamicModule::moduleInstFolder() const { //Because in a developer mod everything is loaded directly from the source folder we give an actual inst folder: - if(_isDeveloperMod) return _modulePackage + "/inst"; + if(_isDeveloperMod && !_isLibpathDevMod) return _modulePackage + "/inst"; //But after install this is in a R-library and therefore there is no more inst folder: else return moduleRLibrary().toStdString() + "/" + _name + "/"; } diff --git a/Desktop/modules/dynamicmodule.h b/Desktop/modules/dynamicmodule.h index 329ec46196..f6e8cfee15 100644 --- a/Desktop/modules/dynamicmodule.h +++ b/Desktop/modules/dynamicmodule.h @@ -78,6 +78,10 @@ class DynamicModule : public QObject ///This constructor is meant specifically for the development module and only *it*! explicit DynamicModule(QObject * parent); + ///This constructor is meant specifically for development modules initialized form a libpaths + explicit DynamicModule(QObject *parent, QString libpath); + + ~DynamicModule() override { for(auto * entry : _menuEntries) @@ -165,6 +169,7 @@ class DynamicModule : public QObject bool installing() const { return _installing; } bool initialized() const { return _initialized; } bool isBundled() const { return _bundled; } + bool isLibpathDevMod() const { return _isLibpathDevMod; } void initialize(); void loadDescriptionQml(const QString & descriptionTxt, const QUrl & url); @@ -242,6 +247,7 @@ public slots: bool _installing = false, _installed = false, _isDeveloperMod = false, + _isLibpathDevMod = false, _initialized = false, _bundled = false, _isCommon = false, diff --git a/Desktop/modules/dynamicmodules.cpp b/Desktop/modules/dynamicmodules.cpp index b9fde87ea6..2d7d86b8e7 100644 --- a/Desktop/modules/dynamicmodules.cpp +++ b/Desktop/modules/dynamicmodules.cpp @@ -299,7 +299,7 @@ void DynamicModules::uninstallModule(const std::string & moduleName) unloadModule(moduleName); _modules[moduleName]->setInstalled(false); - if(_modules[moduleName]->isBundled()) + if(_modules[moduleName]->isBundled() || _modules[moduleName]->isLibpathDevMod()) removeFolder = false; for(int i=int(_moduleNames.size()) - 1; i>=0; i--) @@ -530,14 +530,16 @@ void DynamicModules::uninstallJASPDeveloperModule() void DynamicModules::installJASPDeveloperModule() { - if(Settings::value(Settings::DEVELOPER_FOLDER).toString() == "") + bool directLibpathEnabled = PreferencesModel::prefs()->directLibpathEnabled(); + QString modulePath = directLibpathEnabled ? PreferencesModel::prefs()->directLibpathFolder() : Settings::value(Settings::DEVELOPER_FOLDER).toString(); + if(modulePath == "") { MessageForwarder::showWarning(tr("Select a folder"), tr("To install a development module you need to select the folder you want to watch and load, you can do this under the filemenu, Preferences->Advanced.")); return; } - else if(!QDir(Settings::value(Settings::DEVELOPER_FOLDER).toString()).exists()) + else if(!QDir(modulePath).exists()) { - MessageForwarder::showWarning(tr("Select an exisiting folder"), tr("To install a development module you need to select and existing folder, you selected '$1' but it doesn't exist.").arg(Settings::value(Settings::DEVELOPER_FOLDER).toString())); + MessageForwarder::showWarning(tr("Select an exisiting folder"), tr("To install a development module you need to select and existing folder, you selected '$1' but it doesn't exist.").arg(modulePath)); return; } @@ -545,12 +547,7 @@ void DynamicModules::installJASPDeveloperModule() try { - - _devModSourceDirectory = QDir(Settings::value(Settings::DEVELOPER_FOLDER).toString()); - - DynamicModule * devMod = new DynamicModule(this); - - devMod->loadDescriptionFromFolder(fq(_devModSourceDirectory.absolutePath())); + DynamicModule * devMod = directLibpathEnabled ? new DynamicModule(this, modulePath) : new DynamicModule(this); std::string origin = devMod->modulePackage(), name = devMod->name(), @@ -563,11 +560,14 @@ void DynamicModules::installJASPDeveloperModule() else if(_modules.count(name) > 0 && _modules[name] != devMod) replaceModule(devMod); - DynamicModule::developmentModuleFolderCreate(); - _modules[name] = devMod; - - registerForInstalling(name); + if(directLibpathEnabled) { + initializeModule(devMod); + } + else { + DynamicModule::developmentModuleFolderCreate(); + registerForInstalling(name); + } } catch(ModuleException & e) { @@ -603,8 +603,14 @@ void DynamicModules::startWatchingDevelopersModule() if(dir == "icons") iconsFound = true; } } + else if(entry.isDir() && entry.fileName().toLower() == "qml") + qmlFound = true; + else if(entry.isDir() && entry.fileName().toLower() == "icons") + iconsFound = true; else if(entry.isDir() && entry.fileName().toUpper() == "R") rFound = true; + else if(entry.isFile() && DynamicModule::isDescriptionFile(entry.fileName())) + descFound = entry.fileName(); if(!(descFound != "" && rFound && qmlFound && iconsFound)) { @@ -756,7 +762,10 @@ void DynamicModules::regenerateDeveloperModuleRPackage() throw std::runtime_error("void DynamicModules::regenerateDeveloperModuleRPackage() called but the development module is not initialized..."); auto * devMod = _modules[developmentModuleName()]; - devMod->setStatus(moduleStatus::installModPkgNeeded); + if(devMod->isLibpathDevMod()) + emit dynamicModuleChanged(devMod); + else + devMod->setStatus(moduleStatus::installModPkgNeeded); } QString DynamicModules::moduleDirectoryQ(const QString & moduleName) const diff --git a/Desktop/utilities/settings.cpp b/Desktop/utilities/settings.cpp index d267d65511..6ae6d33e2c 100644 --- a/Desktop/utilities/settings.cpp +++ b/Desktop/utilities/settings.cpp @@ -95,7 +95,10 @@ const Settings::Setting Settings::Values[] = { {"checkUpdatesLastTime", -1 }, {"maxScaleLevels", 100 }, {"pdfLandscape", false }, - {"pdfPageSize", int(pdfPageSize::A4) } + {"pdfPageSize", int(pdfPageSize::A4) }, + {"directLibpathEnabled", false }, + {"directLibpathFolder", "" }, + {"directDevModName", "" } }; diff --git a/Desktop/utilities/settings.h b/Desktop/utilities/settings.h index 4adbdf1598..7b11d2c06d 100644 --- a/Desktop/utilities/settings.h +++ b/Desktop/utilities/settings.h @@ -79,7 +79,10 @@ class Settings { LAST_CHECK, MAX_SCALE_LEVELS, PDF_LANDSCAPE, - PDF_PAGESIZE + PDF_PAGESIZE, + DIRECT_LIBPATH_ENABLED, + DIRECT_LIBPATH_FOLDER, + DIRECT_DEVMOD_NAME }; static QVariant value(Settings::Type key);