Controller Scripting

For each installer, you can specify a control script that interacts with certain parts of the installer's UI or functionality. The control script can add and remove pages to the wizard, change existing pages, do additional checks, and interact with the UI by simulating user clicks. This allows for example unattended installations.

The script format has to be compatible with QJSEngine.

This section describes the functions that are called to implement such a control script. It also gives an overview of installer pages and the widgets that are available on each page, such as push buttons, radio buttons, and line edits.

Writing Control Scripts

A minimal valid script needs to contain at least a constructor, which can look like this:

function Controller()
{
}

The following example presents a more advanced script that uses the gui JavaScript global object methods to set a new page title and welcome message on the introduction page and to automatically click the Next button on the target directory page:

function Controller()
{
}

Controller.prototype.IntroductionPageCallback = function()
{
    var widget = gui.currentPageWidget(); // get the current wizard page
    if (widget != null) {
        widget.title = "New title."; // set the page title
        widget.MessageLabel.setText("New Message."); // set the welcome text
    }
}

Controller.prototype.TargetDirectoryPageCallback = function()
{
    gui.clickButton(buttons.NextButton); // automatically click the Next button
}

For more information about the JavaScript global objects that you can use in control scripts, see Scripting API.

In addition to the predefined global objects, the scripting API supports working with other objects derived from QObject. In the above code example the gui.currentPageWidget() method returns a widget of type QWidget.

The scripting API makes use of Qt's object trees. Widgets derived from QObject export their named child objects as properties for the JavaScript object, where the name of the property is the same as the child object's QObject::objectName. The default properties and their access functions of objects derived from QObject can also be used in the scripts.

For example, in the above code the MessageLabel object from class QLabel is a child of the widget. The setText() is the setter access function for its QLabel::text property.

In addition to properties, the signals and public slots of objects derived from QObject can be used in both controller and component scripts.

Predefined Installer Pages

The QInstaller JavaScript object provides access to the following predefined installer pages:

  • Introduction
  • TargetDirectory
  • ComponentSelection
  • LicenseCheck
  • StartMenuSelection
  • ReadyForInstallation
  • PerformInstallation
  • InstallationFinished

The buttons JavaScript object provides a set of buttons that can be used on installer pages.

The following sections describe the functions that you can implement to interact with installer pages and the widgets that are available on each page.

Introduction Page

Implement the Controller.prototype.IntroductionPageCallback() function to interact with widgets on the introduction page.

Wizard buttons:

  • NextButton
  • CancelButton
WidgetsBrief Description
ErrorLabelDisplays an error message.
MessageLabelDisplays a message. By default, it displays the "Welcome to the <Name> Setup" message.
InformationLabelDisplays progress information.
Radio ButtonsBrief Description
PackageManagerRadioButtonThe package manager radio button shown on the page while running as maintenance tool.
UpdaterRadioButtonThe updater radio button shown on the page while running as maintenance tool.
UninstallerRadioButtonThe uninstaller radio button shown on the page while running as maintenance tool. Selected by default.
Progress BarBrief Description
InformationProgressBarThe progress bar shown while fetching remote packages.
Qt Core FeatureBrief Description
packageManagerCoreTypeChanged()Connect to this signal if you want to be notified when the type of maintenance tool changes.

Note: The signal is only emitted when the user has started the binary as so called maintenance tool (after the installation) and switches between the radio buttons.

Example code:

function Controller()
{
    var widget = gui.pageById(QInstaller.Introduction); // get the introduction wizard page
    if (widget != null)
        widget.packageManagerCoreTypeChanged.connect(onPackageManagerCoreTypeChanged);
}

onPackageManagerCoreTypeChanged = function()
{
    console.log("Is Updater: " + installer.isUpdater());
    console.log("Is Uninstaller: " + installer.isUninstaller());
    console.log("Is Package Manager: " + installer.isPackageManager());
}

License Agreement Page

Implement the Controller.prototype.LicenseAgreementPageCallback() function to interact with widgets on the license agreement page.

Wizard buttons:

  • NextButton
  • CancelButton
  • BackButton
WidgetsBrief Description
LicenseListWidgetLists the available licenses.
LicenseTextBrowserShows the content of the selected license file.
AcceptLicenseLabelShows the text next to the accept license check box.
AcceptLicenseCheckBoxAccepts the license agreement.

Target Directory Page

Implement the Controller.prototype.TargetDirectoryPageCallback() function to interact with widgets on the target directory selection page.

Wizard buttons:

  • NextButton
  • CancelButton
  • BackButton
WidgetsBrief Description
MessageLabelDisplays a message.
TargetDirectoryLineEditDisplays the value of the installation's target directory.
WarningLabelDisplays a warning.

Component Selection Page

Implement the Controller.prototype.ComponentSelectionPageCallback() function to interact with widgets on the component selection page.

Wizard buttons:

  • NextButton
  • CancelButton
  • BackButton
MethodsBrief Description
selectAll()Selects all available packages if possible.
deselectAll()Deselects all available packages if possible.
selectDefault()Resets the checked state of available packages to their initial state.
selectComponent(id)Selects the package with id (string).
deselectComponent(id)Deselects the package with id (string).
Push ButtonsBrief Description
SelectAllComponentsButtonSelects all available packages if possible.
DeselectAllComponentsButtonDeselects all available packages if possible.
SelectDefaultComponentsButtonResets the checked state of available packages to their initial state.
ResetComponentsButtonResets to already installed components.
FetchCategoryButtonFetch components from a category.
WidgetsBrief Description
CategoryGroupBoxContains checkboxes for selecting repository categories.

Installer Framework 3.1 introduces repository categories as a new feature. When you use an installer that contains repository categories, you can select a category by its display name, fetch its contents, and then select the included components for installation.

You can fetch the components from a category as follows:

Controller.prototype.ComponentSelectionPageCallback = function()
{
    var page = gui.pageWidgetByObjectName("ComponentSelectionPage");

    // if CategoryGroupBox is visible, check one of the checkboxes
    // and click fetch button before selecting any components
    var groupBox = gui.findChild(page, "CategoryGroupBox");
    if (groupBox) {
        console.log("groupBox found");
        // findChild second argument is the display name of the checkbox
        var checkBox = gui.findChild(page, "Archive");
        if (checkBox) {
            console.log("checkBox found");
            console.log("checkBox name: " + checkBox.text);
            if (checkBox.checked == false) {
                checkBox.click();
                var fetchButton = gui.findChild(page, "FetchCategoryButton");
                if (fetchButton) {
                    console.log("fetchButton found");
                    fetchButton.click();
                } else {
                    console.log("fetchButton NOT found");
                }
            }
        } else {
            console.log("checkBox NOT found");
        }
    } else {
        console.log("groupBox NOT found");
    }
    // you can now select components from the fetched category
}

Start Menu Directory Page

Implement the Controller.prototype.StartMenuDirectoryPageCallback() function to interact with widgets on the ready for installation page.

Wizard buttons:

  • NextButton
  • CancelButton
  • BackButton
WidgetsBrief Description
StartMenuPathLineEditShows the directory where to create the program's shortcut.

Ready for Installation Page

Implement the Controller.prototype.ReadyForInstallationPageCallback() function to interact with widgets on the ready for installation page.

Wizard buttons:

  • CommitButton
  • CancelButton
  • BackButton
WidgetsBrief Description
MessageLabelDisplays a message.
TaskDetailsBrowserDisplays some more detailed information about the installation.

Perform Installation Page

Implement the Controller.prototype.PerformInstallationPageCallback() function to interact with widgets on the perform installation page.

Wizard buttons:

  • CommitButton
  • CancelButton

Finished Page

Implement the Controller.prototype.FinishedPageCallback() function to interact with widgets on the installation finished page.

Wizard buttons:

  • CommitButton
  • CancelButton
  • FinishButton
WidgetsBrief Description
MessageLabelDisplays a message.
RunItCheckBoxText field that informs users that they can start an application after the installation process has finished.

Custom Pages

Custom pages are registered as Dynamic${ObjectName}, where ${ObjectName} is the object name set in the UI file. Thus, the Dynamic${ObjectName}Callback() function is called. Widgets can be addressed using their object names (from the UI file).

Example code:

function Component()
{
    // add page with widget \c SomePageWidget before the target directory page
    installer.addWizardPage(component, "SomePageWidget", QInstaller.TargetDirectory)
}

Component.prototype.DynamicSomePageWidgetCallback = function()
{
    var page = gui.pageWidgetByObjectName("DynamicSomePageWidget");
    page.myButton.click, //direct child of the UI file's widget
    page.someFancyWidget.subWidget.setText("foobar") // nested widget
}

Message Boxes

While executing the installer application, for example, the application might show some message boxes about an error that occurred. This is fine while running the application on the end user's system, but it might break automated test suites. To overcome this issue, all message boxes shown by the Qt Installer Framework are addressable by a specific identifier.

IdentifierPossible AnswersDescription
OverwriteTargetDirectoryYes, NoConfirmation for using an already existing directory as the target directory for installation.
installationErrorOK, Retry, IgnoreA fatal error occurred while performing the installation.
installationErrorWithRetryRetry, Ignore, CancelAn error occurred while performing the installation. End users can select Retry to try again.
AuthorizationErrorAbort, OKElevated permissions could not be acquired.
OperationDoesNotExistErrorAbort, IgnoreAn error occurred while trying to perform an operation, but the operation did not exist.
isAutoDependOnErrorOKAn error occurred while calling a package script. It was not possible to evaluate if the package has a auto dependency on other packages.
isDefaultErrorOKAn error occurred while calling a package script. It was not possible to evaluate if the package will be installed by default.
DownloadErrorRetry, CancelAn error occurred while downloading an archive hash from a remote repository. End users can select Retry to try again.
archiveDownloadErrorRetry, CancelAn error occurred while downloading a archive from a remote repository. End users can select Retry to try again.
WriteErrorOKAn error occurred while writing the maintenance tool.
ElevationErrorOKElevated permissions could not be acquired.
unknownOKAn unknown error occurred while removing a certain package.
ErrorOKGeneric error.
stopProcessesForUpdatesRetry, Ignore, CancelAn error occurred while updating a package. Some running application or process needs to be quit before the update can be performed. End users can select Retry to try again once they have been stopped.
Installer_Needs_To_Be_Local_ErrorOKThe installer binary was started from a network location, but the installation over network is not supported.
TargetDirectoryInUseNoThe installation's target directory already contains an installation.
WrongTargetDirectoryOKThe installation's target directory is a file or symlink.
AlreadyRunningOKAnother application instance is already running.

Example code:

function Controller()
{
    installer.autoRejectMessageBoxes;
    installer.setMessageBoxAutomaticAnswer("OverwriteTargetDirectory", QMessageBox.Yes);
    installer.setMessageBoxAutomaticAnswer("stopProcessesForUpdates", QMessageBox.Ignore);
}

© 2021 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. The Qt Company, Qt and their respective logos are trademarks of The Qt Company Ltd in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.