void AbstractRepository::process(Job *job,
        const QList<InstallOperation *> &install_, DWORD programCloseType,
        bool printScriptOutput, bool interactive)
{
    QDir d;

    QList<InstallOperation *> install = install_;

    // reoder the operations if a package is updated. In this case it is better
    // to uninstall the old first and then install the new one.
    if (install.size() == 2) {
        InstallOperation* first = install.at(0);
        InstallOperation* second = install.at(1);
        if (first->package == second->package &&
                first->install && !second->install) {
            install.insert(0, second);
            install.removeAt(2);
        }
    }

    // search for PackageVersion objects
    QList<PackageVersion*> pvs;
    for (int i = 0; i < install.size(); i++) {
        InstallOperation* op = install.at(i);

        QString err;
        PackageVersion* pv = op->findPackageVersion(&err);
        if (!err.isEmpty()) {
            job->setErrorMessage(QString(
                    QObject::tr("Cannot find the package version %1 %2: %3")).
                    arg(op->package).
                    arg(op->version.getVersionString()).
                    arg(err));
            break;
        }
        if (!pv) {
            job->setErrorMessage(QString(
                    QObject::tr("Cannot find the package version %1 %2")).
                    arg(op->package).
                    arg(op->version.getVersionString()));
            break;
        }
        pvs.append(pv);
    }

    if (job->shouldProceed()) {
        for (int j = 0; j < pvs.size(); j++) {
            PackageVersion* pv = pvs.at(j);
            pv->lock();
        }
    }

    int n = install.count();

    // where the binary was downloaded
    QStringList dirs;

    // names of the binaries relative to the directory
    QStringList binaries;

    // 70% for downloading the binaries
    if (job->shouldProceed()) {
        // downloading packages
        for (int i = 0; i < install.count(); i++) {
            InstallOperation* op = install.at(i);
            PackageVersion* pv = pvs.at(i);
            if (op->install) {
                QString txt = QObject::tr("Downloading %1").arg(
                        pv->toString());

                Job* sub = job->newSubJob(0.7 / n, txt, true, true);

                // dir is not the final installation directory. It can be
                // changed later during the installation.
                QString dir = op->where;
                if (dir.isEmpty()) {
                    dir = pv->getIdealInstallationDirectory();
                }
                dir = WPMUtils::findNonExistingFile(dir, "");

                if (d.exists(dir)) {
                    sub->setErrorMessage(
                            QObject::tr("Directory %1 already exists").
                            arg(dir));
                    dirs.append("");
                    binaries.append("");
                } else {
                    dirs.append(dir);

                    QString binary = pv->download_(sub, dir, interactive);
                    binaries.append(QFileInfo(binary).fileName());
                }
            } else {
                dirs.append("");
                binaries.append("");
                job->setProgress(job->getProgress() + 0.7 / n);
            }

            if (!job->shouldProceed())
                break;
        }
    }

    // 10% for stopping the packages
    if (job->shouldProceed()) {
        for (int i = 0; i < install.count(); i++) {
            InstallOperation* op = install.at(i);
            PackageVersion* pv = pvs.at(i);
            if (!op->install) {
                Job* sub = job->newSubJob(0.1 / n,
                        QObject::tr("Stopping the package %1 of %2").
                        arg(i + 1).arg(n));
                pv->stop(sub, programCloseType, printScriptOutput);
                if (!sub->getErrorMessage().isEmpty()) {
                    job->setErrorMessage(sub->getErrorMessage());
                    break;
                }
            } else {
                job->setProgress(job->getProgress() + 0.1 / n);
            }
        }
    }

    int processed = 0;

    // 19% for removing/installing the packages
    if (job->shouldProceed()) {
        // installing/removing packages
        for (int i = 0; i < install.count(); i++) {
            InstallOperation* op = install.at(i);
            PackageVersion* pv = pvs.at(i);
            QString txt;
            if (op->install)
                txt = QString(QObject::tr("Installing %1")).arg(
                        pv->toString());
            else
                txt = QString(QObject::tr("Uninstalling %1")).arg(
                        pv->toString());

            Job* sub = job->newSubJob(0.19 / n, txt, true, true);
            if (op->install) {
                QString dir = dirs.at(i);
                QString binary = binaries.at(i);

                if (op->where.isEmpty()) {
                    // if we are not forced to install in a particular
                    // directory, we try to use the ideal location
                    QString try_ = pv->getIdealInstallationDirectory();
                    if (WPMUtils::pathEquals(try_, dir) ||
                            (!d.exists(try_) && d.rename(dir, try_))) {
                        dir = try_;
                    } else {
                        try_ = pv->getSecondaryInstallationDirectory();
                        if (WPMUtils::pathEquals(try_, dir) ||
                                (!d.exists(try_) && d.rename(dir, try_))) {
                            dir = try_;
                        } else {
                            try_ = WPMUtils::findNonExistingFile(try_, "");
                            if (WPMUtils::pathEquals(try_, dir) ||
                                    (!d.exists(try_) && d.rename(dir, try_))) {
                                dir = try_;
                            }
                        }
                    }
                } else {
                    if (d.exists(op->where)) {
                        if (!WPMUtils::pathEquals(op->where, dir)) {
                            // we should install in a particular directory, but it
                            // exists.
                            Job* djob = sub->newSubJob(1,
                                    QObject::tr("Deleting temporary directory %1").
                                    arg(dir));
                            QDir ddir(dir);
                            WPMUtils::removeDirectory(djob, ddir);
                            job->setErrorMessage(QObject::tr(
                                    "Cannot install %1 into %2. The directory already exists.").
                                    arg(pv->toString(true)).arg(op->where));
                            break;
                        }
                    } else {
                        if (d.rename(dir, op->where))
                            dir = op->where;
                        else {
                            // we should install in a particular directory, but it
                            // exists.
                            Job* djob = sub->newSubJob(1,
                                    QObject::tr("Deleting temporary directory %1").
                                    arg(dir));
                            QDir ddir(dir);
                            WPMUtils::removeDirectory(djob, ddir);
                            job->setErrorMessage(QObject::tr(
                                    "Cannot install %1 into %2. Cannot rename %3.").
                                    arg(pv->toString(true), op->where, dir));
                            break;
                        }
                    }
                }

                pv->install(sub, dir, binary, printScriptOutput,
                        programCloseType);
            } else
                pv->uninstall(sub, printScriptOutput, programCloseType);

            if (!job->shouldProceed())
                break;

            processed = i + 1;
        }
    }

    // removing the binaries if we should not proceed
    if (!job->shouldProceed()) {
        for (int i = processed; i < dirs.count(); i++) {
            QString dir = dirs.at(i);
            if (!dir.isEmpty()) {
                QString txt = QObject::tr("Deleting %1").arg(dir);

                Job* sub = job->newSubJob(0.01 / dirs.count(), txt, true, false);
                QDir ddir(dir);
                WPMUtils::removeDirectory(sub, ddir);
            } else {
                job->setProgress(job->getProgress() + 0.01 / dirs.count());
            }
        }
    }

    for (int j = 0; j < pvs.size(); j++) {
        PackageVersion* pv = pvs.at(j);
        pv->unlock();
    }

    qDeleteAll(pvs);

    if (job->shouldProceed())
        job->setProgress(1);

    job->complete();
}
void SettingsFrame::on_buttonBox_clicked(QAbstractButton *button)
{
    MainWindow* mw = MainWindow::getInstance();

    if (mw->hardDriveScanRunning) {
        mw->addErrorMessage(QObject::tr("Cannot change settings now. The hard drive scan is running."));
        return;
    }

    QString err;
    PackageVersion* locked = PackageVersion::findLockedPackageVersion(&err);
    if (locked) {
        err = QObject::tr("Cannot find locked package versions: %1").
                arg(err);
        mw->addErrorMessage(err);
        delete locked;
        return;
    }

    if (locked) {
        QString msg(QObject::tr("Cannot change settings now. The package %1 is locked by a currently running installation/removal."));
        mw->addErrorMessage(msg.arg(locked->toString()));
        delete locked;
        return;
    }

    QStringList list = getRepositoryURLs();

    if (err.isEmpty() && list.count() == 0)
        err = QObject::tr("No repositories defined");

    if (err.isEmpty()) {
        err = WPMUtils::checkInstallationDirectory(getInstallationDirectory());
    }

    QList<QUrl*> urls;
    if (err.isEmpty()) {
        for (int i = 0; i < list.count(); i++) {
            QUrl* url = new QUrl(list.at(i));
            urls.append(url);
            if (!url->isValid()) {
                err = QString(QObject::tr("%1 is not a valid repository address")).arg(
                        list.at(i));
                break;
            }
        }
    }

    if (err.isEmpty()) {
        WPMUtils::setInstallationDirectory(getInstallationDirectory());
        WPMUtils::setCloseProcessType(getCloseProcessType());
    }

    bool repsChanged = false;

    if (err.isEmpty()) {
        QList<QUrl*> oldList = Repository::getRepositoryURLs(&err);
        repsChanged = oldList.count() != urls.count();
        if (!repsChanged) {
            for (int i = 0; i < oldList.count(); i++) {
                if ((*oldList.at(i)) != (*urls.at(i))) {
                    repsChanged = true;
                    break;
                }
            }
        }
        qDeleteAll(oldList);
        oldList.clear();
    }

    if (err.isEmpty()) {
        if (repsChanged) {
            if (mw->reloadRepositoriesThreadRunning) {
                err = QObject::tr("Cannot change settings now. The repositories download is running.");
            } else {
                Repository::setRepositoryURLs(urls, &err);
                if (err.isEmpty()) {
                    mw->closeDetailTabs();
                    mw->recognizeAndLoadRepositories(false);
                }
            }
        }
    }

    qDeleteAll(urls);
    urls.clear();

    if (err.isEmpty()) {
        WindowsRegistry m(HKEY_LOCAL_MACHINE, false, KEY_ALL_ACCESS);
        WindowsRegistry wr = m.createSubKey(
                "Software\\Npackd\\Npackd\\InstallationDirs", &err,
                KEY_ALL_ACCESS);

        QStringList dirs;
        for (int i = 0; i < this->ui->comboBoxDir->count(); i++)
            dirs.append(this->ui->comboBoxDir->itemText(i));
        if (err.isEmpty()) {
            wr.saveStringList(dirs);
        }

        // it is not important, whether the list of directories is saved or not
        err = "";
    }

    if (!err.isEmpty())
        mw->addErrorMessage(err, err, true, QMessageBox::Critical);
}