File indexing completed on 2024-04-21 05:48:33
0001 /* 0002 SPDX-FileCopyrightText: 2019 Farid Boudedja <farid.boudedja@gmail.com>, 2023 Jonathan Esk-Riddell <jr@jriddell.org> 0003 SPDX-License-Identifier: GPL-3.0-or-later 0004 */ 0005 0006 #include "mainwindow.h" 0007 #include "mainapplication.h" 0008 #include "common.h" 0009 #include "fetchisojob.h" 0010 #include "imagewriter.h" 0011 #include "isoverifier.h" 0012 #include "isoimagewriter_debug.h" 0013 0014 #include <QLabel> 0015 #include <QTimer> 0016 #include <QAction> 0017 #include <QThread> 0018 #include <QMimeData> 0019 #include <QDropEvent> 0020 #include <QVBoxLayout> 0021 #include <QHBoxLayout> 0022 #include <QFileDialog> 0023 #include <QMessageBox> 0024 #include <QInputDialog> 0025 #include <QStandardPaths> 0026 #include <KFormat> 0027 #include <KIconLoader> 0028 #include <KPixmapSequence> 0029 #include <KLocalizedString> 0030 #include "isolineedit.h" 0031 0032 #include <KPixmapSequenceLoader> 0033 0034 MainWindow::MainWindow(QWidget *parent) 0035 : QMainWindow(parent), 0036 m_lastOpenedDir(), 0037 m_isWriting(false), 0038 m_enumFlashDevicesWaiting(false), 0039 m_externalProgressBar(this) 0040 { 0041 setupUi(); 0042 setAcceptDrops(true); 0043 0044 // Set initial directory 0045 m_lastOpenedDir = mApp->getInitialDir(); 0046 // Get path to ISO image from command line args (if supplied) 0047 QUrl isoImagePath = mApp->getInitialImage(); 0048 if (isoImagePath.isLocalFile()) { 0049 const QString path = isoImagePath.toLocalFile(); 0050 m_lastOpenedDir = path.left(path.lastIndexOf('/')); 0051 preprocessIsoImage(path); 0052 } else { 0053 m_isoImageLineEdit->setText(isoImagePath.toString()); 0054 } 0055 0056 // Load the list of USB flash devices 0057 QTimer::singleShot(0, this, &MainWindow::enumFlashDevices); 0058 } 0059 0060 void MainWindow::scheduleEnumFlashDevices() 0061 { 0062 if (m_isWriting) 0063 m_enumFlashDevicesWaiting = true; 0064 else 0065 enumFlashDevices(); 0066 } 0067 0068 void MainWindow::showInputDialog(const QString &title, const QString &body) 0069 { 0070 bool ok; 0071 QString text = QInputDialog::getText(this, title, body, QLineEdit::Normal, "", &ok); 0072 0073 emit inputTextReady(ok, text); 0074 } 0075 0076 void MainWindow::setupUi() 0077 { 0078 // Logo 0079 QLabel *logoLabel = new QLabel; 0080 logoLabel->setPixmap(KIconLoader::global()->loadIcon("org.kde.isoimagewriter", KIconLoader::Desktop)); 0081 logoLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); 0082 0083 QLabel *titleLabel = new QLabel; 0084 titleLabel->setTextFormat(Qt::RichText); 0085 titleLabel->setText(QStringLiteral("<h2 style='margin-bottom: 0;'>%1</h2>%2").arg(i18n("KDE ISO Image Writer")).arg(i18n("A quick and simple way to create a bootable USB drive."))); 0086 0087 QHBoxLayout *headerHBoxLayout = new QHBoxLayout; 0088 headerHBoxLayout->addWidget(logoLabel); 0089 headerHBoxLayout->addWidget(titleLabel); 0090 0091 m_centralStackedWidget = new QStackedWidget; 0092 m_centralStackedWidget->addWidget(createFormWidget()); 0093 m_centralStackedWidget->addWidget(createConfirmWidget()); 0094 m_centralStackedWidget->addWidget(createProgressWidget()); 0095 m_centralStackedWidget->addWidget(createSuccessWidget()); 0096 0097 QVBoxLayout *mainVBoxLayout = new QVBoxLayout; 0098 mainVBoxLayout->addLayout(headerHBoxLayout); 0099 mainVBoxLayout->addSpacing(15); 0100 mainVBoxLayout->addWidget(m_centralStackedWidget); 0101 0102 QWidget *centralWidget = new QWidget; 0103 centralWidget->setLayout(mainVBoxLayout); 0104 0105 setCentralWidget(centralWidget); 0106 } 0107 0108 QWidget* MainWindow::createFormWidget() 0109 { 0110 // Form 0111 m_isoImageLineEdit = new IsoLineEdit; 0112 m_isoImageLineEdit->setReadOnly(true); 0113 m_isoImageLineEdit->setPlaceholderText(i18n("Path to ISO image...")); 0114 connect(m_isoImageLineEdit, &IsoLineEdit::clicked, this, &MainWindow::openIsoImage); 0115 0116 m_isoImageSizeLabel = new QLabel; 0117 0118 QAction *openIsoImageAction = m_isoImageLineEdit->addAction( 0119 QIcon::fromTheme("folder-open"), QLineEdit::TrailingPosition); 0120 connect(openIsoImageAction, &QAction::triggered, this, &MainWindow::openIsoImage); 0121 0122 m_usbDriveComboBox = new QComboBox; 0123 0124 m_createButton = new QPushButton(i18n("Create")); 0125 connect(m_createButton, &QPushButton::clicked, this, &MainWindow::showConfirmMessage); 0126 0127 m_busyLabel = new QLabel; 0128 m_busyWidget = new QWidget; 0129 m_busySpinner = new KPixmapSequenceOverlayPainter(this); 0130 m_busySpinner->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); 0131 m_busySpinner->setWidget(m_busyWidget); 0132 m_busyWidget->setFixedSize(24, 24); 0133 0134 QHBoxLayout *footerBoxLayout = new QHBoxLayout; 0135 footerBoxLayout->addWidget(m_busyWidget); 0136 footerBoxLayout->addWidget(m_busyLabel); 0137 footerBoxLayout->addWidget(m_createButton, 0, Qt::AlignRight); 0138 0139 QHBoxLayout *isoImageLayout = new QHBoxLayout; 0140 isoImageLayout->addWidget(m_isoImageLineEdit); 0141 isoImageLayout->addWidget(m_isoImageSizeLabel); 0142 0143 QVBoxLayout *mainVBoxLayout = new QVBoxLayout; 0144 mainVBoxLayout->addWidget(new QLabel(i18n("Write this ISO image:"))); 0145 mainVBoxLayout->addLayout(isoImageLayout); 0146 mainVBoxLayout->addSpacing(5); 0147 mainVBoxLayout->addWidget(new QLabel(i18n("To this USB drive:"))); 0148 mainVBoxLayout->addWidget(m_usbDriveComboBox); 0149 mainVBoxLayout->addSpacing(15); 0150 mainVBoxLayout->addStretch(); 0151 mainVBoxLayout->addLayout(footerBoxLayout); 0152 0153 QWidget *formWidget = new QWidget; 0154 formWidget->setLayout(mainVBoxLayout); 0155 0156 return formWidget; 0157 } 0158 0159 QWidget* MainWindow::createConfirmWidget() 0160 { 0161 QLabel *iconLabel = new QLabel; 0162 iconLabel->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(QSize(64, 64))); 0163 iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); 0164 0165 static const QString overwriteMessage = i18n("Everything on the USB drive will " 0166 "be overwritten." 0167 "\n\nDo you want to continue?"); 0168 QLabel *messageLabel = new QLabel(overwriteMessage); 0169 connect(this, &MainWindow::downloadProgressChanged, messageLabel, [messageLabel, iconLabel, this] { 0170 iconLabel->setPixmap(QIcon::fromTheme("download").pixmap(QSize(64, 64))); 0171 messageLabel->setText(i18n("Downloading %1...", m_fetchIso->fetchUrl().toDisplayString())); 0172 }); 0173 connect(this, &MainWindow::verificationResult, messageLabel, [messageLabel, iconLabel] { 0174 messageLabel->setText(overwriteMessage); 0175 iconLabel->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(QSize(64, 64))); 0176 }); 0177 0178 QHBoxLayout *messageHBoxLayout = new QHBoxLayout; 0179 messageHBoxLayout->addWidget(iconLabel, 0, Qt::AlignTop); 0180 messageHBoxLayout->addWidget(messageLabel, 0, Qt::AlignTop); 0181 0182 QProgressBar *downloadProgressBar = new QProgressBar(); 0183 downloadProgressBar->setVisible(false); 0184 downloadProgressBar->setFormat(i18nc("Progress percent value", "%p%")); 0185 downloadProgressBar->setMinimum(0); 0186 downloadProgressBar->setMaximum(100); 0187 connect(this, &MainWindow::downloadProgressChanged, downloadProgressBar, &QProgressBar::show); 0188 connect(this, &MainWindow::downloadProgressChanged, downloadProgressBar, &QProgressBar::setValue); 0189 0190 QPushButton *abortButton = new QPushButton(i18n("Abort")); 0191 connect(abortButton, &QPushButton::clicked, this, &MainWindow::hideWritingProgress); 0192 0193 QPushButton *continueButton = new QPushButton(i18n("Continue")); 0194 connect(continueButton, &QPushButton::clicked, this, &MainWindow::writeIsoImage); 0195 connect(this, &MainWindow::downloadProgressChanged, continueButton, [continueButton] { continueButton->setEnabled(false); }); 0196 connect(this, &MainWindow::verificationResult, continueButton, [continueButton] { continueButton->setEnabled(true); }); 0197 0198 QHBoxLayout *buttonsHBoxLayout = new QHBoxLayout; 0199 buttonsHBoxLayout->addWidget(abortButton, 0, Qt::AlignLeft); 0200 buttonsHBoxLayout->addWidget(continueButton, 0, Qt::AlignRight); 0201 0202 QVBoxLayout *mainVBoxLayout = new QVBoxLayout; 0203 mainVBoxLayout->addLayout(messageHBoxLayout); 0204 mainVBoxLayout->addWidget(downloadProgressBar); 0205 mainVBoxLayout->addLayout(buttonsHBoxLayout); 0206 0207 QWidget *confirmWidget = new QWidget; 0208 confirmWidget->setLayout(mainVBoxLayout); 0209 0210 return confirmWidget; 0211 } 0212 0213 QWidget* MainWindow::createProgressWidget() 0214 { 0215 QLabel *messageLabel = new QLabel(i18n("Your USB drive is being created.\n\n" 0216 "This may take some time depending " 0217 "on the size of the ISO image file " 0218 "and the transfer speed.")); 0219 messageLabel->setWordWrap(true); 0220 0221 m_progressBar = new QProgressBar; 0222 m_progressBar->setFormat(i18nc("Progress percent value", "%p%")); 0223 m_cancelButton = new QPushButton(i18n("Cancel")); 0224 0225 QVBoxLayout *mainVBoxLayout = new QVBoxLayout; 0226 mainVBoxLayout->addWidget(messageLabel, 0, Qt::AlignTop | Qt::AlignHCenter); 0227 mainVBoxLayout->addWidget(m_progressBar); 0228 mainVBoxLayout->addSpacing(15); 0229 mainVBoxLayout->addWidget(m_cancelButton, 0, Qt::AlignLeft); 0230 0231 QWidget *progressWidget = new QWidget; 0232 progressWidget->setLayout(mainVBoxLayout); 0233 0234 return progressWidget; 0235 } 0236 0237 QWidget* MainWindow::createSuccessWidget() 0238 { 0239 QLabel *messageLabel = new QLabel(i18n("Your live USB flash drive is now " 0240 "complete and ready to use!")); 0241 messageLabel->setWordWrap(true); 0242 0243 QLabel *successIconLabel = new QLabel(); 0244 successIconLabel->setPixmap(QIcon::fromTheme("emblem-success").pixmap(QSize(64, 64))); 0245 0246 QPushButton *backButton = new QPushButton(i18n("Back")); 0247 connect(backButton, &QPushButton::clicked, this, &MainWindow::hideWritingProgress); 0248 0249 QPushButton *closeButton = new QPushButton(i18n("Close")); 0250 connect(closeButton, &QPushButton::clicked, this, &MainWindow::close); 0251 0252 QHBoxLayout *buttonsHBoxLayout = new QHBoxLayout; 0253 buttonsHBoxLayout->addWidget(backButton, 0, Qt::AlignLeft); 0254 buttonsHBoxLayout->addWidget(closeButton, 0, Qt::AlignRight); 0255 0256 QVBoxLayout *mainVBoxLayout = new QVBoxLayout; 0257 mainVBoxLayout->addWidget(messageLabel, 0, Qt::AlignCenter); 0258 mainVBoxLayout->addWidget(successIconLabel, 0, Qt::AlignHCenter); 0259 mainVBoxLayout->addSpacing(15); 0260 mainVBoxLayout->addLayout(buttonsHBoxLayout); 0261 0262 QWidget *successWidget = new QWidget; 0263 successWidget->setLayout(mainVBoxLayout); 0264 0265 return successWidget; 0266 } 0267 0268 void MainWindow::preprocessIsoImage(const QString& isoImagePath) 0269 { 0270 QFile file(isoImagePath); 0271 if (!file.open(QIODevice::ReadOnly)) 0272 { 0273 QMessageBox::critical(this, "Error", 0274 i18n("Failed to open the image file:") 0275 + "\n" + QDir::toNativeSeparators(isoImagePath) 0276 + "\n" + file.errorString()); 0277 return; 0278 } 0279 0280 m_isoImageSize = file.size(); 0281 m_isoImagePath = isoImagePath; 0282 m_isoImageLineEdit->setText(QDir::toNativeSeparators(m_isoImagePath)); 0283 m_isoImageSizeLabel->setText(KFormat().formatByteSize(m_isoImageSize)); 0284 0285 file.close(); 0286 0287 #ifdef _USE_GPG 0288 // Verify ISO image 0289 m_busyLabel->setText(i18n("Verifying ISO image")); 0290 m_busyWidget->show(); 0291 m_busySpinner->setSequence(KPixmapSequenceLoader::load( 0292 "process-working", KIconLoader::SizeSmallMedium)); 0293 m_busySpinner->start(); 0294 0295 IsoVerifier *isoVerifier = new IsoVerifier(m_isoImagePath); 0296 QThread *verifierThread = new QThread(this); 0297 0298 connect(verifierThread, &QThread::started, isoVerifier, &IsoVerifier::verifyIso); 0299 connect(verifierThread, &QThread::finished, verifierThread, &QThread::deleteLater); 0300 0301 connect(isoVerifier, &IsoVerifier::finished, verifierThread, &QThread::quit); 0302 connect(isoVerifier, &IsoVerifier::finished, isoVerifier, &IsoVerifier::deleteLater); 0303 connect(isoVerifier, &IsoVerifier::finished, this, &MainWindow::showIsoVerificationResult); 0304 connect(isoVerifier, &IsoVerifier::inputRequested, this, &MainWindow::showInputDialog); 0305 0306 connect(this, &MainWindow::inputTextReady, isoVerifier, &IsoVerifier::verifyWithInputText); 0307 0308 isoVerifier->moveToThread(verifierThread); 0309 verifierThread->start(); 0310 #endif 0311 0312 // Enable the Write button (if there are USB flash disks present) 0313 m_createButton->setEnabled(m_usbDriveComboBox->count() > 0); 0314 } 0315 0316 void MainWindow::cleanUp() 0317 { 0318 // Delete all the allocated UsbDevice objects attached to the combobox 0319 for (int i = 0; i < m_usbDriveComboBox->count(); ++i) 0320 { 0321 delete m_usbDriveComboBox->itemData(i).value<UsbDevice*>(); 0322 } 0323 } 0324 0325 void MainWindow::enumFlashDevices() 0326 { 0327 m_enumFlashDevicesWaiting = false; 0328 0329 // Remember the currently selected device 0330 QString selectedDevice = ""; 0331 int idx = m_usbDriveComboBox->currentIndex(); 0332 if (idx >= 0) 0333 { 0334 UsbDevice* dev = m_usbDriveComboBox->itemData(idx).value<UsbDevice*>(); 0335 selectedDevice = dev->m_PhysicalDevice; 0336 } 0337 0338 // Remove the existing entries 0339 cleanUp(); 0340 m_usbDriveComboBox->clear(); 0341 0342 // Disable the combobox 0343 m_usbDriveComboBox->setEnabled(false); 0344 0345 // Add the USB flash devices to the combobox 0346 platformEnumFlashDevices(addFlashDeviceCallback, m_usbDriveComboBox); 0347 0348 // Restore the previously selected device (if present) 0349 if (!selectedDevice.isEmpty()) 0350 for (int i = 0; i < m_usbDriveComboBox->count(); ++i) 0351 { 0352 UsbDevice* dev = m_usbDriveComboBox->itemData(i).value<UsbDevice*>(); 0353 if (dev->m_PhysicalDevice == selectedDevice) 0354 { 0355 m_usbDriveComboBox->setCurrentIndex(i); 0356 break; 0357 } 0358 } 0359 0360 // Update the Write button enabled/disabled state 0361 m_createButton->setEnabled(m_usbDriveComboBox->count() > 0 0362 && m_isoImagePath != ""); 0363 0364 // Enable/disable the usb drive combobox 0365 if (m_usbDriveComboBox->count() < 1) { 0366 m_usbDriveComboBox->setEnabled(false); 0367 m_usbDriveComboBox->setEditable(true); 0368 m_usbDriveComboBox->lineEdit() 0369 ->setPlaceholderText(i18n("Please plug in a USB drive")); 0370 } else { 0371 m_usbDriveComboBox->setEnabled(true); 0372 m_usbDriveComboBox->setEditable(false); 0373 } 0374 } 0375 0376 void MainWindow::writeToDevice(bool zeroing) 0377 { 0378 UsbDevice* selectedDevice = m_usbDriveComboBox->itemData( 0379 m_usbDriveComboBox->currentIndex()).value<UsbDevice*>(); 0380 0381 ImageWriter* writer = new ImageWriter(zeroing ? "" : m_isoImagePath, selectedDevice); 0382 QThread *writerThread = new QThread(this); 0383 0384 // Connect start and end signals 0385 connect(writerThread, &QThread::started, writer, &ImageWriter::writeImage); 0386 // When writer finishes its job, quit the thread 0387 connect(writer, &ImageWriter::finished, writerThread, &QThread::quit); 0388 // Guarantee deleting the objects after completion 0389 connect(writer, &ImageWriter::finished, writer, &ImageWriter::deleteLater); 0390 connect(writerThread, &QThread::finished, writerThread, &QThread::deleteLater); 0391 // If the Cancel button is pressed, inform the writer to stop the operation 0392 // Using DirectConnection because the thread does not read its own event queue until completion 0393 connect(m_cancelButton, &QPushButton::clicked, writer, &ImageWriter::cancelWriting, Qt::DirectConnection); 0394 // Each time a block is written, update the progress bar 0395 connect(writer, &ImageWriter::progressChanged, this, &MainWindow::updateProgressBar); 0396 // Show the message about successful completion on success 0397 connect(writer, &ImageWriter::success, this, &MainWindow::showSuccessMessage); 0398 // Show error message if error is sent by the worker 0399 connect(writer, &ImageWriter::error, this, &MainWindow::showErrorMessage); 0400 // Silently return back to normal dialog form if the operation was cancelled 0401 connect(writer, &ImageWriter::cancelled, this, &MainWindow::hideWritingProgress); 0402 0403 // Now start the writer thread 0404 writer->moveToThread(writerThread); 0405 writerThread->start(); 0406 0407 showWritingProgress(); 0408 } 0409 0410 void MainWindow::dragEnterEvent(QDragEnterEvent* event) 0411 { 0412 // Accept only files with ANSI or Unicode paths (Windows) and URIs (Linux) 0413 if (event->mimeData()->hasFormat("application/x-qt-windows-mime;value=\"FileName\"") || 0414 event->mimeData()->hasFormat("application/x-qt-windows-mime;value=\"FileNameW\"") || 0415 event->mimeData()->hasFormat("text/uri-list")) 0416 event->accept(); 0417 } 0418 0419 void MainWindow::dropEvent(QDropEvent* event) 0420 { 0421 QString newImageFile = ""; 0422 QByteArray droppedFileName; 0423 0424 // First, try to use the Unicode file name 0425 droppedFileName = event->mimeData()->data("application/x-qt-windows-mime;value=\"FileNameW\""); 0426 if (!droppedFileName.isEmpty()) { 0427 newImageFile = QString::fromWCharArray(reinterpret_cast<const wchar_t*>(droppedFileName.constData())); 0428 } else { 0429 // If failed, use the ANSI name with the local codepage 0430 droppedFileName = event->mimeData()->data("application/x-qt-windows-mime;value=\"FileName\""); 0431 if (!droppedFileName.isEmpty()) { 0432 newImageFile = QString::fromLocal8Bit(droppedFileName.constData()); 0433 } else { 0434 // And, finally, try the URI 0435 droppedFileName = event->mimeData()->data("text/uri-list"); 0436 if (!droppedFileName.isEmpty()) { 0437 // If several files are dropped they are separated by newlines, 0438 // take the first file 0439 int newLineIndexLF = droppedFileName.indexOf('\n'); 0440 int newLineIndex = droppedFileName.indexOf("\r\n"); 0441 // Make sure both CRLF and LF are accepted 0442 if ((newLineIndexLF != -1) && (newLineIndexLF < newLineIndex)) 0443 newLineIndex = newLineIndexLF; 0444 if (newLineIndex != -1) 0445 droppedFileName.truncate(newLineIndex); 0446 // Decode the file path from percent-encoding 0447 QUrl url = QUrl::fromEncoded(droppedFileName); 0448 if (url.isLocalFile()) 0449 newImageFile = url.toLocalFile(); 0450 } 0451 } 0452 } 0453 } 0454 0455 void MainWindow::closeEvent(QCloseEvent* event) 0456 { 0457 if (m_isWriting) 0458 { 0459 const int answer = QMessageBox::question( 0460 this, 0461 i18n("Cancel?"), 0462 i18n("Writing is in progress, abort it?")); 0463 0464 if (answer == QMessageBox::No) 0465 event->ignore(); 0466 } 0467 } 0468 0469 void MainWindow::addFlashDeviceCallback(void* cbParam, UsbDevice* device) 0470 { 0471 auto usbDriveComboBox = (QComboBox*)cbParam; 0472 usbDriveComboBox->addItem(device->formatDisplayName(), 0473 QVariant::fromValue(device)); 0474 } 0475 0476 void MainWindow::openIsoImage() 0477 { 0478 const QString filter = i18n("Disk Images (%1)", QString("*.iso *.bin *.img *.iso.gz *.iso.xz *.img.zstd *.img.gz *.img.zx *.img.zstd")) 0479 + ";;" + i18n("All Files (%1)", QString("*")); 0480 QUrl isoImageUrl = QFileDialog::getOpenFileUrl(this, i18n("Select image to flash"), QUrl::fromLocalFile(m_lastOpenedDir), 0481 filter, nullptr, 0482 QFileDialog::ReadOnly); 0483 openUrl(isoImageUrl); 0484 } 0485 0486 void MainWindow::openUrl(const QUrl& url) 0487 { 0488 if (url.isEmpty()) { 0489 return; 0490 } 0491 0492 if (url.isLocalFile()) { 0493 const QString path = url.toLocalFile(); 0494 m_lastOpenedDir = path.left(path.lastIndexOf('/')); 0495 preprocessIsoImage(path); 0496 return; 0497 } else { 0498 m_isoImageLineEdit->setText(url.toString()); 0499 } 0500 0501 delete m_fetchIso; 0502 m_fetchIso = new FetchIsoJob(this); 0503 connect(m_fetchIso, &FetchIsoJob::downloadProgressChanged, this, &MainWindow::downloadProgressChanged); 0504 connect(m_fetchIso, &FetchIsoJob::failed, this, &MainWindow::hideWritingProgress); 0505 connect(m_fetchIso, &FetchIsoJob::finished, this, [this] (const QString &file) { 0506 m_isoImagePath = file; 0507 m_busySpinner->stop(); 0508 preprocessIsoImage(file); 0509 }); 0510 m_busyLabel->setText(i18n("Downloading ISO image")); 0511 m_busyWidget->show(); 0512 m_busySpinner->setSequence(KPixmapSequenceLoader::load( 0513 "process-working", KIconLoader::SizeSmallMedium)); 0514 m_busySpinner->start(); 0515 m_fetchIso->fetch(url); 0516 } 0517 0518 void MainWindow::writeIsoImage() 0519 { 0520 if (m_usbDriveComboBox->count() == 0 || m_isoImagePath == "") 0521 return; 0522 0523 UsbDevice* selectedDevice = m_usbDriveComboBox->itemData( 0524 m_usbDriveComboBox->currentIndex()).value<UsbDevice*>(); 0525 0526 if (selectedDevice->m_Size == 0) { 0527 int warningReturn = QMessageBox::warning( 0528 this, 0529 i18n("Unknown Disk Size"), 0530 i18n("The selected disk is of unknown size, please check the image will fit before writing.\n\n" 0531 "Image size: %1 (%2 b)", 0532 KFormat().formatByteSize(m_isoImageSize), 0533 m_isoImageSize), 0534 QMessageBox::Ok | QMessageBox::Cancel); 0535 if (warningReturn != QMessageBox::Ok) { 0536 return; 0537 } 0538 } else if (m_isoImageSize > selectedDevice->m_Size) { 0539 QMessageBox::critical( 0540 this, 0541 i18n("Error"), 0542 i18n("The image is larger than your selected device!\n\n" 0543 "Image size: %1 (%2 b)\n" 0544 "Disk size: %3 (%4 b)", 0545 KFormat().formatByteSize(m_isoImageSize), 0546 m_isoImageSize, 0547 KFormat().formatByteSize(selectedDevice->m_Size), 0548 selectedDevice->m_Size), 0549 QMessageBox::Ok); 0550 return; 0551 } 0552 0553 writeToDevice(false); 0554 } 0555 0556 void MainWindow::updateProgressBar(int percent) 0557 { 0558 m_progressBar->setValue(percent); 0559 m_externalProgressBar.SetProgressValue(percent); 0560 } 0561 0562 void MainWindow::showWritingProgress() 0563 { 0564 m_isWriting = true; 0565 0566 // Do not accept dropped files while writing 0567 setAcceptDrops(false); 0568 0569 // Display and customize the progress bar part 0570 m_progressBar->setMinimum(0); 0571 m_progressBar->setMaximum(100); 0572 m_progressBar->setValue(0); 0573 0574 // Expose the progress bar state to the OS 0575 m_externalProgressBar.InitProgressBar(100); 0576 0577 m_centralStackedWidget->setCurrentIndex(2); 0578 } 0579 0580 void MainWindow::hideWritingProgress() 0581 { 0582 m_isWriting = false; 0583 0584 // Enable drag & drop 0585 setAcceptDrops(true); 0586 0587 // Send a signal that progressbar is no longer present 0588 m_externalProgressBar.DestroyProgressBar(); 0589 0590 m_centralStackedWidget->setCurrentIndex(0); 0591 0592 // If device list changed during writing update it now 0593 if (m_enumFlashDevicesWaiting) 0594 enumFlashDevices(); 0595 } 0596 0597 void MainWindow::showErrorMessage(const QString &message) 0598 { 0599 m_externalProgressBar.ProgressSetError(); 0600 0601 QMessageBox::critical(this, i18n("Error"), message); 0602 0603 hideWritingProgress(); 0604 } 0605 0606 void MainWindow::showSuccessMessage() 0607 { 0608 m_isWriting = false; 0609 0610 // Do not accept dropped files 0611 setAcceptDrops(false); 0612 0613 m_centralStackedWidget->setCurrentIndex(3); 0614 } 0615 0616 void MainWindow::showConfirmMessage() 0617 { 0618 openUrl(QUrl::fromUserInput(m_isoImageLineEdit->text(), {}, QUrl::AssumeLocalFile)); 0619 0620 // Do not accept dropped files 0621 setAcceptDrops(false); 0622 0623 m_centralStackedWidget->setCurrentIndex(1); 0624 } 0625 0626 void MainWindow::showIsoVerificationResult(IsoVerifier::VerifyResult verify, const QString &error) 0627 { 0628 if (verify == IsoVerifier::VerifyResult::Successful) { 0629 m_busyLabel->setText(i18n("The ISO image is valid")); 0630 m_busySpinner->setSequence(KPixmapSequenceLoader::load( 0631 "checkmark", KIconLoader::SizeSmallMedium)); 0632 } else { 0633 m_busySpinner->setSequence( 0634 KPixmapSequenceLoader::load("error", KIconLoader::SizeSmallMedium)); 0635 if (verify == IsoVerifier::VerifyResult::KeyNotFound) { 0636 m_busyLabel->setText(i18n("Could not find the key to verify the ISO image")); 0637 } else if (verify == IsoVerifier::VerifyResult::Failed) { 0638 m_busyLabel->setText(i18n("Could not verify ISO image")); 0639 QMessageBox::warning(this, i18n("ISO Verification failed"), error); 0640 } 0641 } 0642 Q_EMIT verificationResult(verify == IsoVerifier::VerifyResult::Successful); 0643 } 0644 0645 #include "moc_mainwindow.cpp"