diff --git a/src/gui/applyprogressdialog.cpp b/src/gui/applyprogressdialog.cpp index 8b35a2f..d9c1ae1 100644 --- a/src/gui/applyprogressdialog.cpp +++ b/src/gui/applyprogressdialog.cpp @@ -1,463 +1,462 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "gui/applyprogressdialog.h" #include "gui/applyprogressdialogwidget.h" #include "gui/applyprogressdetailswidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const QString ApplyProgressDialog::m_TimeFormat = QStringLiteral("hh:mm:ss"); static QWidget* mainWindow(QWidget* w) { while (w && w->parentWidget()) w = w->parentWidget(); return w; } /** Creates a new ProgressDialog @param parent pointer to the parent widget @param orunner the OperationRunner whose progress this dialog is showing */ ApplyProgressDialog::ApplyProgressDialog(QWidget* parent, OperationRunner& orunner) : QDialog(parent), m_ProgressDialogWidget(new ApplyProgressDialogWidget(this)), m_ProgressDetailsWidget(new ApplyProgressDetailsWidget(this)), m_OperationRunner(orunner), m_Report(nullptr), m_SavedParentTitle(mainWindow(this)->windowTitle()), m_Timer(this), m_Time(), m_CurrentOpItem(nullptr), m_CurrentJobItem(nullptr), m_LastReportUpdate(0) { QVBoxLayout *mainLayout = new QVBoxLayout(this); setLayout(mainLayout); mainLayout->addWidget(&dialogWidget()); QFrame* detailsBox = new QFrame(this); mainLayout->addWidget(detailsBox); QVBoxLayout *detailsLayout = new QVBoxLayout(detailsBox); detailsLayout->addWidget(&detailsWidget()); detailsWidget().hide(); setAttribute(Qt::WA_ShowModal, true); dialogButtonBox = new QDialogButtonBox; okButton = dialogButtonBox->addButton(QDialogButtonBox::Ok); cancelButton = dialogButtonBox->addButton(QDialogButtonBox::Cancel); detailsButton = new QPushButton; detailsButton->setText(xi18nc("@action:button", "&Details") + QStringLiteral(" >>")); detailsButton->setIcon(QIcon::fromTheme(QStringLiteral("help-about")).pixmap(IconSize(KIconLoader::Toolbar))); dialogButtonBox->addButton(detailsButton, QDialogButtonBox::ActionRole); mainLayout->addWidget(dialogButtonBox); dialogWidget().treeTasks().setColumnWidth(0, width() * 8 / 10); detailsWidget().buttonBrowser().setIcon(QIcon::fromTheme(QStringLiteral("document-open")).pixmap(IconSize(KIconLoader::Toolbar))); detailsWidget().buttonSave().setIcon(QIcon::fromTheme(QStringLiteral("document-save")).pixmap(IconSize(KIconLoader::Toolbar))); setupConnections(); KConfigGroup kcg(KSharedConfig::openConfig(), "applyProgressDialog"); restoreGeometry(kcg.readEntry("Geometry", QByteArray())); } /** Destroys a ProgressDialog */ ApplyProgressDialog::~ApplyProgressDialog() { KConfigGroup kcg(KSharedConfig::openConfig(), "applyProgressDialog"); kcg.writeEntry("Geometry", saveGeometry()); delete m_Report; } void ApplyProgressDialog::setupConnections() { connect(&operationRunner(), &OperationRunner::progressSub, &dialogWidget().progressSub(), &QProgressBar::setValue); connect(&operationRunner(), &OperationRunner::finished, this, &ApplyProgressDialog::onAllOpsFinished); connect(&operationRunner(), &OperationRunner::cancelled, this, &ApplyProgressDialog::onAllOpsCancelled); connect(&operationRunner(), &OperationRunner::error, this, &ApplyProgressDialog::onAllOpsError); connect(&operationRunner(), &OperationRunner::opStarted, this, &ApplyProgressDialog::onOpStarted); connect(&operationRunner(), &OperationRunner::opFinished, this, &ApplyProgressDialog::onOpFinished); connect(&timer(), &QTimer::timeout, this, &ApplyProgressDialog::onSecondElapsed); connect(&detailsWidget().buttonSave(), &QPushButton::clicked, this, &ApplyProgressDialog::saveReport); connect(&detailsWidget().buttonBrowser(), &QPushButton::clicked, this, &ApplyProgressDialog::browserReport); connect(dialogButtonBox, &QDialogButtonBox::accepted, this, &ApplyProgressDialog::onOkButton); connect(dialogButtonBox, &QDialogButtonBox::rejected, this, &ApplyProgressDialog::onCancelButton); connect(detailsButton, &QPushButton::clicked, this, &ApplyProgressDialog::toggleDetails); } /** Shows the dialog */ void ApplyProgressDialog::show() { setStatus(xi18nc("@info:progress", "Setting up...")); resetReport(); dialogWidget().progressTotal().setRange(0, operationRunner().numJobs()); dialogWidget().progressTotal().setValue(0); dialogWidget().treeTasks().clear(); okButton->setVisible(false); cancelButton->setVisible(true); + cancelButton->setEnabled(true); + timer().start(1000); time().start(); setLastReportUpdate(0); onSecondElapsed(); // resets the total time output label QDialog::show(); } void ApplyProgressDialog::resetReport() { delete m_Report; m_Report = new Report(nullptr); detailsWidget().editReport().clear(); detailsWidget().editReport().setCursorWidth(0); detailsWidget().buttonSave().setEnabled(false); detailsWidget().buttonBrowser().setEnabled(false); connect(&report(), &Report::outputChanged, this, &ApplyProgressDialog::updateReportUnforced); } void ApplyProgressDialog::closeEvent(QCloseEvent* e) { e->ignore(); operationRunner().isRunning() ? onCancelButton() : onOkButton(); } void ApplyProgressDialog::toggleDetails() { const bool isVisible = detailsWidget().isVisible(); detailsWidget().setVisible(!isVisible); detailsButton->setText(xi18nc("@action:button", "&Details") + (isVisible ? QStringLiteral(" >>") : QStringLiteral(" <<"))); } void ApplyProgressDialog::onDetailsButton() { updateReport(true); return; } void ApplyProgressDialog::onCancelButton() { if (operationRunner().isRunning()) { // only cancel once if (operationRunner().isCancelling()) return; - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - - cancelButton->setEnabled(false); - setStatus(xi18nc("@info:progress", "Waiting for operation to finish...")); - repaint(); - dialogWidget().repaint(); - // suspend the runner, so it doesn't happily carry on while the user decides // if he really wants to cancel operationRunner().suspendMutex().lock(); - cancelButton->setEnabled(true); - - QApplication::restoreOverrideCursor(); if (KMessageBox::questionYesNo(this, xi18nc("@info", "Do you really want to cancel?"), xi18nc("@title:window", "Cancel Running Operations"), KGuiItem(xi18nc("@action:button", "Yes, Cancel Operations"), QStringLiteral("dialog-ok")), KStandardGuiItem::no()) == KMessageBox::Yes) // in the meantime while we were showing the messagebox, the runner might have finished. - if (operationRunner().isRunning()) + if (operationRunner().isRunning()) { + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + cancelButton->setEnabled(false); + setStatus(xi18nc("@info:progress", "Waiting for operation to finish...")); + repaint(); + dialogWidget().repaint(); + QApplication::restoreOverrideCursor(); operationRunner().cancel(); + } operationRunner().suspendMutex().unlock(); } return; } void ApplyProgressDialog::onOkButton() { mainWindow(this)->setWindowTitle(savedParentTitle()); QDialog::accept(); } void ApplyProgressDialog::onAllOpsFinished() { allOpsDone(xi18nc("@info:progress", "All operations successfully finished.")); } void ApplyProgressDialog::onAllOpsCancelled() { allOpsDone(xi18nc("@info:progress", "Operations cancelled.")); } void ApplyProgressDialog::onAllOpsError() { allOpsDone(xi18nc("@info:progress", "There were errors while applying operations. Aborted.")); } void ApplyProgressDialog::allOpsDone(const QString& msg) { dialogWidget().progressTotal().setValue(operationRunner().numJobs()); cancelButton->setVisible(false); okButton->setVisible(true); detailsWidget().buttonSave().setEnabled(true); detailsWidget().buttonBrowser().setEnabled(true); timer().stop(); updateReport(true); setStatus(msg); } void ApplyProgressDialog::updateReportUnforced() { updateReport(false); } void ApplyProgressDialog::updateReport(bool force) { // Rendering the HTML in the QTextEdit is extremely expensive. So make sure not to do that // unnecessarily and not too often: // (1) If the widget isn't visible, don't update. // (2) Also don't update if the last update was n msecs ago, BUT // (3) DO update if we're being forced to. if (force || (detailsWidget().isVisible() && time().elapsed() - lastReportUpdate() > 2000)) { detailsWidget().editReport().setHtml(QStringLiteral("") + report().toHtml() + QStringLiteral("")); detailsWidget().editReport().moveCursor(QTextCursor::End); detailsWidget().editReport().ensureCursorVisible(); setLastReportUpdate(time().elapsed()); } } void ApplyProgressDialog::onOpStarted(int num, Operation* op) { addTaskOutput(num, *op); setStatus(op->description()); dialogWidget().progressSub().setValue(0); dialogWidget().progressSub().setRange(0, op->totalProgress()); connect(op, &Operation::jobStarted, this, &ApplyProgressDialog::onJobStarted); connect(op, &Operation::jobFinished, this, &ApplyProgressDialog::onJobFinished); } void ApplyProgressDialog::onJobStarted(Job* job, Operation* op) { for (qint32 i = 0; i < dialogWidget().treeTasks().topLevelItemCount(); i++) { QTreeWidgetItem* item = dialogWidget().treeTasks().topLevelItem(i); if (item == nullptr || reinterpret_cast(item->data(0, Qt::UserRole).toULongLong()) != op) continue; QTreeWidgetItem* child = new QTreeWidgetItem(); child->setText(0, job->description()); child->setIcon(0, QIcon::fromTheme(job->statusIcon()).pixmap(IconSize(KIconLoader::Small))); child->setText(1, QTime(0, 0).toString(timeFormat())); item->addChild(child); dialogWidget().treeTasks().scrollToBottom(); setCurrentJobItem(child); break; } } void ApplyProgressDialog::onJobFinished(Job* job, Operation* op) { if (currentJobItem()) currentJobItem()->setIcon(0, QIcon::fromTheme(job->statusIcon()).pixmap(IconSize(KIconLoader::Small))); setCurrentJobItem(nullptr); const int current = dialogWidget().progressTotal().value(); dialogWidget().progressTotal().setValue(current + 1); setParentTitle(op->description()); updateReport(true); } void ApplyProgressDialog::onOpFinished(int num, Operation* op) { if (currentOpItem()) { currentOpItem()->setText(0, opDesc(num, *op)); currentOpItem()->setIcon(0, QIcon::fromTheme(op->statusIcon()).pixmap(IconSize(KIconLoader::Small))); } setCurrentOpItem(nullptr); setStatus(op->description()); dialogWidget().progressSub().setValue(op->totalProgress()); updateReport(true); } void ApplyProgressDialog::setParentTitle(const QString& s) { const int percent = dialogWidget().progressTotal().value() * 100 / dialogWidget().progressTotal().maximum(); mainWindow(this)->setWindowTitle(QString::number(percent) + QStringLiteral("% - ") + s + QStringLiteral(" - ") + savedParentTitle()); } void ApplyProgressDialog::setStatus(const QString& s) { setWindowTitle(s); dialogWidget().status().setText(s); setParentTitle(s); } QString ApplyProgressDialog::opDesc(int num, const Operation& op) const { return xi18nc("@info:progress", "[%1/%2] - %3: %4", num, operationRunner().numOperations(), op.statusText(), op.description()); } void ApplyProgressDialog::addTaskOutput(int num, const Operation& op) { QTreeWidgetItem* item = new QTreeWidgetItem(); item->setIcon(0, QIcon::fromTheme(op.statusIcon()).pixmap(IconSize(KIconLoader::Small))); item->setText(0, opDesc(num, op)); item->setText(1, QTime(0, 0).toString(timeFormat())); QFont f; f.setWeight(QFont::Bold); item->setFont(0, f); item->setFont(1, f); item->setData(0, Qt::UserRole, reinterpret_cast(&op)); dialogWidget().treeTasks().addTopLevelItem(item); dialogWidget().treeTasks().scrollToBottom(); setCurrentOpItem(item); } void ApplyProgressDialog::onSecondElapsed() { if (currentJobItem()) { QTime t = QTime::fromString(currentJobItem()->text(1), timeFormat()).addSecs(1); currentJobItem()->setText(1, t.toString(timeFormat())); } if (currentOpItem()) { QTime t = QTime::fromString(currentOpItem()->text(1), timeFormat()).addSecs(1); currentOpItem()->setText(1, t.toString(timeFormat()));; } const QTime outputTime = QTime(0, 0).addMSecs(time().elapsed()); dialogWidget().totalTime().setText(xi18nc("@info:progress", "Total Time: %1", outputTime.toString(timeFormat()))); } void ApplyProgressDialog::keyPressEvent(QKeyEvent* e) { e->accept(); switch (e->key()) { case Qt::Key_Return: case Qt::Key_Enter: if (okButton->isEnabled()) onOkButton(); break; case Qt::Key_Escape: cancelButton->isEnabled() ? onCancelButton() : onOkButton(); break; default: break; } } void ApplyProgressDialog::saveReport() { const QUrl url = QFileDialog::getSaveFileUrl(); if (url.isEmpty()) return; QTemporaryFile tempFile; if (tempFile.open()) { QTextStream s(&tempFile); HtmlReport html; s << html.header() << report().toHtml() << html.footer(); tempFile.close(); KIO::CopyJob* job = KIO::move(QUrl::fromLocalFile(tempFile.fileName()), url, KIO::HideProgressInfo); job->exec(); if (job->error()) job->uiDelegate()->showErrorMessage(); } else KMessageBox::sorry(this, xi18nc("@info", "Could not create temporary file when trying to save to %1.", url.fileName()), xi18nc("@title:window", "Could Not Save Report.")); } void ApplyProgressDialog::browserReport() { QTemporaryFile file; // Make sure the temp file is created somewhere another user can read it: KRun::runUrl() will open // the file as the logged in user, not as the user running our application. file.setFileTemplate(QStringLiteral("/tmp/") + QCoreApplication::applicationName() + QStringLiteral("-XXXXXX.html")); file.setAutoRemove(false); if (file.open()) { QTextStream s(&file); HtmlReport html; s << html.header() << report().toHtml() << html.footer(); // set the temp file's permission for everyone to read it. file.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther); if (!KRun::runUrl(QUrl::fromLocalFile(file.fileName()), QStringLiteral("text/html"), this, KRun::RunFlags())) KMessageBox::sorry(this, xi18nc("@info", "The configured external browser could not be run. Please check your settings."), xi18nc("@title:window", "Could Not Launch Browser.")); } else KMessageBox::sorry(this, xi18nc("@info", "Could not create temporary file %1 for writing.", file.fileName()), i18nc("@title:window", "Could Not Launch Browser.")); } diff --git a/src/gui/editmountpointdialog.cpp b/src/gui/editmountpointdialog.cpp index f80b112..02b4f36 100644 --- a/src/gui/editmountpointdialog.cpp +++ b/src/gui/editmountpointdialog.cpp @@ -1,89 +1,89 @@ /************************************************************************* * Copyright (C) 2009, 2010 by Volker Lanz * * Copyright (C) 2015 by Teo Mrnjavac * * Copyright (C) 2016 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "gui/editmountpointdialog.h" #include "gui/editmountpointdialogwidget.h" #include #include #include #include #include #include #include #include EditMountPointDialog::EditMountPointDialog(QWidget* parent, Partition& p) : QDialog(parent), m_Partition(p), m_DialogWidget(new EditMountPointDialogWidget(this, partition())) { QVBoxLayout *mainLayout = new QVBoxLayout(this); setLayout(mainLayout); mainLayout->addWidget(&widget()); setWindowTitle(xi18nc("@title:window", "Edit mount point for %1", p.deviceNode())); KConfigGroup kcg(KSharedConfig::openConfig(), "editMountPointDialog"); restoreGeometry(kcg.readEntry("Geometry", QByteArray())); QDialogButtonBox* dbb = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this ); mainLayout->addWidget(dbb); connect(dbb, &QDialogButtonBox::accepted, this, [=] () {accept_(Edit);} ); connect(dbb, &QDialogButtonBox::rejected, this, &EditMountPointDialog::reject); connect(widget().m_ButtonRemove, &QPushButton::clicked, this, [=] () {accept_(Remove);} ); } /** Destroys an EditMountOptionsDialog instance */ EditMountPointDialog::~EditMountPointDialog() { KConfigGroup kcg(KSharedConfig::openConfig(), "editMountPointDialog"); kcg.writeEntry("Geometry", saveGeometry()); } void EditMountPointDialog::accept_(MountPointAction action) { if (KMessageBox::warningContinueCancel(this, xi18nc("@info", "Are you sure you want to save the changes you made to the system table file /etc/fstab?" "This will overwrite the existing file on your hard drive now. This can not be undone."), xi18nc("@title:window", "Really save changes?"), KGuiItem(xi18nc("@action:button", "Save changes"), QStringLiteral("arrow-right")), KStandardGuiItem::cancel(), QStringLiteral("reallyWriteMountPoints")) == KMessageBox::Cancel) return; if(action == Remove) widget().removeMountPoint(); else if (action == Edit) widget().acceptChanges(); if (writeMountpoints(widget().fstabEntries())) { if (action == Edit) - partition().setMountPoint(widget().editPath().text()); + partition().setMountPoint(widget().editPath().currentText()); } else KMessageBox::sorry(this, xi18nc("@info", "Could not save mount points to file /etc/fstab."), xi18nc("@title:window", "Error While Saving Mount Points")); QDialog::accept(); } diff --git a/src/gui/editmountpointdialogwidget.cpp b/src/gui/editmountpointdialogwidget.cpp index 7591a83..8af681f 100644 --- a/src/gui/editmountpointdialogwidget.cpp +++ b/src/gui/editmountpointdialogwidget.cpp @@ -1,213 +1,234 @@ /************************************************************************* * Copyright (C) 2009, 2010 by Volker Lanz * * Copyright (C) 2016, 2017 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "gui/editmountpointdialogwidget.h" #include "gui/editmountoptionsdialog.h" #include #include #include #include #include #include #include #include #include #include EditMountPointDialogWidget::EditMountPointDialogWidget(QWidget* parent, Partition& p) : QWidget(parent), m_Partition(p) { m_fstabEntries = readFstabEntries(); setupUi(this); m_deviceNode = partition().deviceNode(); if (partition().roles().has(PartitionRole::Luks) && partition().fileSystem().type() != FileSystem::Luks) { const FS::luks* luksFs = dynamic_cast(&partition().fileSystem()); m_deviceNode = luksFs->mapperName(); } labelName().setText(m_deviceNode); labelType().setText(partition().fileSystem().name()); bool entryFound = false; + editPath().setEditable(true); for (auto &e : m_fstabEntries) { QString canonicalEntryPath = QFileInfo(e.deviceNode()).canonicalFilePath(); QString canonicalDevicePath = QFileInfo(m_deviceNode).canonicalFilePath(); if (canonicalEntryPath == canonicalDevicePath) { // FIXME fix multiple mountpoints entryFound = true; - entry = &e; + entry.append(&e); + mountPointList = possibleMountPoints(e.deviceNode()); } } if (!entryFound) { FileSystem::Type type = partition().fileSystem().type(); QString fsName; switch (type) { case FileSystem::LinuxSwap: fsName = QStringLiteral("swap"); break; case FileSystem::Fat16: case FileSystem::Fat32: fsName = QStringLiteral("vfat"); break; default: fsName = partition().fileSystem().name(); } m_fstabEntries.append(FstabEntry(m_deviceNode, QString(), fsName, QString())); - entry = &m_fstabEntries.last(); - } - - editPath().setText(entry->mountPoint()); - - spinDumpFreq().setValue(entry->dumpFreq()); - spinPassNumber().setValue(entry->passNumber()); - - switch (entry->entryType()) { - case FstabEntryType::uuid: - radioUUID().setChecked(true); - break; - - case FstabEntryType::label: - radioLabel().setChecked(true); - break; - - case FstabEntryType::partuuid: - radioUUID().setChecked(true); - break; - - case FstabEntryType::partlabel: - radioLabel().setChecked(true); - break; - - case FstabEntryType::deviceNode: - radioDeviceNode().setChecked(true); - break; - case FstabEntryType::comment: - break; + entry.append(&m_fstabEntries.last()); } + currentEntry = entry[0]; + editPath().addItems(mountPointList); + spinDumpFreq().setValue(currentEntry->dumpFreq()); + spinPassNumber().setValue(currentEntry->passNumber()); boxOptions()[QStringLiteral("ro")] = m_CheckReadOnly; boxOptions()[QStringLiteral("users")] = m_CheckUsers; boxOptions()[QStringLiteral("noauto")] = m_CheckNoAuto; boxOptions()[QStringLiteral("noatime")] = m_CheckNoAtime; boxOptions()[QStringLiteral("nodiratime")] = m_CheckNoDirAtime; boxOptions()[QStringLiteral("sync")] = m_CheckSync; boxOptions()[QStringLiteral("noexec")] = m_CheckNoExec; boxOptions()[QStringLiteral("relatime")] = m_CheckRelAtime; - setupOptions(entry->options()); - - if (partition().fileSystem().uuid().isEmpty()) { - radioUUID().setEnabled(false); - if (radioUUID().isChecked()) - radioDeviceNode().setChecked(true); - } - - if (partition().fileSystem().label().isEmpty()) { - radioLabel().setEnabled(false); - if (radioLabel().isChecked()) - radioDeviceNode().setChecked(true); - } + setupRadio(currentEntry->entryType()); + setupOptions(currentEntry->options()); connect(m_ButtonMore, &QPushButton::clicked, this, &EditMountPointDialogWidget::buttonMoreClicked); connect(m_ButtonSelect, &QPushButton::clicked, this, &EditMountPointDialogWidget::buttonSelectClicked); + connect(m_EditPath, QOverload::of(&QComboBox::currentIndexChanged), + [=](int index){ currentEntry = entry[index]; + spinDumpFreq().setValue(currentEntry->dumpFreq()); + spinPassNumber().setValue(currentEntry->passNumber()); + setupRadio(currentEntry->entryType()); + for (iterator_BoxOptions = boxOptions().begin(); iterator_BoxOptions != boxOptions().end(); ++iterator_BoxOptions){ + boxOptions()[iterator_BoxOptions->first]->setChecked(false); + } + setupOptions(currentEntry->options()); + }); } EditMountPointDialogWidget::~EditMountPointDialogWidget() { } void EditMountPointDialogWidget::setupOptions(const QStringList& options) { QStringList optTmpList; - for (const auto &o : options) { if (boxOptions().find(o) != boxOptions().end()) boxOptions()[o]->setChecked(true); else optTmpList.append(o); } m_Options = optTmpList.join(QLatin1Char(',')); } +void EditMountPointDialogWidget::setupRadio(const FstabEntryType entryType) +{ + if (partition().fileSystem().uuid().isEmpty()) { + radioUUID().setEnabled(false); + if (radioUUID().isChecked()) + radioDeviceNode().setChecked(true); + } + + if (partition().fileSystem().label().isEmpty()) { + radioLabel().setEnabled(false); + if (radioLabel().isChecked()) + radioDeviceNode().setChecked(true); + } + switch (entryType) { + case FstabEntryType::uuid: + radioUUID().setChecked(true); + break; + + case FstabEntryType::label: + radioLabel().setChecked(true); + break; + + case FstabEntryType::partuuid: + radioUUID().setChecked(true); + break; + + case FstabEntryType::partlabel: + radioLabel().setChecked(true); + break; + + case FstabEntryType::deviceNode: + radioDeviceNode().setChecked(true); + break; + case FstabEntryType::comment: + break; + } +} + void EditMountPointDialogWidget::buttonSelectClicked(bool) { - const QString s = QFileDialog::getExistingDirectory(this, editPath().text()); + const QString s = QFileDialog::getExistingDirectory(this, editPath().currentText()); if (!s.isEmpty()) - editPath().setText(s); + editPath().setCurrentText(s); } void EditMountPointDialogWidget::removeMountPoint() { int i=0; for (const auto &e : fstabEntries()) { - if(e.fsSpec().contains(partition().deviceNode()) || e.fsSpec().contains(partition().fileSystem().uuid()) || - e.fsSpec().contains(partition().fileSystem().label()) || e.fsSpec().contains(partition().label()) || e.fsSpec().contains(partition().uuid()) ) - { + if(editPath().count()<=1 && ((e.fsSpec().contains(partition().deviceNode()) && !partition().deviceNode().isEmpty() ) || (e.fsSpec().contains(partition().fileSystem().uuid()) && !partition().fileSystem().uuid().isEmpty()) || + (e.fsSpec().contains(partition().fileSystem().label()) && !partition().fileSystem().label().isEmpty()) || (e.fsSpec().contains(partition().label()) && !partition().label().isEmpty() ) || (e.fsSpec().contains(partition().uuid()) && !partition().uuid().isEmpty() ))) + { fstabEntries().removeAt(i); partition().setMountPoint(QString()); i--; + } + else if(editPath().count()>1 && ((&e == currentEntry))) + { + fstabEntries().removeAt(i); + editPath().removeItem(editPath().currentIndex()); + partition().setMountPoint(editPath().itemText(editPath().currentIndex())); + i--; + break; } i++; } } void EditMountPointDialogWidget::buttonMoreClicked(bool) { QPointer dlg = new EditMountOptionsDialog(this, m_Options.split(QLatin1Char(','))); if (dlg->exec() == QDialog::Accepted) setupOptions(dlg->options()); delete dlg; } QStringList EditMountPointDialogWidget::options() const { QStringList optList = m_Options.split(QLatin1Char(','), QString::SkipEmptyParts); const auto keys = boxOptions(); for (const auto &s : keys) if (s.second->isChecked()) optList.append(s.first); return optList; } void EditMountPointDialogWidget::acceptChanges() { - entry->setDumpFreq(spinDumpFreq().value()); - entry->setPassNumber(spinPassNumber().value()); - entry->setMountPoint(editPath().text()); - entry->setOptions(options()); + currentEntry->setDumpFreq(spinDumpFreq().value()); + currentEntry->setPassNumber(spinPassNumber().value()); + currentEntry->setMountPoint(editPath().currentText()); + currentEntry->setOptions(options()); if (radioUUID().isChecked() && !partition().fileSystem().uuid().isEmpty()) - entry->setFsSpec(QStringLiteral("UUID=") + partition().fileSystem().uuid()); + currentEntry->setFsSpec(QStringLiteral("UUID=") + partition().fileSystem().uuid()); else if (radioLabel().isChecked() && !partition().fileSystem().label().isEmpty()) - entry->setFsSpec(QStringLiteral("LABEL=") + partition().fileSystem().label()); + currentEntry->setFsSpec(QStringLiteral("LABEL=") + partition().fileSystem().label()); else - entry->setFsSpec(m_deviceNode); + currentEntry->setFsSpec(m_deviceNode); } diff --git a/src/gui/editmountpointdialogwidget.h b/src/gui/editmountpointdialogwidget.h index da54790..56705bc 100644 --- a/src/gui/editmountpointdialogwidget.h +++ b/src/gui/editmountpointdialogwidget.h @@ -1,112 +1,115 @@ /************************************************************************* * Copyright (C) 2009, 2010 by Volker Lanz * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #if !defined(EDITMOUNTPOINTDIALOGWIDGET_H) #define EDITMOUNTPOINTDIALOGWIDGET_H #include "ui_editmountpointdialogwidgetbase.h" #include #include #include #include class Partition; class QFile; class QSpinBox; class QCheckBox; -class QLineEdit; +class QComboBox; class QPushButton; class QStringList; class EditMountPointDialogWidget : public QWidget, public Ui::EditMountPointDialogWidgetBase { public: EditMountPointDialogWidget(QWidget* parent, Partition& p); ~EditMountPointDialogWidget(); QPushButton& buttonMore() { return *m_ButtonMore; } QLabel& labelName() { return *m_LabelNameValue; } - QLineEdit& editPath() { + QComboBox& editPath() { return *m_EditPath; } QSpinBox& spinDumpFreq() { return *m_SpinDumpFreq; } QSpinBox& spinPassNumber() { return *m_SpinPassNumber; } QLabel& labelType() { return *m_LabelTypeValue; } QStringList options() const; QRadioButton& radioUUID() { return *m_RadioUUID; } QRadioButton& radioLabel() { return *m_RadioLabel; } QRadioButton& radioDeviceNode() { return *m_RadioDeviceNode; } FstabEntryList& fstabEntries() { return m_fstabEntries; } void acceptChanges(); void removeMountPoint(); bool writeMountpoints(const QString& filename); protected: void buttonSelectClicked(bool); void buttonMoreClicked(bool); private: void setupOptions(const QStringList& options); + void setupRadio(const FstabEntryType entryType); std::map& boxOptions() { return m_BoxOptions; } const std::map& boxOptions() const { return m_BoxOptions; } Partition& partition() { return m_Partition; } const Partition& partition() const { return m_Partition; } private: FstabEntryList m_fstabEntries; - FstabEntry *entry; - + QList entry; + FstabEntry *currentEntry; Partition& m_Partition; QString m_Options; QString m_deviceNode; + QStringList mountPointList; std::map m_BoxOptions; + std::map::iterator iterator_BoxOptions; }; #endif diff --git a/src/gui/editmountpointdialogwidgetbase.ui b/src/gui/editmountpointdialogwidgetbase.ui index e83a459..0d95b5e 100644 --- a/src/gui/editmountpointdialogwidgetbase.ui +++ b/src/gui/editmountpointdialogwidgetbase.ui @@ -1,333 +1,323 @@ EditMountPointDialogWidgetBase 0 0 - 600 + 613 374 - - - - - 3 - 0 - + + + + UU&ID - - + + + + + - Path: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - m_EditPath + Users can mount and unmount - - + + - Type: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Update access times relative to modification - - + + - Options: + - - Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + + + + + Qt::Horizontal Read-only - - + + - Users can mount and unmount + Pass &Number: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_SpinPassNumber - - + + - No automatic mount + More... - - + + + + Qt::Horizontal + + + + 195 + 22 + + + + + + - No update of file access times + De&vice Node + + + true - - + + - Synchronous access + Options: + + + Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing - - + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + - No update of directory access times + &Label No binary execution - - - - Update access times relative to modification - - + + - - + + Qt::Horizontal - 195 - 22 + 135 + 23 - - + + - More... + No automatic mount + + + + + + + + 1 + 0 + + + + Remove + + + + + + + + 1 + 0 + + + + Select... + + + + + + + No update of directory access times Dump &Frequency: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter m_SpinDumpFreq - - - - - + + - Qt::Horizontal + Qt::Vertical + + + QSizePolicy::Fixed - 70 - 23 + 20 + 10 - - + + - Pass &Number: + Type: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - m_SpinPassNumber - - - + + + + Path: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + 75 true Qt::AlignCenter - - - - - - - - - - - Qt::Horizontal - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 10 - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 10 - - - - Qt::Vertical QSizePolicy::Fixed 20 20 - - - - De&vice Node - - - true - - - - - - - UU&ID - - - - - + + - &Label + No update of file access times - - + + - Identify by: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Synchronous access - - + + Qt::Horizontal - 135 + 70 23 - - - - - 1 - 0 - - + + - Select... - - - - - - - - 1 - 0 - + Identify by: - - Remove + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + diff --git a/src/gui/smartdialog.cpp b/src/gui/smartdialog.cpp index 2a95826..cacffbe 100644 --- a/src/gui/smartdialog.cpp +++ b/src/gui/smartdialog.cpp @@ -1,236 +1,238 @@ /************************************************************************* * Copyright (C) 2010 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "gui/smartdialog.h" #include "gui/smartdialogwidget.h" #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** Creates a new SmartDialog @param parent pointer to the parent widget @param d the Device */ SmartDialog::SmartDialog(QWidget* parent, Device& d) : QDialog(parent), m_Device(d), m_DialogWidget(new SmartDialogWidget(this)) { QVBoxLayout *mainLayout = new QVBoxLayout(this); setLayout(mainLayout); mainLayout->addWidget(&dialogWidget()); setWindowTitle(xi18nc("@title:window", "SMART Properties: %1", device().deviceNode())); buttonBox = new QDialogButtonBox(this); buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Close); buttonBox->button(QDialogButtonBox::Save)->setText(xi18nc("@action:button", "Save SMART Report")); buttonBox->button(QDialogButtonBox::Save)->setIcon(QIcon::fromTheme(QStringLiteral("document-save"))); mainLayout->addWidget(buttonBox); setupDialog(); setupConnections(); KConfigGroup kcg(KSharedConfig::openConfig(), "smartDialog"); restoreGeometry(kcg.readEntry("Geometry", QByteArray())); } /** Destroys a SmartDialog */ SmartDialog::~SmartDialog() { KConfigGroup kcg(KSharedConfig::openConfig(), "smartDialog"); kcg.writeEntry("Geometry", saveGeometry()); } void SmartDialog::setupDialog() { if (device().smartStatus().isValid()) { if (device().smartStatus().status()) { dialogWidget().statusText().setText(xi18nc("@label SMART disk status", "good")); dialogWidget().statusIcon().setPixmap(QIcon::fromTheme(QStringLiteral("dialog-ok")).pixmap(IconSize(KIconLoader::Small))); } else { dialogWidget().statusText().setText(xi18nc("@label SMART disk status", "BAD")); dialogWidget().statusIcon().setPixmap(QIcon::fromTheme(QStringLiteral("dialog-warning")).pixmap(IconSize(KIconLoader::Small))); } dialogWidget().modelName().setText(device().smartStatus().modelName()); dialogWidget().firmware().setText(device().smartStatus().firmware()); dialogWidget().serialNumber().setText(device().smartStatus().serial()); dialogWidget().temperature().setText(SmartStatus::tempToString(device().smartStatus().temp())); const QString badSectors = device().smartStatus().badSectors() > 0 ? QLocale().toString(device().smartStatus().badSectors()) : xi18nc("@label SMART number of bad sectors", "none"); dialogWidget().badSectors().setText(badSectors); dialogWidget().poweredOn().setText(KFormat().formatDuration(device().smartStatus().poweredOn())); dialogWidget().powerCycles().setText(QLocale().toString(device().smartStatus().powerCycles())); dialogWidget().overallAssessment().setText(SmartStatus::overallAssessmentToString(device().smartStatus().overall())); dialogWidget().selfTests().setText(SmartStatus::selfTestStatusToString(device().smartStatus().selfTestStatus())); dialogWidget().treeSmartAttributes().clear(); const QFont f = QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont); const QString size = f.pixelSize() != -1 ? QStringLiteral("%1px").arg(f.pixelSize()) : QStringLiteral("%1pt").arg(f.pointSize()); const QString st = QStringLiteral("").arg(f.family()).arg(size); for (const auto &a : device().smartStatus().attributes()) { QTreeWidgetItem* item = new QTreeWidgetItem( QStringList() << QLocale().toString(a.id()) << QStringLiteral("%1
%2").arg(a.name()).arg(st + a.desc() + QStringLiteral("
")) << (a.failureType() == SmartAttribute::PreFailure ? xi18nc("@item:intable", "Pre-Failure") : xi18nc("@item:intable", "Old-Age")) << (a.updateType() == SmartAttribute::Online ? xi18nc("@item:intable", "Online") : xi18nc("@item:intable", "Offline")) << QLocale().toString(a.worst()) << QLocale().toString(a.current()) << QLocale().toString(a.threshold()) << a.raw() << a.assessmentToString() << a.value() ); item->setSizeHint(0, QSize(0, 64)); + item->setToolTip(1, QTextDocumentFragment::fromHtml(a.desc()).toPlainText()); dialogWidget().treeSmartAttributes().addTopLevelItem(item); } } else dialogWidget().statusText().setText(xi18nc("@label", "(unknown)")); setMinimumSize(dialogWidget().size()); resize(dialogWidget().size()); } void SmartDialog::setupConnections() { connect(buttonBox->button(QDialogButtonBox::Save), &QPushButton::clicked, this, &SmartDialog::saveSmartReport); connect(buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &SmartDialog::close); } QString SmartDialog::toHtml() const { QString rval; QTextStream s(&rval); if (device().smartStatus().status()) s << HtmlReport::tableLine(i18n("SMART status:"), xi18nc("@label SMART disk status", "good")); else s << HtmlReport::tableLine(i18n("SMART status:"), xi18nc("@label SMART disk status", "BAD")); const QString badSectors = device().smartStatus().badSectors() > 0 ? QLocale().toString(device().smartStatus().badSectors()) : i18nc("@label SMART number of bad sectors", "none"); s << HtmlReport::tableLine(i18n("Model:"), device().smartStatus().modelName()) << HtmlReport::tableLine(i18n("Serial number:"), device().smartStatus().serial()) << HtmlReport::tableLine(i18n("Firmware revision:"), device().smartStatus().firmware()) << HtmlReport::tableLine(i18n("Temperature:"), SmartStatus::tempToString(device().smartStatus().temp())) << HtmlReport::tableLine(i18n("Bad sectors:"), badSectors) << HtmlReport::tableLine(i18n("Powered on for:"), KFormat().formatDuration(device().smartStatus().poweredOn())) << HtmlReport::tableLine(i18n("Power cycles:"), QLocale().toString(device().smartStatus().powerCycles())) << HtmlReport::tableLine(i18n("Self tests:"), SmartStatus::selfTestStatusToString(device().smartStatus().selfTestStatus())) << HtmlReport::tableLine(i18n("Overall assessment:"), SmartStatus::overallAssessmentToString(device().smartStatus().overall())); s << "
"; if (device().smartStatus().isValid()) { const QFont f = QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont); const QString size = f.pixelSize() != -1 ? QStringLiteral("%1px").arg(f.pixelSize()) : QStringLiteral("%1pt").arg(f.pointSize()); const QString st = QStringLiteral("").arg(f.family()).arg(size); s << "\n"; for (const auto &a : device().smartStatus().attributes()) { s << "\n"; s << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" << "\n"; s << "\n"; } s << "
" << QLocale().toString(a.id()) << "" << QStringLiteral("%1
%2").arg(a.name()).arg(st + a.desc() + QStringLiteral("")) << "
" << (a.failureType() == SmartAttribute::PreFailure ? xi18nc("@item:intable", "Pre-Failure") : xi18nc("@item:intable", "Old-Age")) << "" << (a.updateType() == SmartAttribute::Online ? xi18nc("@item:intable", "Online") : xi18nc("@item:intable", "Offline")) << "" << QLocale().toString(a.worst()) << "" << QLocale().toString(a.current()) << "" << QLocale().toString(a.threshold()) << "" << a.raw() << "" << a.assessmentToString() << "" << a.value() << "
\n"; } else s << "(unknown)"; s.flush(); return rval; } void SmartDialog::saveSmartReport() { const QUrl url = QFileDialog::getSaveFileUrl(); if (url.isEmpty()) return; QTemporaryFile tempFile; if (tempFile.open()) { QTextStream s(&tempFile); HtmlReport html; s << html.header() << toHtml() << html.footer(); tempFile.close(); KIO::CopyJob* job = KIO::move(QUrl::fromLocalFile(tempFile.fileName()), url, KIO::HideProgressInfo); job->exec(); if (job->error()) job->uiDelegate()->showErrorMessage(); } else KMessageBox::sorry(this, xi18nc("@info", "Could not create temporary file when trying to save to %1.", url.fileName()), xi18nc("@title:window", "Could Not Save SMART Report.")); }