diff options
Diffstat (limited to 'src-qt5/desktop-utils/lumina-archiver/imgDialog.cpp')
-rw-r--r-- | src-qt5/desktop-utils/lumina-archiver/imgDialog.cpp | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src-qt5/desktop-utils/lumina-archiver/imgDialog.cpp b/src-qt5/desktop-utils/lumina-archiver/imgDialog.cpp new file mode 100644 index 00000000..13268a73 --- /dev/null +++ b/src-qt5/desktop-utils/lumina-archiver/imgDialog.cpp @@ -0,0 +1,178 @@ +//=========================================== +// Lumina-Desktop source code +// Copyright (c) 2016, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "imgDialog.h" +#include "ui_imgDialog.h" + +#include <QMessageBox> + +#include <LuminaOS.h> +#include <LuminaXDG.h> + +#include <unistd.h> +#include <sys/types.h> +#include <signal.h> + +imgDialog::imgDialog(QWidget *parent) : QDialog(parent), ui(new Ui::imgDialog()){ + ui->setupUi(this); //load the designer form + QString title = tr("Burn IMG to Device"); + if( getuid()==0){ title.append(" ("+tr("Admin Mode")+")"); } + this->setWindowTitle(title); + ui->frame_running->setVisible(false); + ui->frame_setup->setVisible(true); + ddProc = 0; + unitdiv = 1; + //Setup the signals/slots + ui->tool_refresh->setIcon( LXDG::findIcon("view-refresh","drive-removable-media-usb-pendrive") ); + connect(ui->push_cancel, SIGNAL(clicked()), this, SLOT(cancel()) ); + connect(ui->push_start, SIGNAL(clicked()), this, SLOT(start_process()) ); + connect(ui->tool_refresh, SIGNAL(clicked()), this, SLOT(loadDeviceList()) ); + loadDeviceList(); //do the initial load of the available devices + //Setup the possible transfer rate units + ui->combo_rate_units->clear(); + ui->combo_rate_units->addItem(tr("Kilobyte(s)"), "k"); + ui->combo_rate_units->addItem(tr("Megabyte(s)"), "m"); + ui->combo_rate_units->addItem(tr("Gigabyte(s)"), "g"); + ui->combo_rate_units->setCurrentIndex(1); //MB + //Setup the Process Timer + procTimer = new QTimer(this); + procTimer->setInterval(1000); //1 second updates + connect(procTimer, SIGNAL(timeout()), this, SLOT(getProcStatus()) ); + //Determine which type of system this is for the process status signal + BSD_signal = LOS::OSName().contains("BSD"); //assume everything else is Linux-like +} + +imgDialog::~imgDialog(){ + +} + +void imgDialog::loadIMG(QString filepath){ + ui->label_iso->setText(filepath.section("/",-1)); //only show the filename + ui->label_iso->setWhatsThis(filepath); //save the full path for later +} + +//============================ +// PRIVATE SLOTS +//============================ +void imgDialog::start_process(){ + //Sanity Checks + if( !QFile::exists(ui->combo_devices->currentData().toString()) ){ loadDeviceList(); return; } //USB device no longer available + if(!QFile::exists(ui->label_iso->whatsThis()) ){ return; } //IMG file no longer available + qDebug() << "Start Process..."; + //Read the size of the img file + QString units = ui->combo_rate_units->currentData().toString(); + if(units=="k"){ unitdiv = 1024; } + else if(units=="m"){ unitdiv = 1024*1024; } + else if(units=="g"){ unitdiv = 1024*1024*1024; } + qint64 bytes = QFileInfo(ui->label_iso->whatsThis()).size(); + //qDebug() << "IMG File size:" << bytes; + //Set the progressBar maximum + ui->progressBar->setRange(0, qRound(bytes/unitdiv) ); + ui->progressBar->setValue(0); + ui->label_dev->setText( ui->combo_devices->currentText() ); + ui->label_time->setText("0:00"); + ui->frame_running->setVisible(true); + ui->frame_setup->setVisible(false); + //qDebug() << "Blocks:" << ui->progressBar->maximum(); + //Initialize the process + if(ddProc==0){ + ddProc = new QProcess(this); + connect(ddProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(procFinished()) ); + connect(ddProc, SIGNAL(readyRead()), this, SLOT(procInfoAvailable()) ); + ddProc->setProcessChannelMode(QProcess::MergedChannels); + } + //Generate the command + QString prog; QStringList args; + //if( ::getuid()!=0){ prog = "qsudo"; args<<"dd"; } + //else{ + prog = "dd"; + //} + args << "if="+ui->label_iso->whatsThis(); + args << "of="+ui->combo_devices->currentData().toString(); + args << "bs="+QString::number(ui->spin_rate_num->value())+units; + if(ui->check_sync->isChecked()){ args << "conv=sync"; } + //Start the process + startTime = QDateTime::currentDateTime(); + ddProc->start(prog, args); + //Start the timer to watch for updates + procTimer->start(); + ui->push_start->setEnabled(false); +} + +void imgDialog::cancel(){ + if(ddProc==0 || ddProc->state()==QProcess::NotRunning){ + this->close(); + }else{ + //Prompt if the transfer should be cancelled + if(QMessageBox::Yes == QMessageBox::question(this, tr("Cancel Image Burn?"), tr("Do you wish to stop the current IMG burn process?")+"\n\n"+tr("Warning: This will leave the USB device in an inconsistent state")) ){ + ddProc->kill(); + } + } +} + +void imgDialog::loadDeviceList(){ + ui->combo_devices->clear(); + //Probe the system for USB devices + QDir devDir("/dev"); + QString filter = (BSD_signal) ? "da*" : "sd*"; + QStringList usb = devDir.entryList(QStringList() << filter, QDir::System, QDir::Name); + //Filter out any devices which are currently mounted/used + + //Create the list + for(int i=0; i<usb.length(); i++){ + ui->combo_devices->addItem(usb[i], devDir.absoluteFilePath(usb[i])); + } +} + +void imgDialog::getProcStatus(){ + if(ddProc==0 || ddProc->state()!=QProcess::Running ){ return; } + QStringList pidlist = LUtils::getCmdOutput("pgrep -S -f \"dd if="+ui->label_iso->whatsThis()+"\""); + if(pidlist.isEmpty()){ return; } + int pid = pidlist.first().simplified().toInt(); //just use the first pid - the pgrep should be detailed enough to only match one + //qDebug() << "Sending signal to show status on PID:" << pid; + if(BSD_signal){ ::kill(pid, SIGINFO); } //On BSD systems, the INFO signal is used to poke dd for status updates + else{ ::kill(pid, SIGUSR1); } //On linux systems, the USR1 signal is used to poke dd for status updates + //Now update the elapsed time on the UI + int elapsed = startTime.secsTo( QDateTime::currentDateTime() ); + int min = elapsed/60; + int secs = elapsed%60; + ui->label_time->setText( QString::number(min)+":"+ (secs < 10 ? "0" : "")+QString::number(secs) ); +} + +void imgDialog::procInfoAvailable(){ + lastmsg = ddProc->readAll(); + if(lastmsg.endsWith("\n")){ lastmsg.chop(1); } + //qDebug() << "Got Process Info:" << lastmsg; + //Now look for the " bytes transferred" line + QStringList records = lastmsg.split("\n").filter(" bytes transferred "); + if(!records.isEmpty()){ + //Update the progress bar + //qDebug() << "Got status update:" << records.last(); + ui->progressBar->setValue( qRound(records.last().section(" bytes",0,0).toDouble()/unitdiv) ); + } +} + +void imgDialog::procFinished(){ + qDebug() << "Process Finished:" << ddProc->exitCode(); + procTimer->stop(); + ui->frame_running->setVisible(false); + ui->frame_setup->setVisible(true); + if(ddProc->exitStatus()==QProcess::NormalExit){ + if(ddProc->exitCode() !=0 ){ + if(lastmsg.contains("permission denied", Qt::CaseInsensitive) && LUtils::isValidBinary("qsudo") ){ + if(QMessageBox::Yes == QMessageBox::question(this, tr("Administrator Permissions Needed"), tr("This operation requires administrator priviledges.")+"\n\n"+tr("Would you like to enable these priviledges?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) ){ + QProcess::startDetached("qsudo", QStringList() << "lumina-archiver" << "--burn-img" << ui->label_iso->whatsThis()); + exit(0); + } + }else{ + QMessageBox::warning(this, tr("ERROR"), tr("The process could not be completed:")+"\n\n"+lastmsg); + } + }else{ + QMessageBox::information(this, tr("SUCCESS"), tr("The image was successfully burned to the USB device") ); + this->close(); + } + } +} |