| 128 | } |
| 129 | |
| 130 | bool InstallationManager::extractFiles(QString extractPath, QString title, |
| 131 | bool showFilenames, bool silent) |
| 132 | { |
| 133 | TimeThis tt("InstallationManager::extractFiles"); |
| 134 | |
| 135 | // Callback for errors: |
| 136 | QString errorMessage; |
| 137 | auto errorCallback = [&errorMessage, this](std::wstring const& message) { |
| 138 | m_ArchiveHandler->cancel(); |
| 139 | errorMessage = QString::fromStdWString(message); |
| 140 | }; |
| 141 | |
| 142 | // The future that will hold the result: |
| 143 | QFuture<bool> future; |
| 144 | |
| 145 | if (silent) { |
| 146 | future = QtConcurrent::run([&]() -> bool { |
| 147 | return m_ArchiveHandler->extract(extractPath.toStdWString(), nullptr, nullptr, |
| 148 | errorCallback); |
| 149 | }); |
| 150 | future.waitForFinished(); |
| 151 | } else { |
| 152 | QProgressDialog* installationProgress = new QProgressDialog(m_ParentWidget); |
| 153 | ON_BLOCK_EXIT([=]() { |
| 154 | installationProgress->cancel(); |
| 155 | installationProgress->hide(); |
| 156 | installationProgress->deleteLater(); |
| 157 | }); |
| 158 | installationProgress->setWindowFlags(installationProgress->windowFlags() & |
| 159 | (~Qt::WindowContextHelpButtonHint)); |
| 160 | if (!title.isEmpty()) { |
| 161 | installationProgress->setWindowTitle(title); |
| 162 | } |
| 163 | installationProgress->setWindowModality(Qt::WindowModal); |
| 164 | installationProgress->setFixedSize(600, 100); |
| 165 | |
| 166 | // Turn off auto-reset otherwize the progress dialog is reset before the end. This |
| 167 | // is kind of annoying because updateProgress consider percentage of progression |
| 168 | // through the archive (pack), while we are waiting for extracting archive entries, |
| 169 | // so the percentage of in updateProgress is not really related to the percentage of |
| 170 | // files extracted... |
| 171 | installationProgress->setAutoReset(false); |
| 172 | |
| 173 | // Note: Using a loop with a progressUpdate() that only wake-up the loop. The |
| 174 | // event-loop will be used in a loop and not via exec() because connecting to |
| 175 | // QProgressDialog::setValue and using .exec() creates huge recursion that leads to |
| 176 | // stack-overflow. See https://bugreports.qt.io/browse/QTBUG-10561 |
| 177 | QEventLoop loop; |
| 178 | connect(this, &InstallationManager::progressUpdate, &loop, &QEventLoop::wakeUp, |
| 179 | Qt::QueuedConnection); |
| 180 | |
| 181 | // Cancelling progress only cancel the extraction, we do not force exiting the |
| 182 | // event-loop: |
| 183 | connect(installationProgress, &QProgressDialog::canceled, [this]() { |
| 184 | m_ArchiveHandler->cancel(); |
| 185 | }); |
| 186 | |
| 187 | std::mutex mutex; |