Skip to content

Commit 5d4d872

Browse files
authored
Merge pull request #739 from ghutchis/enh-load-packages
Add code to load new packages out of directories for install
2 parents 21ae63f + e96f026 commit 5d4d872

File tree

3 files changed

+89
-5
lines changed

3 files changed

+89
-5
lines changed

avogadro/mainwindow.cpp

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@
2727
#include <avogadro/qtgui/molecule.h>
2828
#include <avogadro/qtgui/moleculemodel.h>
2929
#include <avogadro/qtgui/multiviewwidget.h>
30+
#include <avogadro/qtgui/packagemanager.h>
3031
#include <avogadro/qtgui/periodictableview.h>
3132
#include <avogadro/qtgui/richtextdelegate.h>
3233
#include <avogadro/qtgui/rwmolecule.h>
3334
#include <avogadro/qtgui/sceneplugin.h>
3435
#include <avogadro/qtgui/scenepluginmodel.h>
3536
#include <avogadro/qtgui/toolplugin.h>
37+
#include <avogadro/qtgui/utilities.h>
3638
#include <avogadro/qtopengl/activeobjects.h>
3739
#include <avogadro/qtopengl/glwidget.h>
3840
#include <avogadro/qtplugins/pluginmanager.h>
@@ -316,12 +318,18 @@ MainWindow::MainWindow(const QStringList& fileNames, bool disableSettings)
316318
connect(extension, &QtGui::ExtensionPlugin::registerCommand, this,
317319
&MainWindow::registerExtensionCommand);
318320
extension->registerCommands();
319-
320-
buildMenu(extension);
321321
m_extensions.append(extension);
322322
}
323323
}
324324

325+
// Scan for pyproject.toml-based plugin packages.
326+
loadPackages();
327+
328+
// now we can build the menus for extensions
329+
foreach (ExtensionPlugin* extension, m_extensions) {
330+
buildMenu(extension);
331+
}
332+
325333
// Now set up the interface.
326334
#ifdef Q_OS_WIN
327335
qDebug() << " setting interface ";
@@ -1268,6 +1276,73 @@ void MainWindow::cleanupCurrentAutosave()
12681276
}
12691277
}
12701278

1279+
void MainWindow::loadPackages()
1280+
{
1281+
QStringList dirs;
1282+
1283+
// Add the standard install locations
1284+
QStringList stdPaths =
1285+
QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation);
1286+
foreach (const QString& dirStr, stdPaths) {
1287+
QString path = dirStr + "/packages";
1288+
dirs << path;
1289+
}
1290+
1291+
// Add the install-relative library path
1292+
dirs << QCoreApplication::applicationDirPath() + "/../" +
1293+
QtGui::Utilities::libraryDirectory() + "/avogadro2/packages";
1294+
1295+
// Check the directories for new packages
1296+
QtGui::PackageManager* pkgManager = QtGui::PackageManager::instance();
1297+
QStringList newPackages;
1298+
foreach (const QString& dir, dirs) {
1299+
#ifndef NDEBUG
1300+
qDebug() << "Checking for packages in" << dir;
1301+
#endif
1302+
newPackages.append(pkgManager->scanDirectory(dir));
1303+
}
1304+
1305+
// If there are new or updated packages, ask the user before installing
1306+
if (!newPackages.isEmpty()) {
1307+
QStringList packageNames;
1308+
foreach (const QString& dir, newPackages) {
1309+
packageNames << QFileInfo(dir).baseName();
1310+
}
1311+
1312+
// TODO: list the packages and count, maybe the versions
1313+
auto reply =
1314+
QMessageBox::question(this, tr("Install New Packages"),
1315+
tr("New or updated packages were found.\n"
1316+
"Would you like to install them now?"),
1317+
QMessageBox::Yes | QMessageBox::No);
1318+
if (reply != QMessageBox::Yes) {
1319+
// Still need to replay cached registrations for already-installed
1320+
// packages
1321+
pkgManager->loadRegisteredPackages();
1322+
return;
1323+
}
1324+
1325+
// TODO: show a dialog listing the new packages and let the user
1326+
// choose which to install
1327+
connect(pkgManager, &QtGui::PackageManager::packagesInstalled, this,
1328+
[this, pkgManager]() {
1329+
disconnect(pkgManager, &QtGui::PackageManager::packagesInstalled,
1330+
this, nullptr);
1331+
foreach (ExtensionPlugin* ext, m_extensions)
1332+
buildMenu(ext);
1333+
m_menuBuilder->buildMenuBar(menuBar());
1334+
});
1335+
pkgManager->installPackages(newPackages);
1336+
return; // Registration and loadRegisteredPackages run in PackageManager
1337+
}
1338+
1339+
// Load cached registrations so consumer plugins get their signals
1340+
#ifndef DEBUG
1341+
qDebug() << "Load cached packages";
1342+
#endif
1343+
pkgManager->loadRegisteredPackages();
1344+
}
1345+
12711346
void MainWindow::checkAutosaveRecovery()
12721347
{
12731348
QString autosaveDirPath =

avogadro/mainwindow.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@ public slots:
148148
*/
149149
void checkAutosaveRecovery();
150150

151+
/**
152+
* Scan standard directories for pyproject.toml-based plugin packages.
153+
*/
154+
void loadPackages();
155+
151156
void startAutosaveTimer();
152157

153158
QString autosaveFilePath() const;

avogadro/menubuilder.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ void MenuBuilder::addAction(const QStringList& pathList, QAction* action,
6868
{
6969
QString path(pathList.join("|"));
7070
if (m_menuActions.contains(path)) {
71+
if (m_menuActions[path].contains(action))
72+
return; // already registered, skip duplicate
7173
#ifdef Q_OS_MAC
7274
// If we're on Mac, don't show icons by default
7375
if (!m_showIcons) {
@@ -206,9 +208,11 @@ void MenuBuilder::buildMenu(QMenu* menu, const QString& path)
206208
bool replacedItem = false;
207209
foreach (QAction* action, menu->actions()) {
208210
if (action->text() == text.text) {
209-
// insert the new action and then remove the old one
210-
menu->insertAction(action, actions[text.text]);
211-
menu->removeAction(action);
211+
if (action != actions[text.text]) {
212+
// insert the new action and then remove the old one
213+
menu->insertAction(action, actions[text.text]);
214+
menu->removeAction(action);
215+
}
212216
replacedItem = true;
213217
break;
214218
}

0 commit comments

Comments
 (0)