Qt Installer Framework Offline Update - how?

installation, qif, qt, qt-installer

Solution

I faced the same problem too. So I have downloaded the latest snapshot and studied samples. One in particular is very helpful : dynamicpage

I didn't succeed to show a popup warning to the user when he's choosing an existing location, so I have found a work around: instead, a red label is shown under the selected directory.

This is not really a solution for updating component by component, but you will be able to continue installation process.

First of all, we need to replace the default page "TargetDirectory".

In file `installerscript.qs`, this is what you need to add:

// Constructor
function Component()
{
    component.loaded.connect(this, Component.prototype.installerLoaded);
    installer.setDefaultPageVisible(QInstaller.TargetDirectory, false);
}

// Utility function like QString QDir::toNativeSeparators(const QString & pathName) [static]
var Dir = new function () {
    this.toNativeSparator = function (path) {
        if (installer.value("os") == "win")
            return path.replace(/\//g, '\\');
        return path;
    }
};

// Called as soon as the component was loaded
Component.prototype.installerLoaded = function()
{
    if (installer.addWizardPage(component, "TargetWidget", QInstaller.TargetDirectory)) {
        var widget = gui.pageWidgetByObjectName("DynamicTargetWidget");
        if (widget != null) {
            widget.targetDirectory.textChanged.connect(this, Component.prototype.targetChanged);
            widget.targetChooser.clicked.connect(this, Component.prototype.chooseTarget);

            widget.windowTitle = "Installation Folder";
            widget.targetDirectory.text = Dir.toNativeSparator(installer.value("TargetDir"));
        }
    }
}

// Callback when one is clicking on the button to select where to install your application
Component.prototype.chooseTarget = function () {
    var widget = gui.pageWidgetByObjectName("DynamicTargetWidget");
    if (widget != null) {
        var newTarget = QFileDialog.getExistingDirectory("Choose your target directory.", widget.targetDirectory.text);
        if (newTarget != "") {
            widget.targetDirectory.text = Dir.toNativeSparator(newTarget);
        }
    }
}

Component.prototype.targetChanged = function (text) {
    var widget = gui.pageWidgetByObjectName("DynamicTargetWidget");
    if (widget != null) {
        if (text != "") {
            widget.complete = true;
            installer.setValue("TargetDir", text);
            if (installer.fileExists(text + "/components.xml")) {
                var warning = "<font color='red'>" + qsTr("A previous installation exists in this folder. If you wish to continue, everything will be overwritten.") + "</font>";
                widget.labelOverwrite.text = warning;
            } else {
                widget.labelOverwrite.text = "";
            }
            return;
        }
        widget.complete = false;
    }
}

In file targetwidget.ui

This is actually not the real .ui file, just for explanation purpose. In the end of this file, I have added an empty QLabel called `labelOverwrite`. The text is filled with red message in `targetChanged` callback.

<widget class="QWidget" name="TargetWidget">
  <layout class="QVBoxLayout" name="verticalLayout">
    <item>
      <widget class="QLabel" name="label">
       <property name="text">
        <string>Please specify the folder where Miam-Player will be installed.</string>
       </property>
      </widget>
    </item>
    <item>
      <layout class="QHBoxLayout" name="horizontalLayout">
       <item>
        <widget class="QLineEdit" name="targetDirectory"/>
       </item>
       <item>
        <widget class="QToolButton" name="targetChooser"/>
       </item>
      </layout>
    </item>
    <item>
      <widget class="QLabel" name="labelOverwrite"/>
    </item>
  </layout>
</widget>

Finally, don't forget to modify your existing file package.xml

<?xml version="1.0" encoding="UTF-8"?>
<Package>
    <DisplayName>Miam-Player</DisplayName>
    <Description>Miam-Player is the main program. It is required and cannot be unselected.</Description>
    <Name>org.miamplayer.core</Name>
    <Script>installscript.qs</Script>
    ...
    <UserInterfaces>
        <UserInterface>targetwidget.ui</UserInterface>
    </UserInterfaces>
</Package>

Problem

I've been able to create an installation for my software. However, I can't figure out how to create another installer which could update previous installation. I have updated component versions, software version and release dates, but whenever I run second installation over the folder with pre-installed software - I'm getting `The folder you selected already exists and contains an installation. Chose different target for installation.` Any hint on how to update an existing installation using Qt installer Framework would be very welcome!

Original source