Skip to content

Commit

Permalink
ENH: Add extensions manager API for downloading and installing an ext…
Browse files Browse the repository at this point in the history
…ension (Slicer#7145)

Allow the user to download and install an extension along with its dependencies
from the extensions server. By default, it will prompt the user to confirm the
installation and restart of the application after installation.

When the testing mode is enabled, the function installs the extension
and its dependencies without any confirmation dialogs. In this case,
the application is not automatically restarted.

To skip the confirmation dialogs during installation without enabling
testing mode, simply call setInteractive(false) on the extensions
manager model before invoking this function.

To prevent the application from automatically restarting after the
installation is completed, set the \a restart parameter to false.

Co-authored-by: SET <set@chirvasc-60.pro>
  • Loading branch information
jcfr and chir-set authored Aug 3, 2023
1 parent 28bd341 commit bda5198
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 0 deletions.
79 changes: 79 additions & 0 deletions Base/QTCore/qSlicerExtensionsManagerModel.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -1713,6 +1713,85 @@ bool qSlicerExtensionsManagerModel::downloadAndInstallExtensionByName(const QStr
return true;
}

//-----------------------------------------------------------------------------
void qSlicerExtensionsManagerModel::installExtensionFromServer(const QString& extensionName, bool restart)
{
Q_D(qSlicerExtensionsManagerModel);

if (this->isExtensionInstalled(extensionName))
{
return;
}

bool isTestingEnabled = qSlicerCoreApplication::testAttribute(qSlicerCoreApplication::AA_EnableTesting);

// Handle installation confirmation
bool installationConfirmed = false;
if (isTestingEnabled)
{
installationConfirmed = true;
qDebug() << "Installing the extension(s) without asking for confirmation (testing mode is enabled)";
}
else if (!this->interactive())
{
installationConfirmed = true;
qDebug() << "Installing the extension(s) without asking for confirmation (interactive mode is disabled)";
}
else
{
QString message = tr("Do you want to install '%1' now?").arg(extensionName);
QMessageBox::StandardButton answer = QMessageBox::question(nullptr, tr("Install extension ?"), message);
installationConfirmed = (answer == QMessageBox::StandardButton::Yes);
}
if (!installationConfirmed)
{
return;
}

// Ensure extension metadata is retrieved from the server or cache.
if (!this->updateExtensionsMetadataFromServer(/* force= */ true, /* waitForCompletion= */ true))
{
return;
}

// Install extension and its dependencies
if (!this->downloadAndInstallExtensionByName(extensionName, /* installDependencies= */ true, /* waitForCompletion= */ true))
{
d->critical(tr("Failed to install %1 extension").arg(extensionName));
return;
}

if (!restart)
{
return;
}

// Handle restart confirmation
bool restartConfirmed = false;
if (isTestingEnabled)
{
restartConfirmed = false;
qDebug() << "Skipping application restart (testing mode is enabled)";
}
else if (!this->interactive())
{
restartConfirmed = true;
qDebug() << "Restarting the application without asking for confirmation (interactive mode is disabled)";
}
else
{
QString message = tr("Extension %1 has been installed from server.").arg(extensionName);
message + "\n\n";
message += tr("Slicer must be restarted. Do you want to restart now ?");
QMessageBox::StandardButton answer = QMessageBox::question(nullptr, tr("Restart slicer ?"), message);
restartConfirmed = (answer == QMessageBox::StandardButton::Yes);
}
if (restartConfirmed)
{
qSlicerCoreApplication::application()->restart();
}
}

// --------------------------------------------------------------------------
void qSlicerExtensionsManagerModel::onInstallDownloadProgress(
qSlicerExtensionDownloadTask* task, qint64 received, qint64 total)
Expand Down
26 changes: 26 additions & 0 deletions Base/QTCore/qSlicerExtensionsManagerModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,32 @@ public slots:
/// \sa installExtension, scheduleExtensionForUninstall, uninstallScheduledExtensions
bool downloadAndInstallExtensionByName(const QString& extensionName, bool installDependencies = true, bool waitForCompletion = false);

/// \brief Download and install an extension from the extensions server.
///
/// This function allows the user to download and install an extension
/// along with its dependencies from the extensions server. By default,
/// it will prompt the user to confirm the installation and restart of
/// the application after installation.
///
/// When the testing mode is enabled, the function installs the extension
/// and its dependencies without any confirmation dialogs. In this case,
/// the application is not automatically restarted.
///
/// If you wish to skip the confirmation dialogs during installation
/// without enabling testing mode, you can call setInteractive(false) on
/// the extensions manager model before invoking this function.
///
/// To prevent the application from automatically restarting after the
/// installation is completed, set the \a restart parameter to false.
///
/// \param extensionName The name of the extension to be installed.
/// \param restart Set to false to prevent automatic application restart (default: true).
///
/// \sa setInteractive
/// \sa isExtensionInstalled, installExtension, updateExtensionsMetadataFromServer, downloadAndInstallExtensionByName
/// \sa qSlicerCoreApplication::testAttribute, qSlicerCoreApplication::AA_EnableTesting, qSlicerCoreApplication::restart
void installExtensionFromServer(const QString& extensionName, bool restart = true);

/// \brief Schedule \a extensionName of uninstall
/// Tell the application to uninstall \a extensionName when it will restart
/// An extension scheduled for uninstall can be effectively uninstalled by calling
Expand Down

0 comments on commit bda5198

Please sign in to comment.