|
1 | 1 | #include "ScmEditorDialog.hpp" |
2 | 2 | #include "ui_scmEditorDialog.h" |
| 3 | +#include "SkyCultureConverter.hpp" |
| 4 | +#include "qmicroz.h" |
3 | 5 | #include <QFileDialog> |
4 | 6 | #include <QFileSystemModel> |
5 | 7 | #include <QMessageBox> |
| 8 | +#include <QMimeDatabase> |
| 9 | +#include <QtConcurrent/QtConcurrent> |
| 10 | +#include <QFutureWatcher> |
6 | 11 |
|
7 | 12 | ScmEditorDialog::ScmEditorDialog() |
8 | 13 | : StelDialog("ScmEditorDialog") |
@@ -88,31 +93,177 @@ void ScmEditorDialog::createDialogContent() |
88 | 93 | connect(ui->saveLabelsBtn, &QPushButton::clicked, this, &ScmEditorDialog::saveLabels); |
89 | 94 | updateLabelsSavedLabel(false); |
90 | 95 |
|
91 | | - /* ============================================= SCM importer/converter ============================================= */ |
| 96 | + /* ============================================= SCM importer/converter */ |
92 | 97 | auto fsModel = new QFileSystemModel(this); |
93 | 98 | fsModel->setRootPath(QDir::homePath()); |
94 | 99 | ui->fileSystem->setModel(fsModel); |
95 | 100 | ui->fileSystem->setRootIndex(fsModel->index(QDir::homePath())); |
96 | 101 |
|
97 | 102 | connect(ui->fileSystem, |
98 | | - &QTreeView::doubleClicked, |
| 103 | + &QTreeView::clicked, |
99 | 104 | this, |
100 | 105 | [this, fsModel](const QModelIndex &idx) |
101 | 106 | { |
102 | 107 | const QString path = fsModel->filePath(idx); |
103 | 108 | ui->filePathLineEdit->setText(path); |
104 | 109 | }); |
105 | | - connect(ui->pushButton, &QPushButton::clicked, this, [this]() |
| 110 | + |
| 111 | + connect( |
| 112 | + ui->pushButton, |
| 113 | + &QPushButton::clicked, |
| 114 | + this, |
| 115 | + [this]() |
| 116 | + { |
| 117 | + const QString path = ui->filePathLineEdit->text(); |
| 118 | + if (path.isEmpty()) |
| 119 | + { |
| 120 | + ui->filePathLineEdit->setText("Please select a file."); |
| 121 | + return; |
| 122 | + } |
| 123 | + |
| 124 | + qDebug() << "Selected file:" << path; |
| 125 | + |
| 126 | + // Create a temporary directory for extraction |
| 127 | + QString baseName = QFileInfo(path).fileName(); // e.g. "foo.zip" |
| 128 | + int dotPos = baseName.indexOf('.'); |
| 129 | + QString stem = |
| 130 | + (dotPos == -1) ? baseName : baseName.left(dotPos); // Extract the part before the first dot |
| 131 | + const QString tempDir = QDir::tempPath() + "/skycultures/" + stem; |
| 132 | + QDir().mkpath(tempDir); |
| 133 | + QDir tempFolder(tempDir); |
| 134 | + |
| 135 | + ui->pushButton->setEnabled(false); |
| 136 | + |
| 137 | + // Run conversion in a background thread |
| 138 | + QFuture<QString> future = QtConcurrent::run( |
| 139 | + [path, tempDir, tempFolder]() mutable -> QString |
| 140 | + { |
| 141 | + QString baseName = QFileInfo(path).fileName(); // e.g. "foo.zip" |
| 142 | + QString stem = baseName.left(baseName.lastIndexOf('.')); |
| 143 | + const QString tempDir = QDir::tempPath() + "/skycultures/" + stem; |
| 144 | + // Check if the file is a valid archive |
| 145 | + QMimeDatabase db; |
| 146 | + QMimeType mime = db.mimeTypeForFile(path, QMimeDatabase::MatchContent); |
| 147 | + |
| 148 | + static const QStringList archiveTypes = {QStringLiteral("application/zip"), |
| 149 | + QStringLiteral("application/x-tar"), |
| 150 | + QStringLiteral("application/x-7z-compressed"), |
| 151 | + QStringLiteral("application/gzip"), |
| 152 | + QStringLiteral("application/x-rar-compressed"), |
| 153 | + QStringLiteral("application/vnd.rar")}; |
| 154 | + |
| 155 | + if (!archiveTypes.contains(mime.name())) |
| 156 | + { |
| 157 | + return QStringLiteral( |
| 158 | + "Please select a valid archive file (zip, tar, rar, 7z, gzip…)"); |
| 159 | + } |
| 160 | + |
| 161 | + try |
| 162 | + { |
| 163 | + QMicroz::extract(path, tempDir); |
| 164 | + qDebug() << "Archive extracted to:" << tempDir; |
| 165 | + } |
| 166 | + catch (const std::exception &e) |
| 167 | + { |
| 168 | + return QString("Error extracting archive: %1").arg(e.what()); |
| 169 | + } |
| 170 | + |
| 171 | + QStringList extracted_files = |
| 172 | + tempFolder.entryList(QDir::AllEntries | QDir::NoDotAndDotDot); |
| 173 | + qDebug() << "Extracted files:" << extracted_files.length(); |
| 174 | + for (const QString &file : extracted_files) |
| 175 | + { |
| 176 | + qDebug() << " - " << file; |
| 177 | + } |
| 178 | + if (extracted_files.isEmpty()) |
| 179 | + { |
| 180 | + return "No files found in the archive."; |
| 181 | + } |
| 182 | + |
| 183 | + // set source as the folder that gets converted |
| 184 | + QString source; |
| 185 | + if (extracted_files.contains("info.ini")) |
| 186 | + source = tempDir; |
| 187 | + else if (extracted_files.length() == 1) |
| 188 | + source = tempDir + "/" + extracted_files.first(); |
| 189 | + else |
| 190 | + return "Invalid archive structure. Expected 'info.ini' or a single subfolder."; |
| 191 | + |
| 192 | + qDebug() << "Source for conversion:" << source; |
| 193 | + |
| 194 | + // Destination is where the converted files will be saved |
| 195 | + QString destDir = |
| 196 | + QDir::homePath() + "/Documents/SkyCultureConverter/" + |
| 197 | + QFileInfo(path).fileName().left(QFileInfo(path).fileName().lastIndexOf('.')); |
| 198 | + qDebug() << "Destination for conversion:" << destDir; |
| 199 | + |
| 200 | + SkyCultureConverter::ReturnValue result; |
| 201 | + |
| 202 | + try |
| 203 | + { |
| 204 | + result = SkyCultureConverter::convert(source, destDir); |
| 205 | + } |
| 206 | + catch (const std::exception &e) |
| 207 | + { |
| 208 | + return QString("Error during conversion: %1").arg(e.what()); |
| 209 | + } |
| 210 | + |
| 211 | + QString msg; |
| 212 | + switch (result) |
| 213 | + { |
| 214 | + case SkyCultureConverter::ReturnValue::CONVERT_SUCCESS: |
| 215 | + msg = "Conversion completed successfully."; |
| 216 | + break; |
| 217 | + case SkyCultureConverter::ReturnValue::ERR_OUTPUT_DIR_EXISTS: |
| 218 | + msg = "Output directory already exists."; |
| 219 | + break; |
| 220 | + case SkyCultureConverter::ReturnValue::ERR_INFO_INI_NOT_FOUND: |
| 221 | + msg = "info.ini not found in the archive."; |
| 222 | + break; |
| 223 | + case SkyCultureConverter::ReturnValue::ERR_OUTPUT_DIR_CREATION_FAILED: |
| 224 | + msg = "Failed to create output directory."; |
| 225 | + break; |
| 226 | + case SkyCultureConverter::ReturnValue::ERR_OUTPUT_FILE_WRITE_FAILED: |
| 227 | + msg = "Failed to write output file."; |
| 228 | + break; |
| 229 | + default: |
| 230 | + msg = "Unknown error."; |
| 231 | + break; |
| 232 | + } |
| 233 | + qDebug() << "Conversion result:" << msg; |
| 234 | + return msg; |
| 235 | + }); |
| 236 | + |
| 237 | + // Watcher to re-enable the button & report result on UI thread |
| 238 | + auto *watcher = new QFutureWatcher<QString>(this); |
| 239 | + connect(watcher, |
| 240 | + &QFutureWatcher<QString>::finished, |
| 241 | + this, |
| 242 | + [this, watcher, tempFolder]() mutable |
| 243 | + { |
| 244 | + QString resultText = watcher->future().result(); |
| 245 | + ui->filePathLineEdit->setText(resultText); |
| 246 | + tempFolder.removeRecursively(); |
| 247 | + ui->pushButton->setEnabled(true); |
| 248 | + watcher->deleteLater(); |
| 249 | + }); |
| 250 | + watcher->setFuture(future); |
| 251 | + |
| 252 | + qDebug() << "Conversion ended."; |
| 253 | + }); |
| 254 | + // Reset the dialog when switching tabs |
| 255 | + const int importPage = ui->tabs->indexOf(ui->Import); |
| 256 | + connect(ui->tabs, |
| 257 | + &QTabWidget::currentChanged, |
| 258 | + this, |
| 259 | + [this, importPage](int idx) |
106 | 260 | { |
107 | | - const QString path = ui->filePathLineEdit->text(); |
108 | | - if (path.isEmpty()) |
| 261 | + if (idx != importPage) |
109 | 262 | { |
110 | | - QMessageBox::warning(dialog, tr("No file selected"), tr("Please pick a file first.")); |
111 | | - return; |
| 263 | + ui->filePathLineEdit->clear(); |
112 | 264 | } |
113 | | - qDebug() << "Importing file:" << path; |
114 | 265 | }); |
115 | | - /* ================================================================================================================== */ |
| 266 | + /* ==================================================================== */ |
116 | 267 | } |
117 | 268 |
|
118 | 269 | void ScmEditorDialog::saveLabels() |
|
0 commit comments